From f104d91595397a4e7ce82a36de92b09e76d9d507 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 26 Nov 2018 17:29:32 -0800
Subject: Broken commit -- saving current state of getting wyre compliance
 token contract setup

---
 contracts/test-utils/src/types.ts | 1 +
 1 file changed, 1 insertion(+)

(limited to 'contracts')

diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts
index d738fcd4e..04f95e1a8 100644
--- a/contracts/test-utils/src/types.ts
+++ b/contracts/test-utils/src/types.ts
@@ -99,6 +99,7 @@ export enum ContractName {
     ERC721Proxy = 'ERC721Proxy',
     DummyERC721Receiver = 'DummyERC721Receiver',
     DummyERC721Token = 'DummyERC721Token',
+    DummyYesComplianceToken = 'DummyYesComplianceToken',
     TestLibBytes = 'TestLibBytes',
     TestWallet = 'TestWallet',
     Authorizable = 'Authorizable',
-- 
cgit v1.2.3


From 88595718c3f78d3facbd4ac67ba8328ce9b2bc8a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 15:37:11 -0800
Subject: Yes Compliance Token

---
 contracts/test-utils/src/types.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts
index 04f95e1a8..f0830deb4 100644
--- a/contracts/test-utils/src/types.ts
+++ b/contracts/test-utils/src/types.ts
@@ -84,6 +84,7 @@ export enum ContractName {
     MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock',
     Exchange = 'Exchange',
     ZRXToken = 'ZRXToken',
+    YesComplianceToken = 'YesComplianceToken',
     DummyERC20Token = 'DummyERC20Token',
     EtherToken = 'WETH9',
     DutchAuction = 'DutchAuction',
@@ -99,7 +100,6 @@ export enum ContractName {
     ERC721Proxy = 'ERC721Proxy',
     DummyERC721Receiver = 'DummyERC721Receiver',
     DummyERC721Token = 'DummyERC721Token',
-    DummyYesComplianceToken = 'DummyYesComplianceToken',
     TestLibBytes = 'TestLibBytes',
     TestWallet = 'TestWallet',
     Authorizable = 'Authorizable',
-- 
cgit v1.2.3


From 0e0e05e0e07aca3cfbfd13b3fdc00183b7ac5a87 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 16:05:18 -0800
Subject: Compile Compliant Forwarder contract

---
 contracts/test-utils/src/types.ts | 1 +
 1 file changed, 1 insertion(+)

(limited to 'contracts')

diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts
index f0830deb4..46b7ad941 100644
--- a/contracts/test-utils/src/types.ts
+++ b/contracts/test-utils/src/types.ts
@@ -105,6 +105,7 @@ export enum ContractName {
     Authorizable = 'Authorizable',
     Whitelist = 'Whitelist',
     Forwarder = 'Forwarder',
+    CompliantForwarder = 'CompliantForwarder',
 }
 
 export interface SignedTransaction {
-- 
cgit v1.2.3


From b4aca370defb9dfe6c01b60d1b522d4a7b731f43 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 18:09:50 -0800
Subject: Writing tests for Compliant Forwarder

---
 contracts/extensions/test/extensions/forwarder.ts | 1 +
 1 file changed, 1 insertion(+)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts
index 4027f493d..a4afa283e 100644
--- a/contracts/extensions/test/extensions/forwarder.ts
+++ b/contracts/extensions/test/extensions/forwarder.ts
@@ -61,6 +61,7 @@ describe(ContractName.Forwarder, () => {
     let wethContract: WETH9Contract;
     let forwarderWrapper: ForwarderWrapper;
     let exchangeWrapper: ExchangeWrapper;
+    let takerPrivateKey: Buffer;
 
     let orderWithoutFee: SignedOrder;
     let orderWithFee: SignedOrder;
-- 
cgit v1.2.3


From 9f68ac7bbecea109692d62d5555bac67e86c123a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 30 Nov 2018 16:43:04 -0800
Subject: Making progress on generalized forwarder

---
 contracts/protocol/test/utils/exchange_wrapper.ts | 1 +
 1 file changed, 1 insertion(+)

(limited to 'contracts')

diff --git a/contracts/protocol/test/utils/exchange_wrapper.ts b/contracts/protocol/test/utils/exchange_wrapper.ts
index cb6dce901..6106e78ca 100644
--- a/contracts/protocol/test/utils/exchange_wrapper.ts
+++ b/contracts/protocol/test/utils/exchange_wrapper.ts
@@ -214,6 +214,7 @@ export class ExchangeWrapper {
             { from },
         );
         const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
+        console.log(JSON.stringify(tx));
         return tx;
     }
     public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
-- 
cgit v1.2.3


From 1cdd82178ff630827095e778a222fafa4161969e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 4 Dec 2018 15:23:25 -0800
Subject: ComplianceForwarder renamed to BalanceThresholdFilter

---
 contracts/test-utils/src/types.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts
index 46b7ad941..cbdd513eb 100644
--- a/contracts/test-utils/src/types.ts
+++ b/contracts/test-utils/src/types.ts
@@ -105,7 +105,7 @@ export enum ContractName {
     Authorizable = 'Authorizable',
     Whitelist = 'Whitelist',
     Forwarder = 'Forwarder',
-    CompliantForwarder = 'CompliantForwarder',
+    BalanceThresholdFilter = 'BalanceThresholdFilter',
 }
 
 export interface SignedTransaction {
-- 
cgit v1.2.3


From 8d6219296a4ac0c2ec46ae077eb87cebb19f8b55 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 10 Dec 2018 17:08:16 -0800
Subject: Removed Yes Token - its no longer needed to test Balance Threshold
 Filter

---
 contracts/test-utils/src/types.ts | 1 -
 1 file changed, 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts
index cbdd513eb..1630eab0d 100644
--- a/contracts/test-utils/src/types.ts
+++ b/contracts/test-utils/src/types.ts
@@ -84,7 +84,6 @@ export enum ContractName {
     MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock',
     Exchange = 'Exchange',
     ZRXToken = 'ZRXToken',
-    YesComplianceToken = 'YesComplianceToken',
     DummyERC20Token = 'DummyERC20Token',
     EtherToken = 'WETH9',
     DutchAuction = 'DutchAuction',
-- 
cgit v1.2.3


From 4417c76b130655da3b14209148191d43037e8f8a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 14:47:52 -0800
Subject: Ported Balance Threshold Filter to new contract directory structure

---
 contracts/extensions/compiler.json                 |    2 +-
 .../BalanceThresholdFilter.sol                     |   44 +
 .../MixinBalanceThresholdFilterCore.sol            |  319 ++++
 .../interfaces/IThresholdAsset.sol                 |   30 +
 .../mixins/MBalanceThresholdFilterCore.sol         |   81 ++
 contracts/extensions/package.json                  |    2 +-
 contracts/extensions/src/artifacts/index.ts        |    2 +
 contracts/extensions/src/wrappers/index.ts         |    1 +
 .../test/extensions/balance_threshold_filter.ts    | 1530 ++++++++++++++++++++
 .../test/utils/balance_threshold_wrapper.ts        |  246 ++++
 contracts/extensions/tsconfig.json                 |    2 +-
 11 files changed, 2256 insertions(+), 3 deletions(-)
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
 create mode 100644 contracts/extensions/test/extensions/balance_threshold_filter.ts
 create mode 100644 contracts/extensions/test/utils/balance_threshold_wrapper.ts

(limited to 'contracts')

diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json
index 69d607b3e..e6ed0c215 100644
--- a/contracts/extensions/compiler.json
+++ b/contracts/extensions/compiler.json
@@ -18,5 +18,5 @@
             }
         }
     },
-    "contracts": ["DutchAuction", "Forwarder"]
+    "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder"]
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
new file mode 100644
index 000000000..a68f6805d
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
@@ -0,0 +1,44 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
+import "./interfaces/IThresholdAsset.sol";
+import "./MixinBalanceThresholdFilterCore.sol";
+
+
+contract BalanceThresholdFilter is MixinBalanceThresholdFilterCore {
+
+    /// @dev Constructs BalanceThresholdFilter.
+    /// @param exchange Address of 0x exchange.
+    /// @param thresholdAsset The asset that must be held by makers/takers.
+    /// @param thresholdBalance The minimum balance of `thresholdAsset` that must be held by makers/takers.
+    constructor(
+        address exchange,
+        address thresholdAsset,
+        uint256 thresholdBalance
+    )
+        public
+    {
+        EXCHANGE = IExchange(exchange);
+        THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
+        THRESHOLD_BALANCE = thresholdBalance;
+    }
+}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
new file mode 100644
index 000000000..0ad8ccddf
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -0,0 +1,319 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "./mixins/MBalanceThresholdFilterCore.sol";
+
+
+contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
+
+    /// @dev Executes an Exchange transaction iff the maker and taker meet 
+    ///      the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR 
+    ///      the exchange function is a cancellation.
+    ///      Supported Exchange functions:
+    ///         - batchFillOrders
+    ///         - batchFillOrdersNoThrow
+    ///         - batchFillOrKillOrders
+    ///         - fillOrder
+    ///         - fillOrderNoThrow
+    ///         - fillOrKillOrder
+    ///         - marketBuyOrders
+    ///         - marketBuyOrdersNoThrow
+    ///         - marketSellOrders
+    ///         - marketSellOrdersNoThrow
+    ///         - matchOrders
+    ///         - cancelOrder
+    ///         - batchCancelOrders
+    ///         - cancelOrdersUpTo
+    ///     Trying to call any other exchange function will throw.
+    /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+    /// @param signerAddress Address of transaction signer.
+    /// @param signedExchangeTransaction AbiV2 encoded calldata.
+    /// @param signature Proof of signer transaction by signer.
+    function executeTransaction(
+        uint256 salt,
+        address signerAddress,
+        bytes signedExchangeTransaction,
+        bytes signature
+    ) 
+         external
+    {
+        // Validate addresses.
+        validateBalanceThresholdsOrRevert();
+        
+        // All addresses are valid. Execute fillOrder.
+        EXCHANGE.executeTransaction(
+            salt,
+            signerAddress,
+            signedExchangeTransaction,
+            signature
+        );
+    }
+
+    /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
+    ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
+    ///      then this function will revert. Which addresses are validated depends on
+    ///      which Exchange function is to be called (defined by `signedExchangeTransaction` above).
+    ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
+    ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
+    ///      of the addresses whose balance thresholds it checked.
+    function validateBalanceThresholdsOrRevert()
+        internal
+    {
+        // Addresses that are validated below.
+        address[] memory validatedAddresses;
+
+        ///// Do not add variables after this point.         /////
+        ///// The assembly block may overwrite their values. /////
+
+        // Validate addresses
+        assembly {
+             /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
+             ///      which is accessed through `signedExchangeTransaction`.
+             /// @param offset - Offset into the Exchange calldata.
+             /// @return value - Corresponding 32 byte value stored at `offset`.
+            function exchangeCalldataload(offset) -> value {
+                // Pointer to exchange transaction
+                // 0x04 for calldata selector
+                // 0x40 to access `signedExchangeTransaction`, which is the third parameter
+                let exchangeTxPtr := calldataload(0x44)
+
+                // Offset into Exchange calldata
+                // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
+                // 0x04 for calldata selector
+                // 0x20 for length field of `signedExchangeTransaction`
+                let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
+                value := calldataload(exchangeCalldataOffset)
+            }
+
+            /// @dev Convenience function that skips the 4 byte selector when loading
+            ///      from the embedded Exchange calldata.
+            /// @param offset - Offset into the Exchange calldata (minus the 4 byte selector)
+            /// @return value - Corresponding 32 byte value stored at `offset` + 4.
+            function loadExchangeData(offset) -> value {
+                value := exchangeCalldataload(add(offset, 0x4))
+            }
+
+             /// @dev A running list is maintained of addresses to validate. 
+             ///     This function records an address in this array.
+             /// @param addressToValidate - Address to record for validation.
+            function recordAddressToValidate(addressToValidate) {
+                // Compute `addressesToValidate` memory offset
+                let addressesToValidate_ := mload(0x40)
+                let nAddressesToValidate_ := mload(addressesToValidate_)
+
+                // Increment length
+                nAddressesToValidate_ := add(mload(addressesToValidate_), 0x01)
+                mstore(addressesToValidate_, nAddressesToValidate_)
+
+                // Append address to validate
+                let offset := mul(nAddressesToValidate_, 0x20)
+                mstore(add(addressesToValidate_, offset), addressToValidate)
+            }
+
+             /// @dev Extracts the maker address from an order stored in the Exchange calldata
+             ///      (which is embedded in `signedExchangeTransaction`), and records it in
+             ///      the running list of addresses to validate.
+             /// @param orderParamIndex - Index of the order in the Exchange function's signature
+            function recordMakerAddressFromOrder(orderParamIndex) {
+                let orderPtr := loadExchangeData(mul(orderParamIndex, 0x20))
+                let makerAddress := loadExchangeData(orderPtr)
+                recordAddressToValidate(makerAddress)
+            }
+
+            /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
+            ///      (which is embedded in `signedExchangeTransaction`), and records them in
+            ///      the running list of addresses to validate.
+            /// @param orderArrayParamIndex - Index of the order array in the Exchange function's signature
+            function recordMakerAddressesFromOrderArray(orderArrayParamIndex) {
+                let orderArrayPtr := loadExchangeData(mul(orderArrayParamIndex, 0x20))
+                let orderArrayLength := loadExchangeData(orderArrayPtr)
+                let orderArrayElementPtr := add(orderArrayPtr, 0x20)
+                let orderArrayElementEndPtr := add(orderArrayElementPtr, mul(orderArrayLength, 0x20))
+                for {let orderPtrOffset := orderArrayElementPtr} lt(orderPtrOffset, orderArrayElementEndPtr) {orderPtrOffset := add(orderPtrOffset, 0x20)} {
+                    let orderPtr := loadExchangeData(orderPtrOffset)
+                    let makerAddress := loadExchangeData(add(orderPtr, orderArrayElementPtr))
+                    recordAddressToValidate(makerAddress)
+                }
+            }
+
+            /// @dev Records address of signer in the running list of addresses to validate.
+            /// @note: We cannot access `signerAddress` directly from within the asm function,
+            ///        so it is loaded from the calldata.
+            function recordSignerAddress() {
+                // Load the signer address from calldata
+                // 0x04 for selector
+                // 0x20 to access `signerAddress`, which is the second parameter.
+                let signerAddress_ := calldataload(0x24)
+                recordAddressToValidate(signerAddress_)
+            }
+
+            /// @dev Records addresses to be validated when Exchange transaction is a batch fill variant.
+            ///      This is one of: batchFillOrders, batchFillOrKillOrders, batchFillNoThrow
+            ///      Reference signature<T>: <batchFillVariant>(Order[],uint256[],bytes[])
+            function recordAddressesForBatchFillVariant() {
+                // Record maker addresses from order array (parameter index 0)
+                // The signer is the taker for these orders and must also be validated.
+                recordMakerAddressesFromOrderArray(0)
+                recordSignerAddress()
+            }
+
+            /// @dev Records addresses to be validated when Exchange transaction is a fill order variant.
+            ///      This is one of: fillOrder, fillOrKillOrder, fillOrderNoThrow
+            ///      Reference signature<T>: <fillOrderVariant>(Order,uint256,bytes)
+            function recordAddressesForFillOrderVariant() {
+                // Record maker address from the order (param index 0)
+                // The signer is the taker for this order and must also be validated.
+                recordMakerAddressFromOrder(0)
+                recordSignerAddress()
+            }
+
+            /// @dev Records addresses to be validated when Exchange transaction is a market fill variant.
+            ///      This is one of: marketBuyOrders, marketBuyOrdersNoThrow, marketSellOrders, marketSellOrdersNoThrow
+            ///      Reference signature<T>: <marketFillInvariant>(Order[],uint256,bytes[])
+            function recordAddressesForMarketFillVariant() {
+                // Record maker addresses from order array (parameter index 0)
+                // The signer is the taker for these orders and must also be validated.
+                recordMakerAddressesFromOrderArray(0)
+                recordSignerAddress()
+            }
+
+            /// @dev Records addresses to be validated when Exchange transaction is matchOrders.
+            ///      Reference signature: matchOrders(Order,Order)
+            function recordAddressesForMatchOrders() {
+                // Record maker address from both orders (param indices 0 & 1).
+                // The signer is the taker and must also be validated.
+                recordMakerAddressFromOrder(0)
+                recordMakerAddressFromOrder(1)
+                recordSignerAddress()
+            }
+
+            ///// Record Addresses to Validate /////
+
+            // Addresses needing validation depends on which Exchange function is being called.
+            // Step 1/2 Read the exchange function selector.
+            let exchangeFunctionSelector := and(
+                exchangeCalldataload(0x0),
+                0xffffffff00000000000000000000000000000000000000000000000000000000
+            )
+
+            // Step 2/2 Extract addresses to validate based on this selector.
+            //          See ../../utils/ExchangeSelectors/ExchangeSelectors.sol for selectors
+            switch exchangeFunctionSelector
+            case 0x297bb70b00000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrders
+            case 0x50dde19000000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrdersNoThrow
+            case 0x4d0ae54600000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrKillOrders
+            case 0xb4be83d500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrder
+            case 0x3e228bae00000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrderNoThrow
+            case 0x64a3bc1500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrKillOrder
+            case 0xe5fa431b00000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketBuyOrders
+            case 0xa3e2038000000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketBuyOrdersNoThrow
+            case 0x7e1d980800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketSellOrders
+            case 0xdd1c7d1800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketSellOrdersNoThrow
+            case 0x3c28d86100000000000000000000000000000000000000000000000000000000 { recordAddressesForMatchOrders() }         // matchOrders
+            case 0xd46b02c300000000000000000000000000000000000000000000000000000000 {}                                          // cancelOrder
+            case 0x4ac1478200000000000000000000000000000000000000000000000000000000 {}                                          // batchCancelOrders
+            case 0x4f9559b100000000000000000000000000000000000000000000000000000000 {}                                          // cancelOrdersUpTo
+            default {
+                // Revert with `Error("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR")`
+                mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                mstore(0x40, 0x00000024494e56414c49445f4f525f424c4f434b45445f45584348414e47455f)
+                mstore(0x60, 0x53454c4543544f52000000000000000000000000000000000000000000000000)
+                mstore(0x80, 0x00000000)
+                // Revert length calculation:
+                // 4   -- error selector
+                // 32  -- offset to string
+                // 32  -- string length field
+                // 64  -- strlen(INVALID_OR_BLOCKED_EXCHANGE_SELECTOR) rounded up to nearest 32-byte word.
+                revert(0, 132)
+            }
+
+            ///// Validate Recorded Addresses /////
+
+            // Load from memory the addresses to validate
+            let addressesToValidate := mload(0x40)
+            let addressesToValidateLength := mload(addressesToValidate)
+            let addressesToValidateElementPtr := add(addressesToValidate, 0x20)
+            let addressesToValidateElementEndPtr := add(addressesToValidateElementPtr, mul(addressesToValidateLength, 0x20))
+
+            // Set free memory pointer to after `addressesToValidate` array.
+            // This is to avoid corruption when making calls in the loop below.
+            let freeMemPtr := addressesToValidateElementEndPtr
+            mstore(0x40, freeMemPtr)
+
+            // Validate addresses
+            let thresholdAssetAddress := sload(THRESHOLD_ASSET_slot)
+            let thresholdBalance := sload(THRESHOLD_BALANCE_slot)
+            for {let addressToValidate := addressesToValidateElementPtr} lt(addressToValidate, addressesToValidateElementEndPtr) {addressToValidate := add(addressToValidate, 0x20)} {
+                // Construct calldata for `THRESHOLD_ASSET.balanceOf`
+                mstore(freeMemPtr, 0x70a0823100000000000000000000000000000000000000000000000000000000)
+                mstore(add(freeMemPtr, 0x04), mload(addressToValidate))
+               
+                // call `THRESHOLD_ASSET.balanceOf`
+                let success := call(
+                    gas,                                    // forward all gas
+                    thresholdAssetAddress,                 // call address of asset proxy
+                    0,                                      // don't send any ETH
+                    freeMemPtr,                             // pointer to start of input
+                    0x24,                                   // length of input (one padded address) 
+                    freeMemPtr,                             // write output to next free memory offset
+                    0x20                                    // reserve space for return balance (0x20 bytes)
+                )
+                if eq(success, 0) {
+                    // @TODO Revert with `Error("BALANCE_QUERY_FAILED")`
+                    mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                    mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                    mstore(0x40, 0x0000001442414c414e43455f51554552595f4641494c45440000000000000000)
+                    mstore(0x60, 0x00000000)
+                    // Revert length calculation:
+                    // 4   -- error selector
+                    // 32  -- offset to string
+                    // 32  -- string length field
+                    // 32  -- strlen(BALANCE_QUERY_FAILED) rounded up to nearest 32-byte word.
+                    revert(0, 100)
+                }
+
+                // Revert if balance not held
+                let addressBalance := mload(freeMemPtr)
+                if lt(addressBalance, thresholdBalance) {
+                    // Revert with `Error("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD")`
+                    mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                    mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                    mstore(0x40, 0x0000003441545f4c454153545f4f4e455f414444524553535f444f45535f4e4f)
+                    mstore(0x60, 0x545f4d4545545f42414c414e43455f5448524553484f4c440000000000000000)
+                    mstore(0x80, 0x00000000)
+                    // Revert length calculation:
+                    // 4   -- error selector
+                    // 32  -- offset to string
+                    // 32  -- string length field
+                    // 64  -- strlen(AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD) rounded up to nearest 32-byte word.
+                    revert(0, 132)
+                }
+            }
+
+            // Record validated addresses
+            validatedAddresses := addressesToValidate
+        }
+
+        ///// If we hit this point then all addresses are valid /////
+        emit ValidatedAddresses(validatedAddresses);
+    }
+}
\ No newline at end of file
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
new file mode 100644
index 000000000..61acaba0a
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
@@ -0,0 +1,30 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+contract IThresholdAsset {
+
+    /// @param _owner The address from which the balance will be retrieved
+    /// @return Balance of owner
+    function balanceOf(address _owner)
+        external
+        view
+        returns (uint256);
+
+}
\ No newline at end of file
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
new file mode 100644
index 000000000..ff0042f58
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
@@ -0,0 +1,81 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
+import "../interfaces/IThresholdAsset.sol";
+
+
+contract MBalanceThresholdFilterCore {
+
+    // Points to 0x exchange contract
+    IExchange internal EXCHANGE;
+
+    // The asset that must be held by makers/takers
+    IThresholdAsset internal THRESHOLD_ASSET;
+
+    // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
+    uint256 internal THRESHOLD_BALANCE;
+
+    // Addresses that hold at least `THRESHOLD_BALANCE` of `THRESHOLD_ASSET`
+    event ValidatedAddresses (
+        address[] addresses
+    );
+
+    /// @dev Executes an Exchange transaction iff the maker and taker meet 
+    ///      the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR 
+    ///      the exchange function is a cancellation.
+    ///      Supported Exchange functions:
+    ///         - batchFillOrders
+    ///         - batchFillOrdersNoThrow
+    ///         - batchFillOrKillOrders
+    ///         - fillOrder
+    ///         - fillOrderNoThrow
+    ///         - fillOrKillOrder
+    ///         - marketBuyOrders
+    ///         - marketBuyOrdersNoThrow
+    ///         - marketSellOrders
+    ///         - marketSellOrdersNoThrow
+    ///         - matchOrders
+    ///         - cancelOrder
+    ///         - batchCancelOrders
+    ///         - cancelOrdersUpTo
+    ///     Trying to call any other exchange function will throw.
+    /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+    /// @param signerAddress Address of transaction signer.
+    /// @param signedExchangeTransaction AbiV2 encoded calldata.
+    /// @param signature Proof of signer transaction by signer.
+    function executeTransaction(
+        uint256 salt,
+        address signerAddress,
+        bytes signedExchangeTransaction,
+        bytes signature
+    ) 
+        external;
+
+    /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
+    ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
+    ///      then this function will revert. Which addresses are validated depends on
+    ///      which Exchange function is to be called (defined by `signedExchangeTransaction` above).
+    ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
+    ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
+    ///      of the addresses whose balance thresholds it checked.
+    function validateBalanceThresholdsOrRevert() internal;
+}
\ No newline at end of file
diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json
index 938e1138c..2d9ed4dcd 100644
--- a/contracts/extensions/package.json
+++ b/contracts/extensions/package.json
@@ -31,7 +31,7 @@
         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
     },
     "config": {
-        "abis": "generated-artifacts/@(DutchAuction|Forwarder).json"
+        "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder).json"
     },
     "repository": {
         "type": "git",
diff --git a/contracts/extensions/src/artifacts/index.ts b/contracts/extensions/src/artifacts/index.ts
index 7588178f0..ebf0b8050 100644
--- a/contracts/extensions/src/artifacts/index.ts
+++ b/contracts/extensions/src/artifacts/index.ts
@@ -1,9 +1,11 @@
 import { ContractArtifact } from 'ethereum-types';
 
+import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
 import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
 import * as Forwarder from '../../generated-artifacts/Forwarder.json';
 
 export const artifacts = {
+    BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
     DutchAuction: DutchAuction as ContractArtifact,
     Forwarder: Forwarder as ContractArtifact,
 };
diff --git a/contracts/extensions/src/wrappers/index.ts b/contracts/extensions/src/wrappers/index.ts
index 90880e37f..8a8122caa 100644
--- a/contracts/extensions/src/wrappers/index.ts
+++ b/contracts/extensions/src/wrappers/index.ts
@@ -1,2 +1,3 @@
+export * from '../../generated-wrappers/balance_threshold_filter';
 export * from '../../generated-wrappers/dutch_auction';
 export * from '../../generated-wrappers/forwarder';
diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
new file mode 100644
index 000000000..34339564c
--- /dev/null
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -0,0 +1,1530 @@
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { RevertReason, SignedOrder, Order } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as chai from 'chai';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
+
+import {
+    artifacts as protocolArtifacts,
+    ERC20Wrapper,
+    ERC721Wrapper,
+    ExchangeContract,
+    ExchangeWrapper,
+    TestExchangeInternalsContract,
+} from '@0x/contracts-protocol';
+import {
+    chaiSetup,
+    constants,
+    ContractName,
+    ERC20BalancesByOwner,
+    expectTransactionFailedAsync,
+    expectTransactionFailedWithoutReasonAsync,
+    getLatestBlockTimestampAsync,
+    LogDecoder,
+    OrderFactory,
+    OrderStatus,
+    orderUtils,
+    provider,
+    SignedTransaction,
+    txDefaults,
+    TransactionFactory,
+    web3Wrapper,
+} from '@0x/contracts-test-utils';
+import {
+    artifacts as tokensArtifacts,
+    DummyERC20TokenContract,
+    DummyERC721TokenContract,
+    WETH9Contract,
+} from '@0x/contracts-tokens';
+
+import { artifacts } from '../../src/artifacts';
+import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
+import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+const DECIMALS_DEFAULT = 18;
+
+interface ValidatedAddressesLog {
+    args: {addresses: string[]}
+}
+
+describe.only(ContractName.BalanceThresholdFilter, () => {
+    let compliantMakerAddress: string;
+    let compliantMakerAddress2: string;
+    let owner: string;
+    let compliantTakerAddress: string;
+    let feeRecipientAddress: string;
+    let nonCompliantAddress: string;
+    let defaultMakerAssetAddress: string;
+    let defaultTakerAssetAddress: string;
+    let zrxAssetData: string;
+    let zrxToken: DummyERC20TokenContract;
+    let exchangeInstance: ExchangeContract;
+    let exchangeWrapper: ExchangeWrapper;
+
+    let orderFactory: OrderFactory;
+    let orderFactory2: OrderFactory;
+    let nonCompliantOrderFactory: OrderFactory;
+    let erc20Wrapper: ERC20Wrapper;
+    let erc20Balances: ERC20BalancesByOwner;
+    let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
+    let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
+    let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper;
+    let erc721NonCompliantBalanceThresholdWrapper: BalanceThresholdWrapper;
+
+    let takerTransactionFactory: TransactionFactory;
+    let makerTransactionFactory: TransactionFactory;
+    let compliantSignedOrder: SignedOrder;
+    let compliantSignedOrder2: SignedOrder;
+    let compliantSignedFillOrderTx: SignedTransaction;
+
+    let logDecoder: LogDecoder;
+    let exchangeInternals: TestExchangeInternalsContract;
+
+    let defaultOrderParams: Partial<Order>;
+
+    const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
+    const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
+    const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
+
+    let erc721CompliantForwarderInstance: BalanceThresholdFilterContract;
+    let erc20CompliantForwarderInstance: BalanceThresholdFilterContract;
+
+    const assertValidatedAddressesLog = async (txReceipt: TransactionReceiptWithDecodedLogs, expectedValidatedAddresses: string[]) => {
+        expect(txReceipt.logs.length).to.be.gte(1);
+        const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog;
+        const validatedAddresses = validatedAddressesLog.args.addresses;
+        // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once
+        //             the new ABI Encoder/Decoder is used by the contract templates.
+        let validatedAddressesNormalized: string[] = [];
+        _.each(validatedAddresses, (address) => {
+            const normalizedAddress = _.toLower(address);
+            validatedAddressesNormalized.push(normalizedAddress);
+        });
+        expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses);
+    };
+
+    before(async () => {
+        // Create accounts
+        await blockchainLifecycle.startAsync();
+        const accounts = await web3Wrapper.getAvailableAddressesAsync();
+        const usedAddresses = ([
+            owner,
+            compliantMakerAddress,
+            compliantMakerAddress2,
+            compliantTakerAddress,
+            feeRecipientAddress,
+            nonCompliantAddress,
+        ] = accounts);
+        // Create wrappers
+        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
+        let compliantAddresses = _.cloneDeepWith(usedAddresses);
+        _.remove(compliantAddresses, (address: string) => {
+            return address === nonCompliantAddress;
+        });
+        const erc721Wrapper = new ERC721Wrapper(provider, compliantAddresses, owner);
+        // Deploy ERC20 tokens
+        const numDummyErc20ToDeploy = 4;
+        let erc20TokenA: DummyERC20TokenContract;
+        let erc20TokenB: DummyERC20TokenContract;
+        let erc20BalanceThresholdAsset: DummyERC20TokenContract;
+        [erc20TokenA, erc20TokenB, zrxToken, erc20BalanceThresholdAsset] = await erc20Wrapper.deployDummyTokensAsync(
+            numDummyErc20ToDeploy,
+            constants.DUMMY_TOKEN_DECIMALS,
+        );
+        defaultMakerAssetAddress = erc20TokenA.address;
+        defaultTakerAssetAddress = erc20TokenB.address;
+        zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+        // Create proxies
+        const erc20Proxy = await erc20Wrapper.deployProxyAsync();
+        await erc20Wrapper.setBalancesAndAllowancesAsync();
+        // Deploy Exchange congtract
+        exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
+            protocolArtifacts.Exchange,
+            provider,
+            txDefaults,
+            zrxAssetData,
+        );
+        exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
+        // Register proxies
+        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+        await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
+            from: owner,
+        });
+        // Deploy Compliant Forwarder
+        const erc721alanceThreshold = new BigNumber(1);
+        await erc721Wrapper.deployProxyAsync();
+        const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync();
+        await erc721Wrapper.setBalancesAndAllowancesAsync();
+        erc721CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
+            artifacts.BalanceThresholdFilter,
+            provider,
+            txDefaults,
+            exchangeInstance.address,
+            erc721BalanceThresholdAsset.address,
+            erc721alanceThreshold
+        );
+        const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10);
+        erc20CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
+            artifacts.BalanceThresholdFilter,
+            provider,
+            txDefaults,
+            exchangeInstance.address,
+            erc20BalanceThresholdAsset.address,
+            erc20BalanceThreshold
+        );
+
+        // Default order parameters
+        defaultOrderParams = {
+            exchangeAddress: exchangeInstance.address,
+            feeRecipientAddress,
+            makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
+            takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
+            makerAssetAmount,
+            takerAssetAmount,
+            makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT),
+            takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT),
+            senderAddress: erc721CompliantForwarderInstance.address,
+        };
+        const defaultOrderParams1 = {
+            makerAddress: compliantMakerAddress,
+            ...
+            defaultOrderParams,
+        }
+        const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)];
+        takerTransactionFactory = new TransactionFactory(makerPrivateKey, exchangeInstance.address);
+        orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1);
+        const defaultOrderParams2 = {
+            makerAddress: compliantMakerAddress2,
+            ...
+            defaultOrderParams,
+        }
+        const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress2)];
+        orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2);
+
+        const nonCompliantPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(nonCompliantAddress)];
+        const defaultNonCompliantOrderParams = {
+            makerAddress: nonCompliantAddress,
+            ...
+            defaultOrderParams,
+        };
+        nonCompliantOrderFactory = new OrderFactory(nonCompliantPrivateKey, defaultNonCompliantOrderParams);
+        // Create Valid/Invalid orders
+        const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)];
+        takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address);
+        compliantSignedOrder = await orderFactory.newSignedOrderAsync({
+            senderAddress: erc721CompliantForwarderInstance.address,
+        });
+        const compliantSignedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
+            compliantSignedOrder,
+        );
+        const compliantSignedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
+            compliantSignedOrderWithoutExchangeAddress,
+            takerAssetFillAmount,
+            compliantSignedOrder.signature,
+        );
+        compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction(
+            compliantSignedOrderWithoutExchangeAddressData,
+        );
+
+        logDecoder = new LogDecoder(web3Wrapper, {... artifacts, ... protocolArtifacts, ... tokensArtifacts});
+        erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc20CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider);
+        erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider);
+        erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(makerPrivateKey, exchangeInstance.address), provider);
+        erc721NonCompliantBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(nonCompliantPrivateKey, exchangeInstance.address), provider);
+        
+        // Instantiate internal exchange contract
+        exchangeInternals = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
+            protocolArtifacts.TestExchangeInternals,
+            provider,
+            txDefaults,
+        );
+    });
+    beforeEach(async () => {
+        await blockchainLifecycle.startAsync();
+    });
+    afterEach(async () => {
+        await blockchainLifecycle.revertAsync();
+    });
+
+    describe('General Sanity Checks', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => {
+            const compliantSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({
+                ...
+                defaultOrderParams,
+                makerAddress: compliantMakerAddress,
+                senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(),
+            });
+            // Execute a valid fill
+            const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrderERC20Sender, compliantTakerAddress, {takerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
+            );
+        });
+        it('should revert if the signed transaction is not intended for supported', async () => {
+            // Create signed order without the fillOrder function selector
+            const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data);
+            const selectorLengthInBytes = 4;
+            const txDataBufMinusSelector = txDataBuf.slice(selectorLengthInBytes);
+            const badSelector = '0x00000000';
+            const badSelectorBuf = ethUtil.toBuffer(badSelector);
+            const txDataBufWithBadSelector = Buffer.concat([badSelectorBuf, txDataBufMinusSelector]);
+            const txDataBufWithBadSelectorHex = ethUtil.bufferToHex(txDataBufWithBadSelector);
+            // Call compliant forwarder
+            return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
+                compliantSignedFillOrderTx.salt,
+                compliantSignedFillOrderTx.signerAddress,
+                txDataBufWithBadSelectorHex,
+                compliantSignedFillOrderTx.signature,
+            ));
+        });
+        it('should revert if senderAddress is not set to the compliant forwarding contract', async () => {
+            // Create signed order with incorrect senderAddress
+            const notBalanceThresholdFilterAddress = zrxToken.address;
+            const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: notBalanceThresholdFilterAddress,
+            });
+            const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
+                signedOrderWithBadSenderAddress,
+            );
+            const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
+                signedOrderWithoutExchangeAddress,
+                takerAssetFillAmount,
+                compliantSignedOrder.signature,
+            );
+            const signedFillOrderTx = takerTransactionFactory.newSignedTransaction(
+                signedOrderWithoutExchangeAddressData,
+            );
+            // Call compliant forwarder
+            return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
+                signedFillOrderTx.salt,
+                signedFillOrderTx.signerAddress,
+                signedFillOrderTx.data,
+                signedFillOrderTx.signature,
+            ));
+        });
+        // @TODO - greater than 1 balance
+    });
+
+    describe('batchFillOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .times(2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+                        
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('batchFillOrdersNoThrow', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .times(2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+                        
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('batchFillOrKillOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .times(2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+                        
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if one takerAssetFillAmount is not fully filled', async () => {
+            const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2);
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount];
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmounts}
+                ),
+                RevertReason.FailedExecution
+            );
+        });
+    });
+
+    describe('fillOrder', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
+            );
+        });
+        it('should revert if maker does not meet the balance threshold', async () => {
+            // Create signed order with non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: erc721CompliantForwarderInstance.address,
+                makerAddress: nonCompliantAddress
+            });
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.fillOrderAsync(
+                    signedOrderWithBadMakerAddress,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.fillOrderAsync(
+                    compliantSignedOrder,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('fillOrderNoThrow', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
+            );
+        });
+        it('should revert if maker does not meet the balance threshold', async () => {
+            // Create signed order with non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: erc721CompliantForwarderInstance.address,
+                makerAddress: nonCompliantAddress
+            });
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
+                    signedOrderWithBadMakerAddress,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.fillOrderNoThrowAsync(
+                    compliantSignedOrder,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('fillOrKillOrder', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const takerAssetFillAmount_ = compliantSignedOrder.takerAssetAmount;
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount: takerAssetFillAmount_});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount = takerAssetFillAmount_
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee
+                .times(makerAssetFillAmount)
+                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount_),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            );
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
+            );
+        });
+        it('should revert if maker does not meet the balance threshold', async () => {
+            // Create signed order with non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: erc721CompliantForwarderInstance.address,
+                makerAddress: nonCompliantAddress
+            });
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
+                    signedOrderWithBadMakerAddress,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.fillOrKillOrderAsync(
+                    compliantSignedOrder,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if takerAssetFillAmount is not fully filled', async () => {
+            const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2);
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
+                    compliantSignedOrder,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount: tooBigTakerAssetFillAmount}
+                ),
+                RevertReason.FailedExecution
+            );
+        });
+    });
+
+    describe('marketSellOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount2 = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('marketSellOrdersNoThrow', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerAssetFillAmount2 = takerAssetFillAmount
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {takerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('marketBuyOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const makerAssetFillAmount2 = takerAssetFillAmount
+            .times(compliantSignedOrder.makerAssetAmount)
+            .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            const dummyMakerAssetFillAmount = new BigNumber(0);
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const dummyMakerAssetFillAmount = new BigNumber(0);
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('marketBuyOrdersNoThrowAsync', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
+            // Execute a valid fill
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const makerAssetFillAmount2 = takerAssetFillAmount
+            .times(compliantSignedOrder.makerAssetAmount)
+            .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount});
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .times(makerAssetFillAmount2)
+                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
+            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+            // Maker #1
+            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+            );
+            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            );
+            // Maker #2
+            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            );
+            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            );
+            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            );
+            // Taker      
+            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            );
+            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            );
+            // Fee recipient
+            expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+            );
+        });
+        it('should revert if one maker does not meet the balance threshold', async () => {
+            // Create order set with one non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                makerAddress: nonCompliantAddress
+            });
+            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            // Execute transaction
+            const dummyMakerAssetFillAmount = new BigNumber(0);
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
+                    orders,
+                    compliantTakerAddress, 
+                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const dummyMakerAssetFillAmount = new BigNumber(0);
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
+                    orders,
+                    nonCompliantAddress, 
+                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+    
+    describe('matchOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => {
+            // Test values/results taken from Match Orders test:
+            // 'Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil'
+            // Create orders to match
+            const signedOrderLeft = await orderFactory.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
+                makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
+                takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
+                feeRecipientAddress: feeRecipientAddress,
+            });
+            const signedOrderRight = await orderFactory2.newSignedOrderAsync({
+                makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
+                takerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
+                makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
+                takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
+                feeRecipientAddress: feeRecipientAddress,
+            });
+            // Compute expected transfer amounts
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
+                amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
+                feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47%
+                // Right Maker
+                amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
+                amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
+                feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
+                // Taker
+                amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0),
+                feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
+                feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
+            };
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, compliantTakerAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses = [signedOrderLeft.makerAddress, signedOrderRight.makerAddress, compliantTakerAddress];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check balances
+            const newBalances = await erc20Wrapper.getBalancesAsync();
+            expect(
+                newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress],
+                'Checking left maker egress ERC20 account balance',
+            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].sub(expectedTransferAmounts.amountSoldByLeftMaker));
+            expect(
+                newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress],
+                'Checking right maker ingress ERC20 account balance',
+            ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].sub(expectedTransferAmounts.amountSoldByRightMaker));
+            expect(
+                newBalances[compliantTakerAddress][defaultMakerAssetAddress],
+                'Checking taker ingress ERC20 account balance',
+            ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountReceivedByTaker));
+            expect(
+                newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress],
+                'Checking left maker ingress ERC20 account balance',
+            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].add(expectedTransferAmounts.amountBoughtByLeftMaker));
+            expect(
+                newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress],
+                'Checking right maker egress ERC20 account balance',
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountBoughtByRightMaker),
+            );
+            // Paid fees
+            expect(
+                newBalances[signedOrderLeft.makerAddress][zrxToken.address],
+                'Checking left maker egress ERC20 account fees',
+            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByLeftMaker));
+            expect(
+                newBalances[signedOrderRight.makerAddress][zrxToken.address],
+                'Checking right maker egress ERC20 account fees',
+            ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByRightMaker));
+            expect(
+                newBalances[compliantTakerAddress][zrxToken.address],
+                'Checking taker egress ERC20 account fees',
+            ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByTakerLeft).sub(expectedTransferAmounts.feePaidByTakerRight));
+            // Received fees
+            expect(
+                newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address],
+                'Checking left fee recipient ingress ERC20 account fees',
+            ).to.be.bignumber.equal(
+                erc20Balances[feeRecipientAddress][zrxToken.address].add(expectedTransferAmounts.feePaidByLeftMaker).add(expectedTransferAmounts.feePaidByRightMaker).add(expectedTransferAmounts.feePaidByTakerLeft).add(expectedTransferAmounts.feePaidByTakerRight),
+            );
+        });
+        it('should revert if left maker does not meet the balance threshold', async () => {
+            // Create signed order with non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: erc721CompliantForwarderInstance.address,
+                makerAddress: nonCompliantAddress
+            });
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
+                    compliantSignedOrder,
+                    signedOrderWithBadMakerAddress,
+                    compliantTakerAddress, 
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if right maker does not meet the balance threshold', async () => {
+            // Create signed order with non-compliant maker address
+            const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
+                senderAddress: erc721CompliantForwarderInstance.address,
+                makerAddress: nonCompliantAddress
+            });
+            // Execute transaction
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
+                    signedOrderWithBadMakerAddress,
+                    compliantSignedOrder,
+                    compliantTakerAddress, 
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+        it('should revert if taker does not meet the balance threshold', async () => {
+            return expectTransactionFailedAsync(
+                erc721NonCompliantBalanceThresholdWrapper.matchOrdersAsync(
+                    compliantSignedOrder,
+                    compliantSignedOrder,
+                    nonCompliantAddress, 
+                ),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+            );
+        });
+    });
+
+    describe('cancelOrder', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+        });
+        it('Should successfully cancel order if maker meets balance threshold', async () => {
+            // Verify order is not cancelled
+            const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            // Cancel
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(compliantSignedOrder, compliantSignedOrder.makerAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+        });
+        it('Should successfully cancel order if maker does not meet balance threshold', async () => {
+            // Create order where maker does not meet balance threshold
+            const signedOrderWithBadMakerAddress = await nonCompliantOrderFactory.newSignedOrderAsync({});
+            // Verify order is not cancelled
+            const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress)
+            expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            // Cancel
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrderAsync(signedOrderWithBadMakerAddress, signedOrderWithBadMakerAddress.makerAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress)
+            expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+        });
+    });
+
+    describe('batchCancelOrders', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+        });
+        it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
+            // Create orders to cancel
+            const compliantSignedOrders = [
+                await orderFactory.newSignedOrderAsync(),
+                await orderFactory.newSignedOrderAsync(),
+                await orderFactory.newSignedOrderAsync(),
+            ]; 
+            // Verify orders are not cancelled
+            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
+                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+                return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            });
+            // Cancel
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(compliantSignedOrders, compliantSignedOrder.makerAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
+                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+                return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+            });
+        });
+        it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
+            // Create orders to cancel
+            const nonCompliantSignedOrders = [
+                await nonCompliantOrderFactory.newSignedOrderAsync(),
+                await nonCompliantOrderFactory.newSignedOrderAsync(),
+                await nonCompliantOrderFactory.newSignedOrderAsync(),
+            ]; 
+            // Verify orders are not cancelled
+            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
+                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+                return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            });
+            // Cancel
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.batchCancelOrdersAsync(nonCompliantSignedOrders, nonCompliantAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
+                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+                return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+            });
+        });
+    });
+
+    describe('cancelOrdersUpTo', () => {
+        beforeEach(async () => {
+            erc20Balances = await erc20Wrapper.getBalancesAsync();
+        });
+        it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
+            // Create orders to cancel
+            const compliantSignedOrders = [
+                await orderFactory.newSignedOrderAsync({salt: new BigNumber(0)}),
+                await orderFactory.newSignedOrderAsync({salt: new BigNumber(1)}),
+                await orderFactory.newSignedOrderAsync({salt: new BigNumber(2)}),
+            ]; 
+            // Verify orders are not cancelled
+            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
+                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+                return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            });
+            // Cancel
+            const cancelOrdersUpToThisSalt = new BigNumber(1);
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, compliantSignedOrder.makerAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            await _.each(compliantSignedOrders, async (compliantSignedOrder, salt: number) => {
+                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+                const saltAsBigNumber = new BigNumber(salt);
+                if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
+                    return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+                } else {
+                    return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+                }
+            });
+        });
+        it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
+            // Create orders to cancel
+            const nonCompliantSignedOrders = [
+                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(0)}),
+                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(1)}),
+                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(2)}),
+            ]; 
+            // Verify orders are not cancelled
+            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
+                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+                return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+            });
+            // Cancel
+            const cancelOrdersUpToThisSalt = new BigNumber(1);
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, nonCompliantAddress);
+            // Assert validated addresses
+            const expectedValidatedAddresseses: string[] = [];
+            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            // Check that order was cancelled
+            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder, salt: number) => {
+                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+                const saltAsBigNumber = new BigNumber(salt);
+                if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
+                    return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
+                } else {
+                    return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
+                }
+            });
+        });
+    });
+});
+// tslint:disable:max-file-line-count
+// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/test/utils/balance_threshold_wrapper.ts b/contracts/extensions/test/utils/balance_threshold_wrapper.ts
new file mode 100644
index 000000000..63128686c
--- /dev/null
+++ b/contracts/extensions/test/utils/balance_threshold_wrapper.ts
@@ -0,0 +1,246 @@
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { ExchangeContract } from '@0x/contracts-protocol';
+import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
+
+import { formatters, LogDecoder, orderUtils, OrderInfo, TransactionFactory } from '@0x/contracts-test-utils';
+import { artifacts } from '../../src/artifacts';
+import {artifacts as protocolArtifacts} from '@0x/contracts-protocol';
+import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
+
+export class BalanceThresholdWrapper {
+    private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
+    private readonly _signerTransactionFactory: TransactionFactory;
+    private readonly _exchange: ExchangeContract;
+    private readonly _web3Wrapper: Web3Wrapper;
+    private readonly _logDecoder: LogDecoder;
+    constructor(balanceThresholdFilter: BalanceThresholdFilterContract, exchangeContract: ExchangeContract, signerTransactionFactory: TransactionFactory, provider: Provider) {
+        this._balanceThresholdFilter = balanceThresholdFilter;
+        this._exchange = exchangeContract;
+        this._signerTransactionFactory = signerTransactionFactory;
+        this._web3Wrapper = new Web3Wrapper(provider);
+        this._logDecoder = new LogDecoder(this._web3Wrapper, {... artifacts, ... tokensArtifacts, ... protocolArtifacts} );
+    }
+    public async fillOrderAsync(
+        signedOrder: SignedOrder,
+        from: string,
+        opts: { takerAssetFillAmount?: BigNumber } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
+        const data = this._exchange.fillOrder.getABIEncodedTransactionData(
+            params.order,
+            params.takerAssetFillAmount,
+            params.signature,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async fillOrKillOrderAsync(
+        signedOrder: SignedOrder,
+        from: string,
+        opts: { takerAssetFillAmount?: BigNumber } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
+        const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
+            params.order,
+            params.takerAssetFillAmount,
+            params.signature,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async fillOrderNoThrowAsync(
+        signedOrder: SignedOrder,
+        from: string,
+        opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
+        const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
+            params.order,
+            params.takerAssetFillAmount,
+            params.signature,
+        );
+        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        return txReceipt;
+    }
+    public async batchFillOrdersAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { takerAssetFillAmounts?: BigNumber[] } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
+        const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
+            params.orders,
+            params.takerAssetFillAmounts,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async batchFillOrKillOrdersAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { takerAssetFillAmounts?: BigNumber[] } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
+        const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
+            params.orders,
+            params.takerAssetFillAmounts,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async batchFillOrdersNoThrowAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
+        const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
+            params.orders,
+            params.takerAssetFillAmounts,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        return txReceipt;
+    }
+    public async marketSellOrdersAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { takerAssetFillAmount: BigNumber },
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
+        const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
+            params.orders,
+            params.takerAssetFillAmount,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async marketSellOrdersNoThrowAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { takerAssetFillAmount: BigNumber; gas?: number },
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
+        const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
+            params.orders,
+            params.takerAssetFillAmount,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        return txReceipt;
+    }
+    public async marketBuyOrdersAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { makerAssetFillAmount: BigNumber },
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
+        const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
+            params.orders,
+            params.makerAssetFillAmount,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async marketBuyOrdersNoThrowAsync(
+        orders: SignedOrder[],
+        from: string,
+        opts: { makerAssetFillAmount: BigNumber; gas?: number },
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
+        const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
+            params.orders,
+            params.makerAssetFillAmount,
+            params.signatures,
+        );
+        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        return txReceipt;
+    }
+    public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = orderUtils.createCancel(signedOrder);
+        const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async batchCancelOrdersAsync(
+        orders: SignedOrder[],
+        from: string,
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = formatters.createBatchCancel(orders);
+        const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
+        const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
+        const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
+        return filledAmount;
+    }
+    public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
+        const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
+        return isCancelled;
+    }
+    public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
+        const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
+        return orderEpoch;
+    }
+    public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
+        const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
+        return orderInfo;
+    }
+    public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
+        const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
+        return ordersInfo;
+    }
+    public async matchOrdersAsync(
+        signedOrderLeft: SignedOrder,
+        signedOrderRight: SignedOrder,
+        from: string,
+    ): Promise<TransactionReceiptWithDecodedLogs> {
+        const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
+        const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
+            params.left,
+            params.right,
+            params.leftSignature,
+            params.rightSignature
+        );
+        const txReceipt = this._executeTransaction(data, from);
+        return txReceipt;
+    }
+    public getBalanceThresholdAddress(): string {
+        return this._balanceThresholdFilter.address;
+    }
+    public getExchangeAddress(): string {
+        return this._exchange.address;
+    }
+    // Exchange functions
+    //abiEncodeFillOrder
+    //getFillOrderResultsAsync
+    //
+    private async _executeTransaction(abiEncodedExchangeTxData: string, from: string, gas?: number): Promise<TransactionReceiptWithDecodedLogs> {
+        const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
+        const txOpts = _.isUndefined(gas) ? {from} : {from, gas};
+        const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
+            signedExchangeTx.salt,
+            signedExchangeTx.signerAddress,
+            signedExchangeTx.data,
+            signedExchangeTx.signature,
+            txOpts,
+        );
+        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
+        return txReceipt;
+    }
+}
diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json
index a4ce1e002..5d3ebfe74 100644
--- a/contracts/extensions/tsconfig.json
+++ b/contracts/extensions/tsconfig.json
@@ -6,6 +6,6 @@
         "resolveJsonModule": true
     },
     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
-    "files": ["./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
+    "files": ["./generated-artifacts/BalanceThresholdFilter.json", "./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
     "exclude": ["./deploy/solc/solc_bin"]
 }
-- 
cgit v1.2.3


From 6a0f5f39eea5fef285a1e2e962be03c2fa8847ab Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 15:55:36 -0800
Subject: Prettier / Linter fixes for TS

---
 .../test/extensions/balance_threshold_filter.ts    | 779 +++++++++++++--------
 contracts/extensions/test/extensions/forwarder.ts  |   1 -
 .../test/utils/balance_threshold_wrapper.ts        |  95 ++-
 contracts/extensions/tsconfig.json                 |   6 +-
 4 files changed, 543 insertions(+), 338 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index 34339564c..e4eda3354 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -1,12 +1,12 @@
 import { BlockchainLifecycle } from '@0x/dev-utils';
 import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason, SignedOrder, Order } from '@0x/types';
+import { Order, RevertReason, SignedOrder } from '@0x/types';
 import { BigNumber } from '@0x/utils';
 import { Web3Wrapper } from '@0x/web3-wrapper';
 import * as chai from 'chai';
+import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
-import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
 
 import {
     artifacts as protocolArtifacts,
@@ -14,7 +14,6 @@ import {
     ERC721Wrapper,
     ExchangeContract,
     ExchangeWrapper,
-    TestExchangeInternalsContract,
 } from '@0x/contracts-protocol';
 import {
     chaiSetup,
@@ -23,26 +22,19 @@ import {
     ERC20BalancesByOwner,
     expectTransactionFailedAsync,
     expectTransactionFailedWithoutReasonAsync,
-    getLatestBlockTimestampAsync,
-    LogDecoder,
     OrderFactory,
     OrderStatus,
     orderUtils,
     provider,
     SignedTransaction,
-    txDefaults,
     TransactionFactory,
+    txDefaults,
     web3Wrapper,
 } from '@0x/contracts-test-utils';
-import {
-    artifacts as tokensArtifacts,
-    DummyERC20TokenContract,
-    DummyERC721TokenContract,
-    WETH9Contract,
-} from '@0x/contracts-tokens';
+import { DummyERC20TokenContract } from '@0x/contracts-tokens';
 
-import { artifacts } from '../../src/artifacts';
 import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
+import { artifacts } from '../../src/artifacts';
 import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper';
 
 chaiSetup.configure();
@@ -51,7 +43,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 const DECIMALS_DEFAULT = 18;
 
 interface ValidatedAddressesLog {
-    args: {addresses: string[]}
+    args: { addresses: string[] };
 }
 
 describe.only(ContractName.BalanceThresholdFilter, () => {
@@ -79,14 +71,10 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
     let erc721NonCompliantBalanceThresholdWrapper: BalanceThresholdWrapper;
 
     let takerTransactionFactory: TransactionFactory;
-    let makerTransactionFactory: TransactionFactory;
     let compliantSignedOrder: SignedOrder;
     let compliantSignedOrder2: SignedOrder;
     let compliantSignedFillOrderTx: SignedTransaction;
 
-    let logDecoder: LogDecoder;
-    let exchangeInternals: TestExchangeInternalsContract;
-
     let defaultOrderParams: Partial<Order>;
 
     const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
@@ -96,14 +84,17 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
     let erc721CompliantForwarderInstance: BalanceThresholdFilterContract;
     let erc20CompliantForwarderInstance: BalanceThresholdFilterContract;
 
-    const assertValidatedAddressesLog = async (txReceipt: TransactionReceiptWithDecodedLogs, expectedValidatedAddresses: string[]) => {
+    const assertValidatedAddressesLog = async (
+        txReceipt: TransactionReceiptWithDecodedLogs,
+        expectedValidatedAddresses: string[],
+    ) => {
         expect(txReceipt.logs.length).to.be.gte(1);
         const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog;
         const validatedAddresses = validatedAddressesLog.args.addresses;
         // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once
         //             the new ABI Encoder/Decoder is used by the contract templates.
-        let validatedAddressesNormalized: string[] = [];
-        _.each(validatedAddresses, (address) => {
+        const validatedAddressesNormalized: string[] = [];
+        _.each(validatedAddresses, address => {
             const normalizedAddress = _.toLower(address);
             validatedAddressesNormalized.push(normalizedAddress);
         });
@@ -124,7 +115,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         ] = accounts);
         // Create wrappers
         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-        let compliantAddresses = _.cloneDeepWith(usedAddresses);
+        const compliantAddresses = _.cloneDeepWith(usedAddresses);
         _.remove(compliantAddresses, (address: string) => {
             return address === nonCompliantAddress;
         });
@@ -168,7 +159,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             txDefaults,
             exchangeInstance.address,
             erc721BalanceThresholdAsset.address,
-            erc721alanceThreshold
+            erc721alanceThreshold,
         );
         const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10);
         erc20CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
@@ -177,7 +168,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             txDefaults,
             exchangeInstance.address,
             erc20BalanceThresholdAsset.address,
-            erc20BalanceThreshold
+            erc20BalanceThreshold,
         );
 
         // Default order parameters
@@ -194,25 +185,22 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         };
         const defaultOrderParams1 = {
             makerAddress: compliantMakerAddress,
-            ...
-            defaultOrderParams,
-        }
+            ...defaultOrderParams,
+        };
         const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)];
         takerTransactionFactory = new TransactionFactory(makerPrivateKey, exchangeInstance.address);
         orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1);
         const defaultOrderParams2 = {
             makerAddress: compliantMakerAddress2,
-            ...
-            defaultOrderParams,
-        }
+            ...defaultOrderParams,
+        };
         const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress2)];
         orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2);
 
         const nonCompliantPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(nonCompliantAddress)];
         const defaultNonCompliantOrderParams = {
             makerAddress: nonCompliantAddress,
-            ...
-            defaultOrderParams,
+            ...defaultOrderParams,
         };
         nonCompliantOrderFactory = new OrderFactory(nonCompliantPrivateKey, defaultNonCompliantOrderParams);
         // Create Valid/Invalid orders
@@ -233,17 +221,29 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             compliantSignedOrderWithoutExchangeAddressData,
         );
 
-        logDecoder = new LogDecoder(web3Wrapper, {... artifacts, ... protocolArtifacts, ... tokensArtifacts});
-        erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc20CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider);
-        erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider);
-        erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(makerPrivateKey, exchangeInstance.address), provider);
-        erc721NonCompliantBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(nonCompliantPrivateKey, exchangeInstance.address), provider);
-        
-        // Instantiate internal exchange contract
-        exchangeInternals = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
-            protocolArtifacts.TestExchangeInternals,
+        erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
+            erc20CompliantForwarderInstance,
+            exchangeInstance,
+            new TransactionFactory(takerPrivateKey, exchangeInstance.address),
+            provider,
+        );
+        erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
+            erc721CompliantForwarderInstance,
+            exchangeInstance,
+            new TransactionFactory(takerPrivateKey, exchangeInstance.address),
+            provider,
+        );
+        erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
+            erc721CompliantForwarderInstance,
+            exchangeInstance,
+            new TransactionFactory(makerPrivateKey, exchangeInstance.address),
+            provider,
+        );
+        erc721NonCompliantBalanceThresholdWrapper = new BalanceThresholdWrapper(
+            erc721CompliantForwarderInstance,
+            exchangeInstance,
+            new TransactionFactory(nonCompliantPrivateKey, exchangeInstance.address),
             provider,
-            txDefaults,
         );
     });
     beforeEach(async () => {
@@ -261,16 +261,22 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => {
             const compliantSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({
-                ...
-                defaultOrderParams,
+                ...defaultOrderParams,
                 makerAddress: compliantMakerAddress,
                 senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(),
             });
             // Execute a valid fill
-            const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrderERC20Sender, compliantTakerAddress, {takerAssetFillAmount});
+            const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(
+                compliantSignedOrderERC20Sender,
+                compliantTakerAddress,
+                { takerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
@@ -314,12 +320,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const txDataBufWithBadSelector = Buffer.concat([badSelectorBuf, txDataBufMinusSelector]);
             const txDataBufWithBadSelectorHex = ethUtil.bufferToHex(txDataBufWithBadSelector);
             // Call compliant forwarder
-            return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
-                compliantSignedFillOrderTx.salt,
-                compliantSignedFillOrderTx.signerAddress,
-                txDataBufWithBadSelectorHex,
-                compliantSignedFillOrderTx.signature,
-            ));
+            return expectTransactionFailedWithoutReasonAsync(
+                erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
+                    compliantSignedFillOrderTx.salt,
+                    compliantSignedFillOrderTx.signerAddress,
+                    txDataBufWithBadSelectorHex,
+                    compliantSignedFillOrderTx.signature,
+                ),
+            );
         });
         it('should revert if senderAddress is not set to the compliant forwarding contract', async () => {
             // Create signed order with incorrect senderAddress
@@ -339,12 +347,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 signedOrderWithoutExchangeAddressData,
             );
             // Call compliant forwarder
-            return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
-                signedFillOrderTx.salt,
-                signedFillOrderTx.signerAddress,
-                signedFillOrderTx.data,
-                signedFillOrderTx.signature,
-            ));
+            return expectTransactionFailedWithoutReasonAsync(
+                erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
+                    signedFillOrderTx.salt,
+                    signedFillOrderTx.signerAddress,
+                    signedFillOrderTx.data,
+                    signedFillOrderTx.signature,
+                ),
+            );
         });
         // @TODO - greater than 1 balance
     });
@@ -359,10 +369,18 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(
+                orders,
+                compliantTakerAddress,
+                { takerAssetFillAmounts },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
@@ -396,11 +414,11 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-                        
+
             expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
@@ -416,29 +434,25 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create order set with one non-compliant maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersAsync(orders, nonCompliantAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -453,10 +467,18 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
+                orders,
+                compliantTakerAddress,
+                { takerAssetFillAmounts },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
@@ -490,11 +512,11 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-                        
+
             expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
@@ -510,29 +532,25 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create order set with one non-compliant maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -547,10 +565,18 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
+                orders,
+                compliantTakerAddress,
+                { takerAssetFillAmounts },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
@@ -584,11 +610,11 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-                        
+
             expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
@@ -604,29 +630,25 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create order set with one non-compliant maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, nonCompliantAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if one takerAssetFillAmount is not fully filled', async () => {
@@ -634,12 +656,10 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmounts}
-                ),
-                RevertReason.FailedExecution
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmounts,
+                }),
+                RevertReason.FailedExecution,
             );
         });
     });
@@ -651,10 +671,17 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(
+                compliantSignedOrder,
+                compliantTakerAddress,
+                { takerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
@@ -692,26 +719,24 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create signed order with non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrderAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount}
+                    compliantTakerAddress,
+                    { takerAssetFillAmount },
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.fillOrderAsync(
-                    compliantSignedOrder,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, nonCompliantAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -723,10 +748,17 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
+                compliantSignedOrder,
+                compliantTakerAddress,
+                { takerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
@@ -764,26 +796,26 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create signed order with non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount}
+                    compliantTakerAddress,
+                    { takerAssetFillAmount },
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
                 erc721NonCompliantBalanceThresholdWrapper.fillOrderNoThrowAsync(
                     compliantSignedOrder,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmount}
+                    nonCompliantAddress,
+                    { takerAssetFillAmount },
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -796,10 +828,17 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
             const takerAssetFillAmount_ = compliantSignedOrder.takerAssetAmount;
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount: takerAssetFillAmount_});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
+                compliantSignedOrder,
+                compliantTakerAddress,
+                { takerAssetFillAmount: takerAssetFillAmount_ },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount_
@@ -837,37 +876,35 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Create signed order with non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount}
+                    compliantTakerAddress,
+                    { takerAssetFillAmount },
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
                 erc721NonCompliantBalanceThresholdWrapper.fillOrKillOrderAsync(
                     compliantSignedOrder,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmount}
+                    nonCompliantAddress,
+                    { takerAssetFillAmount },
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if takerAssetFillAmount is not fully filled', async () => {
             const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
-                    compliantSignedOrder,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount: tooBigTakerAssetFillAmount}
-                ),
-                RevertReason.FailedExecution
+                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(compliantSignedOrder, compliantTakerAddress, {
+                    takerAssetFillAmount: tooBigTakerAssetFillAmount,
+                }),
+                RevertReason.FailedExecution,
             );
         });
     });
@@ -882,10 +919,18 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(
+                orders,
+                compliantTakerAddress,
+                { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount2 = takerAssetFillAmount
@@ -901,10 +946,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
             expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
+                    compliantSignedOrder.makerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
+                    compliantSignedOrder.takerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
@@ -919,7 +968,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
@@ -931,34 +980,33 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+                erc20Balances[feeRecipientAddress][zrxToken.address]
+                    .add(compliantSignedOrder.makerFee)
+                    .add(makerFeePaid2)
+                    .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
             // Create order set with one non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersAsync(orders, nonCompliantAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -973,10 +1021,18 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
+                orders,
+                compliantTakerAddress,
+                { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount2 = takerAssetFillAmount
@@ -992,10 +1048,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
             expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
+                    compliantSignedOrder.makerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
+                    compliantSignedOrder.takerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
@@ -1010,7 +1070,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
@@ -1022,34 +1082,33 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+                erc20Balances[feeRecipientAddress][zrxToken.address]
+                    .add(compliantSignedOrder.makerFee)
+                    .add(makerFeePaid2)
+                    .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
             // Create order set with one non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {takerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {takerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -1065,13 +1124,21 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const makerAssetFillAmount2 = takerAssetFillAmount
-            .times(compliantSignedOrder.makerAssetAmount)
-            .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
             const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(
+                orders,
+                compliantTakerAddress,
+                { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerFeePaid2 = compliantSignedOrder2.makerFee
@@ -1083,10 +1150,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
             expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
+                    compliantSignedOrder.makerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
+                    compliantSignedOrder.takerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
@@ -1101,7 +1172,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
@@ -1113,36 +1184,35 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+                erc20Balances[feeRecipientAddress][zrxToken.address]
+                    .add(compliantSignedOrder.makerFee)
+                    .add(makerFeePaid2)
+                    .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
             // Create order set with one non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, compliantTakerAddress, {
+                    makerAssetFillAmount: dummyMakerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersAsync(orders, nonCompliantAddress, {
+                    makerAssetFillAmount: dummyMakerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -1158,13 +1228,21 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const makerAssetFillAmount2 = takerAssetFillAmount
-            .times(compliantSignedOrder.makerAssetAmount)
-            .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
+                .times(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
             const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount});
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
+                orders,
+                compliantTakerAddress,
+                { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                compliantSignedOrder.makerAddress,
+                compliantSignedOrder2.makerAddress,
+                compliantSignedFillOrderTx.signerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerFeePaid2 = compliantSignedOrder2.makerFee
@@ -1176,10 +1254,14 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
             expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
+                    compliantSignedOrder.makerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount),
+                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
+                    compliantSignedOrder.takerAssetAmount,
+                ),
             );
             expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
@@ -1194,7 +1276,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
-            // Taker      
+            // Taker
             expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
                 erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
@@ -1206,40 +1288,39 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid),
+                erc20Balances[feeRecipientAddress][zrxToken.address]
+                    .add(compliantSignedOrder.makerFee)
+                    .add(makerFeePaid2)
+                    .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
             // Create order set with one non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
-                    orders,
-                    compliantTakerAddress, 
-                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                    makerAssetFillAmount: dummyMakerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             const orders = [compliantSignedOrder, compliantSignedOrder2];
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
-                    orders,
-                    nonCompliantAddress, 
-                    {makerAssetFillAmount: dummyMakerAssetFillAmount}
-                ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                    makerAssetFillAmount: dummyMakerAssetFillAmount,
+                }),
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
-    
+
     describe('matchOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
@@ -1255,7 +1336,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
                 makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
                 takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
-                feeRecipientAddress: feeRecipientAddress,
+                feeRecipientAddress,
             });
             const signedOrderRight = await orderFactory2.newSignedOrderAsync({
                 makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
@@ -1264,7 +1345,7 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
                 makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
                 takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
-                feeRecipientAddress: feeRecipientAddress,
+                feeRecipientAddress,
             });
             // Compute expected transfer amounts
             const expectedTransferAmounts = {
@@ -1281,85 +1362,127 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
                 feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
             };
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, compliantTakerAddress);
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
+                signedOrderLeft,
+                signedOrderRight,
+                compliantTakerAddress,
+            );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [signedOrderLeft.makerAddress, signedOrderRight.makerAddress, compliantTakerAddress];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            const expectedValidatedAddresseses = [
+                signedOrderLeft.makerAddress,
+                signedOrderRight.makerAddress,
+                compliantTakerAddress,
+            ];
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             expect(
                 newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress],
                 'Checking left maker egress ERC20 account balance',
-            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].sub(expectedTransferAmounts.amountSoldByLeftMaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].sub(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
             expect(
                 newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress],
                 'Checking right maker ingress ERC20 account balance',
-            ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].sub(expectedTransferAmounts.amountSoldByRightMaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].sub(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
             expect(
                 newBalances[compliantTakerAddress][defaultMakerAssetAddress],
                 'Checking taker ingress ERC20 account balance',
-            ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountReceivedByTaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(
+                    expectedTransferAmounts.amountReceivedByTaker,
+                ),
+            );
             expect(
                 newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress],
                 'Checking left maker ingress ERC20 account balance',
-            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].add(expectedTransferAmounts.amountBoughtByLeftMaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].add(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
             expect(
                 newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress],
                 'Checking right maker egress ERC20 account balance',
             ).to.be.bignumber.equal(
-                erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountBoughtByRightMaker),
+                erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].add(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
             );
             // Paid fees
             expect(
                 newBalances[signedOrderLeft.makerAddress][zrxToken.address],
                 'Checking left maker egress ERC20 account fees',
-            ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByLeftMaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus(
+                    expectedTransferAmounts.feePaidByLeftMaker,
+                ),
+            );
             expect(
                 newBalances[signedOrderRight.makerAddress][zrxToken.address],
                 'Checking right maker egress ERC20 account fees',
-            ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByRightMaker));
+            ).to.be.bignumber.equal(
+                erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus(
+                    expectedTransferAmounts.feePaidByRightMaker,
+                ),
+            );
             expect(
                 newBalances[compliantTakerAddress][zrxToken.address],
                 'Checking taker egress ERC20 account fees',
-            ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByTakerLeft).sub(expectedTransferAmounts.feePaidByTakerRight));
+            ).to.be.bignumber.equal(
+                erc20Balances[compliantTakerAddress][zrxToken.address]
+                    .minus(expectedTransferAmounts.feePaidByTakerLeft)
+                    .sub(expectedTransferAmounts.feePaidByTakerRight),
+            );
             // Received fees
             expect(
                 newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address],
                 'Checking left fee recipient ingress ERC20 account fees',
             ).to.be.bignumber.equal(
-                erc20Balances[feeRecipientAddress][zrxToken.address].add(expectedTransferAmounts.feePaidByLeftMaker).add(expectedTransferAmounts.feePaidByRightMaker).add(expectedTransferAmounts.feePaidByTakerLeft).add(expectedTransferAmounts.feePaidByTakerRight),
+                erc20Balances[feeRecipientAddress][zrxToken.address]
+                    .add(expectedTransferAmounts.feePaidByLeftMaker)
+                    .add(expectedTransferAmounts.feePaidByRightMaker)
+                    .add(expectedTransferAmounts.feePaidByTakerLeft)
+                    .add(expectedTransferAmounts.feePaidByTakerRight),
             );
         });
         it('should revert if left maker does not meet the balance threshold', async () => {
             // Create signed order with non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
                     compliantSignedOrder,
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress, 
+                    compliantTakerAddress,
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if right maker does not meet the balance threshold', async () => {
             // Create signed order with non-compliant maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress
+                makerAddress: nonCompliantAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
                     signedOrderWithBadMakerAddress,
                     compliantSignedOrder,
-                    compliantTakerAddress, 
+                    compliantTakerAddress,
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
@@ -1367,9 +1490,9 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 erc721NonCompliantBalanceThresholdWrapper.matchOrdersAsync(
                     compliantSignedOrder,
                     compliantSignedOrder,
-                    nonCompliantAddress, 
+                    nonCompliantAddress,
                 ),
-                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold
+                RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
     });
@@ -1382,30 +1505,44 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         });
         it('Should successfully cancel order if maker meets balance threshold', async () => {
             // Verify order is not cancelled
-            const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                compliantSignedOrder,
+            );
             expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             // Cancel
-            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(compliantSignedOrder, compliantSignedOrder.makerAddress);
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(
+                compliantSignedOrder,
+                compliantSignedOrder.makerAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                compliantSignedOrder,
+            );
             expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
         });
         it('Should successfully cancel order if maker does not meet balance threshold', async () => {
             // Create order where maker does not meet balance threshold
             const signedOrderWithBadMakerAddress = await nonCompliantOrderFactory.newSignedOrderAsync({});
             // Verify order is not cancelled
-            const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress)
+            const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+                signedOrderWithBadMakerAddress,
+            );
             expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             // Cancel
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrderAsync(signedOrderWithBadMakerAddress, signedOrderWithBadMakerAddress.makerAddress);
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrderAsync(
+                signedOrderWithBadMakerAddress,
+                signedOrderWithBadMakerAddress.makerAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress)
+            const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                signedOrderWithBadMakerAddress,
+            );
             expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
         });
     });
@@ -1420,20 +1557,27 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 await orderFactory.newSignedOrderAsync(),
                 await orderFactory.newSignedOrderAsync(),
                 await orderFactory.newSignedOrderAsync(),
-            ]; 
+            ];
             // Verify orders are not cancelled
-            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
-                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            _.each(compliantSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
-            const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(compliantSignedOrders, compliantSignedOrder.makerAddress);
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(
+                compliantSignedOrders,
+                compliantSignedOrder.makerAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
-                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            _.each(compliantSignedOrders, async signedOrder => {
+                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
             });
         });
@@ -1443,20 +1587,27 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
                 await nonCompliantOrderFactory.newSignedOrderAsync(),
                 await nonCompliantOrderFactory.newSignedOrderAsync(),
                 await nonCompliantOrderFactory.newSignedOrderAsync(),
-            ]; 
+            ];
             // Verify orders are not cancelled
-            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
-                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+            _.each(nonCompliantSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.batchCancelOrdersAsync(nonCompliantSignedOrders, nonCompliantAddress);
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.batchCancelOrdersAsync(
+                nonCompliantSignedOrders,
+                nonCompliantAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
-                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+            _.each(nonCompliantSignedOrders, async signedOrder => {
+                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
             });
         });
@@ -1469,24 +1620,31 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
             // Create orders to cancel
             const compliantSignedOrders = [
-                await orderFactory.newSignedOrderAsync({salt: new BigNumber(0)}),
-                await orderFactory.newSignedOrderAsync({salt: new BigNumber(1)}),
-                await orderFactory.newSignedOrderAsync({salt: new BigNumber(2)}),
-            ]; 
+                await orderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
+                await orderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
+                await orderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
+            ];
             // Verify orders are not cancelled
-            await _.each(compliantSignedOrders, async (compliantSignedOrder) => {
-                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            _.each(compliantSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
             const cancelOrdersUpToThisSalt = new BigNumber(1);
-            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, compliantSignedOrder.makerAddress);
+            const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(
+                cancelOrdersUpToThisSalt,
+                compliantSignedOrder.makerAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            await _.each(compliantSignedOrders, async (compliantSignedOrder, salt: number) => {
-                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder)
+            _.each(compliantSignedOrders, async (signedOrder, salt: number) => {
+                const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 const saltAsBigNumber = new BigNumber(salt);
                 if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
                     return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
@@ -1498,24 +1656,31 @@ describe.only(ContractName.BalanceThresholdFilter, () => {
         it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
             // Create orders to cancel
             const nonCompliantSignedOrders = [
-                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(0)}),
-                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(1)}),
-                await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(2)}),
-            ]; 
+                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
+                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
+                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
+            ];
             // Verify orders are not cancelled
-            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => {
-                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+            _.each(nonCompliantSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
             const cancelOrdersUpToThisSalt = new BigNumber(1);
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, nonCompliantAddress);
+            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrdersUpToAsync(
+                cancelOrdersUpToThisSalt,
+                nonCompliantAddress,
+            );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-            assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
+            await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder, salt: number) => {
-                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder)
+            _.each(nonCompliantSignedOrders, async (signedOrder, salt: number) => {
+                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+                    signedOrder,
+                );
                 const saltAsBigNumber = new BigNumber(salt);
                 if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) {
                     return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts
index a4afa283e..4027f493d 100644
--- a/contracts/extensions/test/extensions/forwarder.ts
+++ b/contracts/extensions/test/extensions/forwarder.ts
@@ -61,7 +61,6 @@ describe(ContractName.Forwarder, () => {
     let wethContract: WETH9Contract;
     let forwarderWrapper: ForwarderWrapper;
     let exchangeWrapper: ExchangeWrapper;
-    let takerPrivateKey: Buffer;
 
     let orderWithoutFee: SignedOrder;
     let orderWithFee: SignedOrder;
diff --git a/contracts/extensions/test/utils/balance_threshold_wrapper.ts b/contracts/extensions/test/utils/balance_threshold_wrapper.ts
index 63128686c..28a4ef011 100644
--- a/contracts/extensions/test/utils/balance_threshold_wrapper.ts
+++ b/contracts/extensions/test/utils/balance_threshold_wrapper.ts
@@ -1,16 +1,21 @@
+import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol';
+import {
+    FillResults,
+    formatters,
+    LogDecoder,
+    OrderInfo,
+    orderUtils,
+    TransactionFactory,
+} from '@0x/contracts-test-utils';
+import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
 import { SignedOrder } from '@0x/types';
 import { BigNumber } from '@0x/utils';
 import { Web3Wrapper } from '@0x/web3-wrapper';
 import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { ExchangeContract } from '@0x/contracts-protocol';
 import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
-
-import { formatters, LogDecoder, orderUtils, OrderInfo, TransactionFactory } from '@0x/contracts-test-utils';
 import { artifacts } from '../../src/artifacts';
-import {artifacts as protocolArtifacts} from '@0x/contracts-protocol';
-import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
 
 export class BalanceThresholdWrapper {
     private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
@@ -18,12 +23,21 @@ export class BalanceThresholdWrapper {
     private readonly _exchange: ExchangeContract;
     private readonly _web3Wrapper: Web3Wrapper;
     private readonly _logDecoder: LogDecoder;
-    constructor(balanceThresholdFilter: BalanceThresholdFilterContract, exchangeContract: ExchangeContract, signerTransactionFactory: TransactionFactory, provider: Provider) {
+    constructor(
+        balanceThresholdFilter: BalanceThresholdFilterContract,
+        exchangeContract: ExchangeContract,
+        signerTransactionFactory: TransactionFactory,
+        provider: Provider,
+    ) {
         this._balanceThresholdFilter = balanceThresholdFilter;
         this._exchange = exchangeContract;
         this._signerTransactionFactory = signerTransactionFactory;
         this._web3Wrapper = new Web3Wrapper(provider);
-        this._logDecoder = new LogDecoder(this._web3Wrapper, {... artifacts, ... tokensArtifacts, ... protocolArtifacts} );
+        this._logDecoder = new LogDecoder(this._web3Wrapper, {
+            ...artifacts,
+            ...tokensArtifacts,
+            ...protocolArtifacts,
+        });
     }
     public async fillOrderAsync(
         signedOrder: SignedOrder,
@@ -36,7 +50,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmount,
             params.signature,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async fillOrKillOrderAsync(
@@ -50,7 +64,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmount,
             params.signature,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async fillOrderNoThrowAsync(
@@ -64,7 +78,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmount,
             params.signature,
         );
-        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
         return txReceipt;
     }
     public async batchFillOrdersAsync(
@@ -78,7 +92,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmounts,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async batchFillOrKillOrdersAsync(
@@ -92,7 +106,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmounts,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async batchFillOrdersNoThrowAsync(
@@ -106,7 +120,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmounts,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
         return txReceipt;
     }
     public async marketSellOrdersAsync(
@@ -120,7 +134,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmount,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async marketSellOrdersNoThrowAsync(
@@ -134,7 +148,7 @@ export class BalanceThresholdWrapper {
             params.takerAssetFillAmount,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
         return txReceipt;
     }
     public async marketBuyOrdersAsync(
@@ -148,7 +162,7 @@ export class BalanceThresholdWrapper {
             params.makerAssetFillAmount,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async marketBuyOrdersNoThrowAsync(
@@ -162,13 +176,13 @@ export class BalanceThresholdWrapper {
             params.makerAssetFillAmount,
             params.signatures,
         );
-        const txReceipt = this._executeTransaction(data, from, opts.gas);
+        const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
         return txReceipt;
     }
     public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
         const params = orderUtils.createCancel(signedOrder);
         const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async batchCancelOrdersAsync(
@@ -177,12 +191,12 @@ export class BalanceThresholdWrapper {
     ): Promise<TransactionReceiptWithDecodedLogs> {
         const params = formatters.createBatchCancel(orders);
         const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
         const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
     public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
@@ -198,7 +212,7 @@ export class BalanceThresholdWrapper {
         return orderEpoch;
     }
     public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
-        const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
+        const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
         return orderInfo;
     }
     public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
@@ -215,24 +229,47 @@ export class BalanceThresholdWrapper {
             params.left,
             params.right,
             params.leftSignature,
-            params.rightSignature
+            params.rightSignature,
         );
-        const txReceipt = this._executeTransaction(data, from);
+        const txReceipt = this._executeTransactionAsync(data, from);
         return txReceipt;
     }
+    public async getFillOrderResultsAsync(
+        signedOrder: SignedOrder,
+        from: string,
+        opts: { takerAssetFillAmount?: BigNumber } = {},
+    ): Promise<FillResults> {
+        const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
+        const fillResults = await this._exchange.fillOrder.callAsync(
+            params.order,
+            params.takerAssetFillAmount,
+            params.signature,
+            { from },
+        );
+        return fillResults;
+    }
+    public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
+        const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
+        const data = this._exchange.fillOrder.getABIEncodedTransactionData(
+            params.order,
+            params.takerAssetFillAmount,
+            params.signature,
+        );
+        return data;
+    }
     public getBalanceThresholdAddress(): string {
         return this._balanceThresholdFilter.address;
     }
     public getExchangeAddress(): string {
         return this._exchange.address;
     }
-    // Exchange functions
-    //abiEncodeFillOrder
-    //getFillOrderResultsAsync
-    //
-    private async _executeTransaction(abiEncodedExchangeTxData: string, from: string, gas?: number): Promise<TransactionReceiptWithDecodedLogs> {
+    private async _executeTransactionAsync(
+        abiEncodedExchangeTxData: string,
+        from: string,
+        gas?: number,
+    ): Promise<TransactionReceiptWithDecodedLogs> {
         const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
-        const txOpts = _.isUndefined(gas) ? {from} : {from, gas};
+        const txOpts = _.isUndefined(gas) ? { from } : { from, gas };
         const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
             signedExchangeTx.salt,
             signedExchangeTx.signerAddress,
diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json
index 5d3ebfe74..a303e3f5c 100644
--- a/contracts/extensions/tsconfig.json
+++ b/contracts/extensions/tsconfig.json
@@ -6,6 +6,10 @@
         "resolveJsonModule": true
     },
     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
-    "files": ["./generated-artifacts/BalanceThresholdFilter.json", "./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
+    "files": [
+        "./generated-artifacts/BalanceThresholdFilter.json",
+        "./generated-artifacts/DutchAuction.json",
+        "./generated-artifacts/Forwarder.json"
+    ],
     "exclude": ["./deploy/solc/solc_bin"]
 }
-- 
cgit v1.2.3


From fc684ad063151f160a5bc584482aabb56df71e00 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:01:06 -0800
Subject: solhint fixes

---
 .../BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol    | 8 ++++++--
 .../BalanceThresholdFilter/interfaces/IThresholdAsset.sol         | 3 ++-
 .../BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol | 4 +++-
 3 files changed, 11 insertions(+), 4 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 0ad8ccddf..51dbae8f3 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -53,7 +53,7 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
         bytes signedExchangeTransaction,
         bytes signature
     ) 
-         external
+        external
     {
         // Validate addresses.
         validateBalanceThresholdsOrRevert();
@@ -216,6 +216,7 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
 
             // Step 2/2 Extract addresses to validate based on this selector.
             //          See ../../utils/ExchangeSelectors/ExchangeSelectors.sol for selectors
+            // solhint-disable no-empty-blocks
             switch exchangeFunctionSelector
             case 0x297bb70b00000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrders
             case 0x50dde19000000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrdersNoThrow
@@ -245,6 +246,7 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
                 // 64  -- strlen(INVALID_OR_BLOCKED_EXCHANGE_SELECTOR) rounded up to nearest 32-byte word.
                 revert(0, 132)
             }
+            // solhint-enable no-empty-blocks
 
             ///// Validate Recorded Addresses /////
 
@@ -262,7 +264,9 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
             // Validate addresses
             let thresholdAssetAddress := sload(THRESHOLD_ASSET_slot)
             let thresholdBalance := sload(THRESHOLD_BALANCE_slot)
+            // solhint-disable max-line-length 
             for {let addressToValidate := addressesToValidateElementPtr} lt(addressToValidate, addressesToValidateElementEndPtr) {addressToValidate := add(addressToValidate, 0x20)} {
+                // solhint-enable max-line-length 
                 // Construct calldata for `THRESHOLD_ASSET.balanceOf`
                 mstore(freeMemPtr, 0x70a0823100000000000000000000000000000000000000000000000000000000)
                 mstore(add(freeMemPtr, 0x04), mload(addressToValidate))
@@ -316,4 +320,4 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
         ///// If we hit this point then all addresses are valid /////
         emit ValidatedAddresses(validatedAddresses);
     }
-}
\ No newline at end of file
+}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
index 61acaba0a..3e424b9f4 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol
@@ -18,6 +18,7 @@
 
 pragma solidity 0.4.24;
 
+
 contract IThresholdAsset {
 
     /// @param _owner The address from which the balance will be retrieved
@@ -27,4 +28,4 @@ contract IThresholdAsset {
         view
         returns (uint256);
 
-}
\ No newline at end of file
+}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
index ff0042f58..af7a9453b 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
@@ -26,6 +26,7 @@ import "../interfaces/IThresholdAsset.sol";
 contract MBalanceThresholdFilterCore {
 
     // Points to 0x exchange contract
+    // solhint-disable var-name-mixedcase
     IExchange internal EXCHANGE;
 
     // The asset that must be held by makers/takers
@@ -33,6 +34,7 @@ contract MBalanceThresholdFilterCore {
 
     // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
     uint256 internal THRESHOLD_BALANCE;
+    // solhint-enable var-name-mixedcase
 
     // Addresses that hold at least `THRESHOLD_BALANCE` of `THRESHOLD_ASSET`
     event ValidatedAddresses (
@@ -78,4 +80,4 @@ contract MBalanceThresholdFilterCore {
     ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
     ///      of the addresses whose balance thresholds it checked.
     function validateBalanceThresholdsOrRevert() internal;
-}
\ No newline at end of file
+}
-- 
cgit v1.2.3


From dccca95c2c7a3bfcbf88db5f9182919f0e5ebf10 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:02:45 -0800
Subject: removed `only` from tests

---
 contracts/extensions/test/extensions/balance_threshold_filter.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index e4eda3354..72227090b 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -46,7 +46,7 @@ interface ValidatedAddressesLog {
     args: { addresses: string[] };
 }
 
-describe.only(ContractName.BalanceThresholdFilter, () => {
+describe(ContractName.BalanceThresholdFilter, () => {
     let compliantMakerAddress: string;
     let compliantMakerAddress2: string;
     let owner: string;
-- 
cgit v1.2.3


From d45c13bfa8a85e69bbf4476b22ad48443ae320e7 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:03:48 -0800
Subject: removed unnecessary log

---
 contracts/protocol/test/utils/exchange_wrapper.ts | 1 -
 1 file changed, 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/protocol/test/utils/exchange_wrapper.ts b/contracts/protocol/test/utils/exchange_wrapper.ts
index 6106e78ca..cb6dce901 100644
--- a/contracts/protocol/test/utils/exchange_wrapper.ts
+++ b/contracts/protocol/test/utils/exchange_wrapper.ts
@@ -214,7 +214,6 @@ export class ExchangeWrapper {
             { from },
         );
         const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
-        console.log(JSON.stringify(tx));
         return tx;
     }
     public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
-- 
cgit v1.2.3


From 34ff7fae9cffa7aaba5f0ba0060ed063a855f8e9 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:07:19 -0800
Subject: Removed deprecated README + comments

---
 contracts/extensions/test/extensions/balance_threshold_filter.ts | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index 72227090b..63cb9de31 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -135,7 +135,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
         // Create proxies
         const erc20Proxy = await erc20Wrapper.deployProxyAsync();
         await erc20Wrapper.setBalancesAndAllowancesAsync();
-        // Deploy Exchange congtract
+        // Deploy Exchange contract
         exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
             protocolArtifacts.Exchange,
             provider,
@@ -356,7 +356,6 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 ),
             );
         });
-        // @TODO - greater than 1 balance
     });
 
     describe('batchFillOrders', () => {
-- 
cgit v1.2.3


From a1266a3341cdc899a9090c90d6cf30b0ceb1db94 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:36:56 -0800
Subject: Cleaned up tests for balance threshold filter

---
 .../test/extensions/balance_threshold_filter.ts    | 1097 ++++++++++----------
 1 file changed, 534 insertions(+), 563 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index 63cb9de31..ced9d6e25 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -46,13 +46,17 @@ interface ValidatedAddressesLog {
     args: { addresses: string[] };
 }
 
-describe(ContractName.BalanceThresholdFilter, () => {
-    let compliantMakerAddress: string;
-    let compliantMakerAddress2: string;
+describe.only(ContractName.BalanceThresholdFilter, () => {
+    const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
+    const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
+    const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
+
+    let validMakerAddress: string;
+    let validMakerAddress2: string;
     let owner: string;
-    let compliantTakerAddress: string;
+    let validTakerAddress: string;
     let feeRecipientAddress: string;
-    let nonCompliantAddress: string;
+    let invalidAddress: string;
     let defaultMakerAssetAddress: string;
     let defaultTakerAssetAddress: string;
     let zrxAssetData: string;
@@ -62,27 +66,21 @@ describe(ContractName.BalanceThresholdFilter, () => {
 
     let orderFactory: OrderFactory;
     let orderFactory2: OrderFactory;
-    let nonCompliantOrderFactory: OrderFactory;
+    let invalidOrderFactory: OrderFactory;
     let erc20Wrapper: ERC20Wrapper;
     let erc20Balances: ERC20BalancesByOwner;
     let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
     let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper;
     let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper;
-    let erc721NonCompliantBalanceThresholdWrapper: BalanceThresholdWrapper;
-
-    let takerTransactionFactory: TransactionFactory;
-    let compliantSignedOrder: SignedOrder;
-    let compliantSignedOrder2: SignedOrder;
-    let compliantSignedFillOrderTx: SignedTransaction;
+    let erc721NonValidBalanceThresholdWrapper: BalanceThresholdWrapper;
 
     let defaultOrderParams: Partial<Order>;
+    let validSignedOrder: SignedOrder;
+    let validSignedOrder2: SignedOrder;
+    let validSignedFillOrderTx: SignedTransaction;
 
-    const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
-    const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
-    const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
-
-    let erc721CompliantForwarderInstance: BalanceThresholdFilterContract;
-    let erc20CompliantForwarderInstance: BalanceThresholdFilterContract;
+    let erc721BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
+    let erc20BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
 
     const assertValidatedAddressesLog = async (
         txReceipt: TransactionReceiptWithDecodedLogs,
@@ -107,19 +105,23 @@ describe(ContractName.BalanceThresholdFilter, () => {
         const accounts = await web3Wrapper.getAvailableAddressesAsync();
         const usedAddresses = ([
             owner,
-            compliantMakerAddress,
-            compliantMakerAddress2,
-            compliantTakerAddress,
+            validMakerAddress,
+            validMakerAddress2,
+            validTakerAddress,
             feeRecipientAddress,
-            nonCompliantAddress,
+            invalidAddress,
         ] = accounts);
+        const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validTakerAddress)];
+        const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress)];
+        const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress2)];
+        const invalidAddressPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(invalidAddress)];
         // Create wrappers
         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-        const compliantAddresses = _.cloneDeepWith(usedAddresses);
-        _.remove(compliantAddresses, (address: string) => {
-            return address === nonCompliantAddress;
+        const validAddresses = _.cloneDeepWith(usedAddresses);
+        _.remove(validAddresses, (address: string) => {
+            return address === invalidAddress;
         });
-        const erc721Wrapper = new ERC721Wrapper(provider, compliantAddresses, owner);
+        const erc721Wrapper = new ERC721Wrapper(provider, validAddresses, owner);
         // Deploy ERC20 tokens
         const numDummyErc20ToDeploy = 4;
         let erc20TokenA: DummyERC20TokenContract;
@@ -148,12 +150,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
         await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
             from: owner,
         });
-        // Deploy Compliant Forwarder
+        // Deploy Balance Threshold Filters
+        // One uses an ERC721 token as its balance threshold asset; the other uses an ERC20
         const erc721alanceThreshold = new BigNumber(1);
         await erc721Wrapper.deployProxyAsync();
         const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync();
         await erc721Wrapper.setBalancesAndAllowancesAsync();
-        erc721CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
+        erc721BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
             artifacts.BalanceThresholdFilter,
             provider,
             txDefaults,
@@ -162,7 +165,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
             erc721alanceThreshold,
         );
         const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10);
-        erc20CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
+        erc20BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync(
             artifacts.BalanceThresholdFilter,
             provider,
             txDefaults,
@@ -170,7 +173,6 @@ describe(ContractName.BalanceThresholdFilter, () => {
             erc20BalanceThresholdAsset.address,
             erc20BalanceThreshold,
         );
-
         // Default order parameters
         defaultOrderParams = {
             exchangeAddress: exchangeInstance.address,
@@ -181,68 +183,51 @@ describe(ContractName.BalanceThresholdFilter, () => {
             takerAssetAmount,
             makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT),
             takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT),
-            senderAddress: erc721CompliantForwarderInstance.address,
+            senderAddress: erc721BalanceThresholdFilterInstance.address,
         };
+        // Create two order factories with valid makers (who meet the threshold balance), and
+        // one factory for an invalid address (that does not meet the threshold balance)
+        // Valid order factory #1
         const defaultOrderParams1 = {
-            makerAddress: compliantMakerAddress,
+            makerAddress: validMakerAddress,
             ...defaultOrderParams,
         };
-        const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)];
-        takerTransactionFactory = new TransactionFactory(makerPrivateKey, exchangeInstance.address);
         orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1);
+        // Valid order factory #2
         const defaultOrderParams2 = {
-            makerAddress: compliantMakerAddress2,
+            makerAddress: validMakerAddress2,
             ...defaultOrderParams,
         };
-        const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress2)];
         orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2);
-
-        const nonCompliantPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(nonCompliantAddress)];
-        const defaultNonCompliantOrderParams = {
-            makerAddress: nonCompliantAddress,
+        // Invalid order factory
+        const defaultNonValidOrderParams = {
+            makerAddress: invalidAddress,
             ...defaultOrderParams,
         };
-        nonCompliantOrderFactory = new OrderFactory(nonCompliantPrivateKey, defaultNonCompliantOrderParams);
-        // Create Valid/Invalid orders
-        const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)];
-        takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address);
-        compliantSignedOrder = await orderFactory.newSignedOrderAsync({
-            senderAddress: erc721CompliantForwarderInstance.address,
-        });
-        const compliantSignedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
-            compliantSignedOrder,
-        );
-        const compliantSignedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
-            compliantSignedOrderWithoutExchangeAddress,
-            takerAssetFillAmount,
-            compliantSignedOrder.signature,
-        );
-        compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction(
-            compliantSignedOrderWithoutExchangeAddressData,
-        );
-
+        invalidOrderFactory = new OrderFactory(invalidAddressPrivateKey, defaultNonValidOrderParams);
+        // Create Balance Thresold Wrappers
         erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
-            erc20CompliantForwarderInstance,
+            erc20BalanceThresholdFilterInstance,
             exchangeInstance,
             new TransactionFactory(takerPrivateKey, exchangeInstance.address),
             provider,
         );
         erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
-            erc721CompliantForwarderInstance,
+            erc721BalanceThresholdFilterInstance,
             exchangeInstance,
             new TransactionFactory(takerPrivateKey, exchangeInstance.address),
             provider,
         );
         erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(
-            erc721CompliantForwarderInstance,
+            erc721BalanceThresholdFilterInstance,
             exchangeInstance,
             new TransactionFactory(makerPrivateKey, exchangeInstance.address),
             provider,
         );
-        erc721NonCompliantBalanceThresholdWrapper = new BalanceThresholdWrapper(
-            erc721CompliantForwarderInstance,
+        erc721NonValidBalanceThresholdWrapper = new BalanceThresholdWrapper(
+            erc721BalanceThresholdFilterInstance,
             exchangeInstance,
-            new TransactionFactory(nonCompliantPrivateKey, exchangeInstance.address),
+            new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address),
             provider,
         );
     });
@@ -256,104 +241,90 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('General Sanity Checks', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => {
-            const compliantSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({
+            const validSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({
                 ...defaultOrderParams,
-                makerAddress: compliantMakerAddress,
+                makerAddress: validMakerAddress,
                 senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(),
             });
             // Execute a valid fill
             const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(
-                compliantSignedOrderERC20Sender,
-                compliantTakerAddress,
+                validSignedOrderERC20Sender,
+                validTakerAddress,
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
             );
         });
-        it('should revert if the signed transaction is not intended for supported', async () => {
+        it('should revert if the Exchange transaction function is not supported', async () => {
             // Create signed order without the fillOrder function selector
-            const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data);
-            const selectorLengthInBytes = 4;
-            const txDataBufMinusSelector = txDataBuf.slice(selectorLengthInBytes);
-            const badSelector = '0x00000000';
-            const badSelectorBuf = ethUtil.toBuffer(badSelector);
-            const txDataBufWithBadSelector = Buffer.concat([badSelectorBuf, txDataBufMinusSelector]);
-            const txDataBufWithBadSelectorHex = ethUtil.bufferToHex(txDataBufWithBadSelector);
-            // Call compliant forwarder
-            return expectTransactionFailedWithoutReasonAsync(
-                erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
-                    compliantSignedFillOrderTx.salt,
-                    compliantSignedFillOrderTx.signerAddress,
-                    txDataBufWithBadSelectorHex,
-                    compliantSignedFillOrderTx.signature,
+            const salt = new BigNumber(0);
+            const badSelectorHex = '0x00000000';
+            const signatureHex = '0x';
+            // Call valid forwarder
+            return expectTransactionFailedAsync(
+                erc721BalanceThresholdFilterInstance.executeTransaction.sendTransactionAsync(
+                    salt,
+                    validTakerAddress,
+                    badSelectorHex,
+                    signatureHex,
                 ),
+                RevertReason.InvalidOrBlockedExchangeSelector
             );
         });
-        it('should revert if senderAddress is not set to the compliant forwarding contract', async () => {
+        it('should revert if senderAddress is not set to the valid forwarding contract', async () => {
             // Create signed order with incorrect senderAddress
             const notBalanceThresholdFilterAddress = zrxToken.address;
             const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({
                 senderAddress: notBalanceThresholdFilterAddress,
             });
-            const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(
-                signedOrderWithBadSenderAddress,
-            );
-            const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData(
-                signedOrderWithoutExchangeAddress,
-                takerAssetFillAmount,
-                compliantSignedOrder.signature,
-            );
-            const signedFillOrderTx = takerTransactionFactory.newSignedTransaction(
-                signedOrderWithoutExchangeAddressData,
-            );
-            // Call compliant forwarder
-            return expectTransactionFailedWithoutReasonAsync(
-                erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync(
-                    signedFillOrderTx.salt,
-                    signedFillOrderTx.signerAddress,
-                    signedFillOrderTx.data,
-                    signedFillOrderTx.signature,
+            // Call valid forwarder
+            return expectTransactionFailedAsync(
+                erc721TakerBalanceThresholdWrapper.fillOrderAsync(
+                    signedOrderWithBadSenderAddress,
+                    validTakerAddress,
+                    { takerAssetFillAmount },
                 ),
+                RevertReason.FailedExecution
             );
         });
     });
@@ -361,68 +332,68 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('batchFillOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { takerAssetFillAmounts },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
                 .times(2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
 
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
@@ -430,25 +401,25 @@ describe(ContractName.BalanceThresholdFilter, () => {
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.batchFillOrdersAsync(orders, invalidAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -459,68 +430,68 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('batchFillOrdersNoThrow', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { takerAssetFillAmounts },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
                 .times(2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
 
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
@@ -528,25 +499,25 @@ describe(ContractName.BalanceThresholdFilter, () => {
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, validTakerAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, invalidAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -557,68 +528,68 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('batchFillOrKillOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { takerAssetFillAmounts },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2);
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount)
                 .times(2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
 
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
@@ -626,36 +597,36 @@ describe(ContractName.BalanceThresholdFilter, () => {
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, invalidAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if one takerAssetFillAmount is not fully filled', async () => {
-            const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2);
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2);
+            const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount];
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, {
                     takerAssetFillAmounts,
                 }),
                 RevertReason.FailedExecution,
@@ -666,65 +637,65 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('fillOrder', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
             const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(
-                compliantSignedOrder,
-                compliantTakerAddress,
+                validSignedOrder,
+                validTakerAddress,
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
             );
         });
         it('should revert if maker does not meet the balance threshold', async () => {
-            // Create signed order with non-compliant maker address
+            // Create signed order with non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress,
+                senderAddress: erc721BalanceThresholdFilterInstance.address,
+                makerAddress: invalidAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrderAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress,
+                    validTakerAddress,
                     { takerAssetFillAmount },
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -732,7 +703,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.fillOrderAsync(validSignedOrder, invalidAddress, {
                     takerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -743,65 +714,65 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('fillOrderNoThrow', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
             const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
-                compliantSignedOrder,
-                compliantTakerAddress,
+                validSignedOrder,
+                validTakerAddress,
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
             );
         });
         it('should revert if maker does not meet the balance threshold', async () => {
-            // Create signed order with non-compliant maker address
+            // Create signed order with non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress,
+                senderAddress: erc721BalanceThresholdFilterInstance.address,
+                makerAddress: invalidAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress,
+                    validTakerAddress,
                     { takerAssetFillAmount },
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -809,9 +780,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.fillOrderNoThrowAsync(
-                    compliantSignedOrder,
-                    nonCompliantAddress,
+                erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(
+                    validSignedOrder,
+                    invalidAddress,
                     { takerAssetFillAmount },
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -822,66 +793,66 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('fillOrKillOrder', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const takerAssetFillAmount_ = compliantSignedOrder.takerAssetAmount;
+            const takerAssetFillAmount_ = validSignedOrder.takerAssetAmount;
             const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
-                compliantSignedOrder,
-                compliantTakerAddress,
+                validSignedOrder,
+                validTakerAddress,
                 { takerAssetFillAmount: takerAssetFillAmount_ },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount = takerAssetFillAmount_
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid = compliantSignedOrder.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid = validSignedOrder.makerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee
                 .times(makerAssetFillAmount)
-                .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount);
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
+                .dividedToIntegerBy(validSignedOrder.makerAssetAmount);
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount_),
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount_),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid),
             );
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
             );
         });
         it('should revert if maker does not meet the balance threshold', async () => {
-            // Create signed order with non-compliant maker address
+            // Create signed order with non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress,
+                senderAddress: erc721BalanceThresholdFilterInstance.address,
+                makerAddress: invalidAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress,
+                    validTakerAddress,
                     { takerAssetFillAmount },
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -889,18 +860,18 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.fillOrKillOrderAsync(
-                    compliantSignedOrder,
-                    nonCompliantAddress,
+                erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(
+                    validSignedOrder,
+                    invalidAddress,
                     { takerAssetFillAmount },
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if takerAssetFillAmount is not fully filled', async () => {
-            const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2);
+            const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(compliantSignedOrder, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, validTakerAddress, {
                     takerAssetFillAmount: tooBigTakerAssetFillAmount,
                 }),
                 RevertReason.FailedExecution,
@@ -911,98 +882,98 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('marketSellOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
-            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const orders = [validSignedOrder, validSignedOrder2];
+            const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount2 = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid2 = validSignedOrder2.makerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = validSignedOrder2.takerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
-            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
+            const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
-                    compliantSignedOrder.makerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
+                    validSignedOrder.makerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
-                    compliantSignedOrder.takerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
+                    validSignedOrder.takerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address]
-                    .add(compliantSignedOrder.makerFee)
+                    .add(validSignedOrder.makerFee)
                     .add(makerFeePaid2)
                     .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, validTakerAddress, {
                     takerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.marketSellOrdersAsync(orders, invalidAddress, {
                     takerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -1013,98 +984,98 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('marketSellOrdersNoThrow', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
-            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const orders = [validSignedOrder, validSignedOrder2];
+            const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
             const makerAssetFillAmount2 = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const makerFeePaid2 = compliantSignedOrder2.makerFee
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const makerFeePaid2 = validSignedOrder2.makerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = validSignedOrder2.takerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
-            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
+            const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
-                    compliantSignedOrder.makerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
+                    validSignedOrder.makerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
-                    compliantSignedOrder.takerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
+                    validSignedOrder.takerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address]
-                    .add(compliantSignedOrder.makerFee)
+                    .add(validSignedOrder.makerFee)
                     .add(makerFeePaid2)
                     .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, validTakerAddress, {
                     takerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, invalidAddress, {
                     takerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -1115,100 +1086,100 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('marketBuyOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
-            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const orders = [validSignedOrder, validSignedOrder2];
+            const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const makerAssetFillAmount2 = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
-            const makerFeePaid2 = compliantSignedOrder2.makerFee
+            const makerFeePaid2 = validSignedOrder2.makerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = validSignedOrder2.takerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
-                    compliantSignedOrder.makerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
+                    validSignedOrder.makerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
-                    compliantSignedOrder.takerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
+                    validSignedOrder.takerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address]
-                    .add(compliantSignedOrder.makerFee)
+                    .add(validSignedOrder.makerFee)
                     .add(makerFeePaid2)
                     .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, {
                     makerAssetFillAmount: dummyMakerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.marketBuyOrdersAsync(orders, invalidAddress, {
                     makerAssetFillAmount: dummyMakerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -1219,100 +1190,100 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('marketBuyOrdersNoThrowAsync', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => {
             // Execute a valid fill
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
-            const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
+            const orders = [validSignedOrder, validSignedOrder2];
+            const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount);
             const makerAssetFillAmount2 = takerAssetFillAmount
-                .times(compliantSignedOrder.makerAssetAmount)
-                .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount);
-            const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
+                .times(validSignedOrder.makerAssetAmount)
+                .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
+            const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
                 orders,
-                compliantTakerAddress,
+                validTakerAddress,
                 { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
-                compliantSignedOrder.makerAddress,
-                compliantSignedOrder2.makerAddress,
-                compliantSignedFillOrderTx.signerAddress,
+                validSignedOrder.makerAddress,
+                validSignedOrder2.makerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
-            const makerFeePaid2 = compliantSignedOrder2.makerFee
+            const makerFeePaid2 = validSignedOrder2.makerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid2 = compliantSignedOrder2.takerFee
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid2 = validSignedOrder2.takerFee
                 .times(makerAssetFillAmount2)
-                .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount);
-            const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2);
+                .dividedToIntegerBy(validSignedOrder2.makerAssetAmount);
+            const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
-            expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(
-                    compliantSignedOrder.makerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
+                    validSignedOrder.makerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(
-                    compliantSignedOrder.takerAssetAmount,
+            expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
+                    validSignedOrder.takerAssetAmount,
                 ),
             );
-            expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee),
+            expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
             );
             // Maker #2
-            expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
+            expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2),
             );
-            expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
+            expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount),
             );
-            expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2),
+            expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2),
             );
             // Taker
-            expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
+            expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount),
             );
-            expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid),
+            expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal(
+                erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid),
             );
             // Fee recipient
             expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[feeRecipientAddress][zrxToken.address]
-                    .add(compliantSignedOrder.makerFee)
+                    .add(validSignedOrder.makerFee)
                     .add(makerFeePaid2)
                     .add(takerFeePaid),
             );
         });
         it('should revert if one maker does not meet the balance threshold', async () => {
-            // Create order set with one non-compliant maker address
+            // Create order set with one non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                makerAddress: nonCompliantAddress,
+                makerAddress: invalidAddress,
             });
-            const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress];
+            const orders = [validSignedOrder, signedOrderWithBadMakerAddress];
             // Execute transaction
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, compliantTakerAddress, {
+                erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, validTakerAddress, {
                     makerAssetFillAmount: dummyMakerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
-            const orders = [compliantSignedOrder, compliantSignedOrder2];
+            const orders = [validSignedOrder, validSignedOrder2];
             const dummyMakerAssetFillAmount = new BigNumber(0);
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, nonCompliantAddress, {
+                erc721NonValidBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, invalidAddress, {
                     makerAssetFillAmount: dummyMakerAssetFillAmount,
                 }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
@@ -1323,8 +1294,8 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('matchOrders', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => {
             // Test values/results taken from Match Orders test:
@@ -1364,13 +1335,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
                 signedOrderLeft,
                 signedOrderRight,
-                compliantTakerAddress,
+                validTakerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
                 signedOrderLeft.makerAddress,
                 signedOrderRight.makerAddress,
-                compliantTakerAddress,
+                validTakerAddress,
             ];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
@@ -1392,10 +1363,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 ),
             );
             expect(
-                newBalances[compliantTakerAddress][defaultMakerAssetAddress],
+                newBalances[validTakerAddress][defaultMakerAssetAddress],
                 'Checking taker ingress ERC20 account balance',
             ).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(
+                erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(
                     expectedTransferAmounts.amountReceivedByTaker,
                 ),
             );
@@ -1433,10 +1404,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 ),
             );
             expect(
-                newBalances[compliantTakerAddress][zrxToken.address],
+                newBalances[validTakerAddress][zrxToken.address],
                 'Checking taker egress ERC20 account fees',
             ).to.be.bignumber.equal(
-                erc20Balances[compliantTakerAddress][zrxToken.address]
+                erc20Balances[validTakerAddress][zrxToken.address]
                     .minus(expectedTransferAmounts.feePaidByTakerLeft)
                     .sub(expectedTransferAmounts.feePaidByTakerRight),
             );
@@ -1453,43 +1424,43 @@ describe(ContractName.BalanceThresholdFilter, () => {
             );
         });
         it('should revert if left maker does not meet the balance threshold', async () => {
-            // Create signed order with non-compliant maker address
+            // Create signed order with non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress,
+                senderAddress: erc721BalanceThresholdFilterInstance.address,
+                makerAddress: invalidAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
-                    compliantSignedOrder,
+                    validSignedOrder,
                     signedOrderWithBadMakerAddress,
-                    compliantTakerAddress,
+                    validTakerAddress,
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if right maker does not meet the balance threshold', async () => {
-            // Create signed order with non-compliant maker address
+            // Create signed order with non-valid maker address
             const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({
-                senderAddress: erc721CompliantForwarderInstance.address,
-                makerAddress: nonCompliantAddress,
+                senderAddress: erc721BalanceThresholdFilterInstance.address,
+                makerAddress: invalidAddress,
             });
             // Execute transaction
             return expectTransactionFailedAsync(
                 erc721TakerBalanceThresholdWrapper.matchOrdersAsync(
                     signedOrderWithBadMakerAddress,
-                    compliantSignedOrder,
-                    compliantTakerAddress,
+                    validSignedOrder,
+                    validTakerAddress,
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonCompliantBalanceThresholdWrapper.matchOrdersAsync(
-                    compliantSignedOrder,
-                    compliantSignedOrder,
-                    nonCompliantAddress,
+                erc721NonValidBalanceThresholdWrapper.matchOrdersAsync(
+                    validSignedOrder,
+                    validSignedOrder,
+                    invalidAddress,
                 ),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
@@ -1499,39 +1470,39 @@ describe(ContractName.BalanceThresholdFilter, () => {
     describe('cancelOrder', () => {
         beforeEach(async () => {
             erc20Balances = await erc20Wrapper.getBalancesAsync();
-            compliantSignedOrder = await orderFactory.newSignedOrderAsync();
-            compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync();
+            validSignedOrder = await orderFactory.newSignedOrderAsync();
+            validSignedOrder2 = await orderFactory2.newSignedOrderAsync();
         });
         it('Should successfully cancel order if maker meets balance threshold', async () => {
             // Verify order is not cancelled
             const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
-                compliantSignedOrder,
+                validSignedOrder,
             );
             expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             // Cancel
             const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(
-                compliantSignedOrder,
-                compliantSignedOrder.makerAddress,
+                validSignedOrder,
+                validSignedOrder.makerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
             const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
-                compliantSignedOrder,
+                validSignedOrder,
             );
             expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
         });
         it('Should successfully cancel order if maker does not meet balance threshold', async () => {
             // Create order where maker does not meet balance threshold
-            const signedOrderWithBadMakerAddress = await nonCompliantOrderFactory.newSignedOrderAsync({});
+            const signedOrderWithBadMakerAddress = await invalidOrderFactory.newSignedOrderAsync({});
             // Verify order is not cancelled
-            const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+            const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
                 signedOrderWithBadMakerAddress,
             );
             expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             // Cancel
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrderAsync(
+            const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrderAsync(
                 signedOrderWithBadMakerAddress,
                 signedOrderWithBadMakerAddress.makerAddress,
             );
@@ -1552,13 +1523,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
             // Create orders to cancel
-            const compliantSignedOrders = [
+            const validSignedOrders = [
                 await orderFactory.newSignedOrderAsync(),
                 await orderFactory.newSignedOrderAsync(),
                 await orderFactory.newSignedOrderAsync(),
             ];
             // Verify orders are not cancelled
-            _.each(compliantSignedOrders, async signedOrder => {
+            _.each(validSignedOrders, async signedOrder => {
                 const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
@@ -1566,14 +1537,14 @@ describe(ContractName.BalanceThresholdFilter, () => {
             });
             // Cancel
             const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(
-                compliantSignedOrders,
-                compliantSignedOrder.makerAddress,
+                validSignedOrders,
+                validSignedOrder.makerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            _.each(compliantSignedOrders, async signedOrder => {
+            _.each(validSignedOrders, async signedOrder => {
                 const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
@@ -1582,29 +1553,29 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
             // Create orders to cancel
-            const nonCompliantSignedOrders = [
-                await nonCompliantOrderFactory.newSignedOrderAsync(),
-                await nonCompliantOrderFactory.newSignedOrderAsync(),
-                await nonCompliantOrderFactory.newSignedOrderAsync(),
+            const invalidSignedOrders = [
+                await invalidOrderFactory.newSignedOrderAsync(),
+                await invalidOrderFactory.newSignedOrderAsync(),
+                await invalidOrderFactory.newSignedOrderAsync(),
             ];
             // Verify orders are not cancelled
-            _.each(nonCompliantSignedOrders, async signedOrder => {
-                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+            _.each(invalidSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.batchCancelOrdersAsync(
-                nonCompliantSignedOrders,
-                nonCompliantAddress,
+            const txReceipt = await erc721NonValidBalanceThresholdWrapper.batchCancelOrdersAsync(
+                invalidSignedOrders,
+                invalidAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            _.each(nonCompliantSignedOrders, async signedOrder => {
-                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+            _.each(invalidSignedOrders, async signedOrder => {
+                const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
                 return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED);
@@ -1618,13 +1589,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('Should successfully batch cancel orders if maker meets balance threshold', async () => {
             // Create orders to cancel
-            const compliantSignedOrders = [
+            const validSignedOrders = [
                 await orderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
                 await orderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
                 await orderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
             ];
             // Verify orders are not cancelled
-            _.each(compliantSignedOrders, async signedOrder => {
+            _.each(validSignedOrders, async signedOrder => {
                 const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
@@ -1634,13 +1605,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const cancelOrdersUpToThisSalt = new BigNumber(1);
             const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(
                 cancelOrdersUpToThisSalt,
-                compliantSignedOrder.makerAddress,
+                validSignedOrder.makerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            _.each(compliantSignedOrders, async (signedOrder, salt: number) => {
+            _.each(validSignedOrders, async (signedOrder, salt: number) => {
                 const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
@@ -1654,30 +1625,30 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('Should successfully batch cancel order if maker does not meet balance threshold', async () => {
             // Create orders to cancel
-            const nonCompliantSignedOrders = [
-                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
-                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
-                await nonCompliantOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
+            const invalidSignedOrders = [
+                await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }),
+                await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }),
+                await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }),
             ];
             // Verify orders are not cancelled
-            _.each(nonCompliantSignedOrders, async signedOrder => {
-                const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+            _.each(invalidSignedOrders, async signedOrder => {
+                const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
                 return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE);
             });
             // Cancel
             const cancelOrdersUpToThisSalt = new BigNumber(1);
-            const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrdersUpToAsync(
+            const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrdersUpToAsync(
                 cancelOrdersUpToThisSalt,
-                nonCompliantAddress,
+                invalidAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check that order was cancelled
-            _.each(nonCompliantSignedOrders, async (signedOrder, salt: number) => {
-                const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(
+            _.each(invalidSignedOrders, async (signedOrder, salt: number) => {
+                const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync(
                     signedOrder,
                 );
                 const saltAsBigNumber = new BigNumber(salt);
-- 
cgit v1.2.3


From 22fd23643cb26ba1b79e9b13e5ef41c97ab7fe6a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 11 Dec 2018 16:37:07 -0800
Subject: Run all tests for extensions

---
 contracts/extensions/test/extensions/balance_threshold_filter.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index ced9d6e25..6350c019f 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -46,7 +46,7 @@ interface ValidatedAddressesLog {
     args: { addresses: string[] };
 }
 
-describe.only(ContractName.BalanceThresholdFilter, () => {
+describe(ContractName.BalanceThresholdFilter, () => {
     const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT);
     const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT);
     const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT);
-- 
cgit v1.2.3


From f91781a0605f46ee1a40bf979d22ff510f48d464 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 13:52:20 -0800
Subject: Less Assembly. More Solidity. Less Efficiency. More Readability.

---
 .../BalanceThresholdFilter.sol                     |  10 +-
 .../MixinBalanceThresholdFilterCore.sol            | 404 ++++++++-------------
 .../mixins/MBalanceThresholdFilterCore.sol         |   7 +-
 .../utils/ExchangeSelectors/ExchangeSelectors.sol  | 151 ++++++++
 4 files changed, 306 insertions(+), 266 deletions(-)
 create mode 100644 contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
index a68f6805d..ea248793f 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
@@ -24,21 +24,23 @@ import "./interfaces/IThresholdAsset.sol";
 import "./MixinBalanceThresholdFilterCore.sol";
 
 
-contract BalanceThresholdFilter is MixinBalanceThresholdFilterCore {
+contract BalanceThresholdFilter is
+    MixinBalanceThresholdFilterCore
+{
 
     /// @dev Constructs BalanceThresholdFilter.
     /// @param exchange Address of 0x exchange.
     /// @param thresholdAsset The asset that must be held by makers/takers.
-    /// @param thresholdBalance The minimum balance of `thresholdAsset` that must be held by makers/takers.
+    /// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
     constructor(
         address exchange,
         address thresholdAsset,
-        uint256 thresholdBalance
+        uint256 balanceThreshold
     )
         public
     {
         EXCHANGE = IExchange(exchange);
         THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
-        THRESHOLD_BALANCE = thresholdBalance;
+        BALANCE_THRESHOLD = balanceThreshold;
     }
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 51dbae8f3..e78f9ced8 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -6,7 +6,7 @@
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
 
-    http://www.apache.org/licenses/LICENSE-2.0
+    http://www.apache.org/licenses/LICENSE2.0
 
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,31 +17,36 @@
 */
 
 pragma solidity 0.4.24;
-pragma experimental ABIEncoderV2;
 
 import "./mixins/MBalanceThresholdFilterCore.sol";
+import "@0x/contracts-utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol";
+import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
 
 
-contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
+contract MixinBalanceThresholdFilterCore is
+    MBalanceThresholdFilterCore,
+    LibOrder,
+    ExchangeSelectors
+{
 
     /// @dev Executes an Exchange transaction iff the maker and taker meet 
     ///      the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR 
     ///      the exchange function is a cancellation.
     ///      Supported Exchange functions:
-    ///         - batchFillOrders
-    ///         - batchFillOrdersNoThrow
-    ///         - batchFillOrKillOrders
-    ///         - fillOrder
-    ///         - fillOrderNoThrow
-    ///         - fillOrKillOrder
-    ///         - marketBuyOrders
-    ///         - marketBuyOrdersNoThrow
-    ///         - marketSellOrders
-    ///         - marketSellOrdersNoThrow
-    ///         - matchOrders
-    ///         - cancelOrder
-    ///         - batchCancelOrders
-    ///         - cancelOrdersUpTo
+    ///          batchFillOrders
+    ///          batchFillOrdersNoThrow
+    ///          batchFillOrKillOrders
+    ///          fillOrder
+    ///          fillOrderNoThrow
+    ///          fillOrKillOrder
+    ///          marketBuyOrders
+    ///          marketBuyOrdersNoThrow
+    ///          marketSellOrders
+    ///          marketSellOrdersNoThrow
+    ///          matchOrders
+    ///          cancelOrder
+    ///          batchCancelOrders
+    ///          cancelOrdersUpTo
     ///     Trying to call any other exchange function will throw.
     /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
     /// @param signerAddress Address of transaction signer.
@@ -56,7 +61,7 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
         external
     {
         // Validate addresses.
-        validateBalanceThresholdsOrRevert();
+        validateBalanceThresholdsOrRevert(signerAddress);
         
         // All addresses are valid. Execute fillOrder.
         EXCHANGE.executeTransaction(
@@ -67,6 +72,83 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
         );
     }
 
+    /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
+    ///      which is accessed through `signedExchangeTransaction`.
+    /// @param offset  Offset into the Exchange calldata.
+    /// @return value  Corresponding 32 byte value stored at `offset`.
+    function exchangeCalldataload(uint256 offset)
+        internal
+        returns (bytes32 value)
+    {
+        assembly {
+            // Pointer to exchange transaction
+            // 0x04 for calldata selector
+            // 0x40 to access `signedExchangeTransaction`, which is the third parameter
+            let exchangeTxPtr := calldataload(0x44)
+
+            // Offset into Exchange calldata
+            // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
+            // 0x04 for calldata selector
+            // 0x20 for length field of `signedExchangeTransaction`
+            let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
+            value := calldataload(exchangeCalldataOffset)
+        }
+    }
+
+    /// @dev Convenience function that skips the 4 byte selector when loading
+    ///      from the embedded Exchange calldata.
+    /// @param offset  Offset into the Exchange calldata (minus the 4 byte selector)
+    /// @return value  Corresponding 32 byte value stored at `offset` + 4.
+    function loadExchangeData(uint256 offset)
+        internal
+        returns (bytes32 value)
+    {
+        value = exchangeCalldataload(offset + 4);
+    }
+
+    /// @dev A running list is maintained of addresses to validate. 
+    ///     This function records an address in this array.
+    /// @param addressToValidate  Address to record for validation.
+    function recordAddressToValidate(address addressToValidate, address[] memory addressList) 
+        internal
+    {
+        uint256 newAddressListLength = addressList.length + 1;
+        assembly {
+            // Store new array length
+            mstore(addressList, newAddressListLength)
+            mstore(0x40, add(addressList, add(0x20, mul(0x20, newAddressListLength))))
+        }
+        addressList[newAddressListLength - 1] = addressToValidate;
+    }
+
+    /// @dev Extracts the maker address from an order stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`), and records it in
+    ///      the running list of addresses to validate.
+    /// @param orderParamIndex  Index of the order in the Exchange function's signature
+    function loadMakerAddressFromOrder(uint8 orderParamIndex) internal returns (address makerAddress) {
+        uint256 orderPtr = uint256(loadExchangeData(orderParamIndex * 0x20));
+        makerAddress = address(loadExchangeData(orderPtr));
+    }
+
+    /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`), and records them in
+    ///      the running list of addresses to validate.
+    /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
+    function loadMakerAddressesFromOrderArray(uint8 orderArrayParamIndex)
+        internal
+        returns (address[] makerAddresses)
+    {
+        uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayParamIndex * 0x20));
+        uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
+        uint256 orderArrayElementPtr = orderArrayPtr + 0x20;
+        uint256 orderArrayElementEndPtr = orderArrayElementPtr + (orderArrayLength * 0x20);
+        for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 0x20) {
+            uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
+            address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
+            recordAddressToValidate(makerAddress, makerAddresses);
+        }
+    }
+
     /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
     ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
     ///      then this function will revert. Which addresses are validated depends on
@@ -74,250 +156,56 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
     ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
     ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
     ///      of the addresses whose balance thresholds it checked.
-    function validateBalanceThresholdsOrRevert()
+    function validateBalanceThresholdsOrRevert(address signerAddress)
         internal
     {
-        // Addresses that are validated below.
-        address[] memory validatedAddresses;
-
-        ///// Do not add variables after this point.         /////
-        ///// The assembly block may overwrite their values. /////
-
-        // Validate addresses
-        assembly {
-             /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
-             ///      which is accessed through `signedExchangeTransaction`.
-             /// @param offset - Offset into the Exchange calldata.
-             /// @return value - Corresponding 32 byte value stored at `offset`.
-            function exchangeCalldataload(offset) -> value {
-                // Pointer to exchange transaction
-                // 0x04 for calldata selector
-                // 0x40 to access `signedExchangeTransaction`, which is the third parameter
-                let exchangeTxPtr := calldataload(0x44)
-
-                // Offset into Exchange calldata
-                // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
-                // 0x04 for calldata selector
-                // 0x20 for length field of `signedExchangeTransaction`
-                let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
-                value := calldataload(exchangeCalldataOffset)
-            }
-
-            /// @dev Convenience function that skips the 4 byte selector when loading
-            ///      from the embedded Exchange calldata.
-            /// @param offset - Offset into the Exchange calldata (minus the 4 byte selector)
-            /// @return value - Corresponding 32 byte value stored at `offset` + 4.
-            function loadExchangeData(offset) -> value {
-                value := exchangeCalldataload(add(offset, 0x4))
-            }
-
-             /// @dev A running list is maintained of addresses to validate. 
-             ///     This function records an address in this array.
-             /// @param addressToValidate - Address to record for validation.
-            function recordAddressToValidate(addressToValidate) {
-                // Compute `addressesToValidate` memory offset
-                let addressesToValidate_ := mload(0x40)
-                let nAddressesToValidate_ := mload(addressesToValidate_)
-
-                // Increment length
-                nAddressesToValidate_ := add(mload(addressesToValidate_), 0x01)
-                mstore(addressesToValidate_, nAddressesToValidate_)
-
-                // Append address to validate
-                let offset := mul(nAddressesToValidate_, 0x20)
-                mstore(add(addressesToValidate_, offset), addressToValidate)
-            }
-
-             /// @dev Extracts the maker address from an order stored in the Exchange calldata
-             ///      (which is embedded in `signedExchangeTransaction`), and records it in
-             ///      the running list of addresses to validate.
-             /// @param orderParamIndex - Index of the order in the Exchange function's signature
-            function recordMakerAddressFromOrder(orderParamIndex) {
-                let orderPtr := loadExchangeData(mul(orderParamIndex, 0x20))
-                let makerAddress := loadExchangeData(orderPtr)
-                recordAddressToValidate(makerAddress)
-            }
-
-            /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
-            ///      (which is embedded in `signedExchangeTransaction`), and records them in
-            ///      the running list of addresses to validate.
-            /// @param orderArrayParamIndex - Index of the order array in the Exchange function's signature
-            function recordMakerAddressesFromOrderArray(orderArrayParamIndex) {
-                let orderArrayPtr := loadExchangeData(mul(orderArrayParamIndex, 0x20))
-                let orderArrayLength := loadExchangeData(orderArrayPtr)
-                let orderArrayElementPtr := add(orderArrayPtr, 0x20)
-                let orderArrayElementEndPtr := add(orderArrayElementPtr, mul(orderArrayLength, 0x20))
-                for {let orderPtrOffset := orderArrayElementPtr} lt(orderPtrOffset, orderArrayElementEndPtr) {orderPtrOffset := add(orderPtrOffset, 0x20)} {
-                    let orderPtr := loadExchangeData(orderPtrOffset)
-                    let makerAddress := loadExchangeData(add(orderPtr, orderArrayElementPtr))
-                    recordAddressToValidate(makerAddress)
-                }
-            }
-
-            /// @dev Records address of signer in the running list of addresses to validate.
-            /// @note: We cannot access `signerAddress` directly from within the asm function,
-            ///        so it is loaded from the calldata.
-            function recordSignerAddress() {
-                // Load the signer address from calldata
-                // 0x04 for selector
-                // 0x20 to access `signerAddress`, which is the second parameter.
-                let signerAddress_ := calldataload(0x24)
-                recordAddressToValidate(signerAddress_)
-            }
-
-            /// @dev Records addresses to be validated when Exchange transaction is a batch fill variant.
-            ///      This is one of: batchFillOrders, batchFillOrKillOrders, batchFillNoThrow
-            ///      Reference signature<T>: <batchFillVariant>(Order[],uint256[],bytes[])
-            function recordAddressesForBatchFillVariant() {
-                // Record maker addresses from order array (parameter index 0)
-                // The signer is the taker for these orders and must also be validated.
-                recordMakerAddressesFromOrderArray(0)
-                recordSignerAddress()
-            }
-
-            /// @dev Records addresses to be validated when Exchange transaction is a fill order variant.
-            ///      This is one of: fillOrder, fillOrKillOrder, fillOrderNoThrow
-            ///      Reference signature<T>: <fillOrderVariant>(Order,uint256,bytes)
-            function recordAddressesForFillOrderVariant() {
-                // Record maker address from the order (param index 0)
-                // The signer is the taker for this order and must also be validated.
-                recordMakerAddressFromOrder(0)
-                recordSignerAddress()
-            }
-
-            /// @dev Records addresses to be validated when Exchange transaction is a market fill variant.
-            ///      This is one of: marketBuyOrders, marketBuyOrdersNoThrow, marketSellOrders, marketSellOrdersNoThrow
-            ///      Reference signature<T>: <marketFillInvariant>(Order[],uint256,bytes[])
-            function recordAddressesForMarketFillVariant() {
-                // Record maker addresses from order array (parameter index 0)
-                // The signer is the taker for these orders and must also be validated.
-                recordMakerAddressesFromOrderArray(0)
-                recordSignerAddress()
-            }
-
-            /// @dev Records addresses to be validated when Exchange transaction is matchOrders.
-            ///      Reference signature: matchOrders(Order,Order)
-            function recordAddressesForMatchOrders() {
-                // Record maker address from both orders (param indices 0 & 1).
-                // The signer is the taker and must also be validated.
-                recordMakerAddressFromOrder(0)
-                recordMakerAddressFromOrder(1)
-                recordSignerAddress()
-            }
-
-            ///// Record Addresses to Validate /////
-
-            // Addresses needing validation depends on which Exchange function is being called.
-            // Step 1/2 Read the exchange function selector.
-            let exchangeFunctionSelector := and(
-                exchangeCalldataload(0x0),
-                0xffffffff00000000000000000000000000000000000000000000000000000000
-            )
-
-            // Step 2/2 Extract addresses to validate based on this selector.
-            //          See ../../utils/ExchangeSelectors/ExchangeSelectors.sol for selectors
-            // solhint-disable no-empty-blocks
-            switch exchangeFunctionSelector
-            case 0x297bb70b00000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrders
-            case 0x50dde19000000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrdersNoThrow
-            case 0x4d0ae54600000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() }    // batchFillOrKillOrders
-            case 0xb4be83d500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrder
-            case 0x3e228bae00000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrderNoThrow
-            case 0x64a3bc1500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() }    // fillOrKillOrder
-            case 0xe5fa431b00000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketBuyOrders
-            case 0xa3e2038000000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketBuyOrdersNoThrow
-            case 0x7e1d980800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketSellOrders
-            case 0xdd1c7d1800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() }   // marketSellOrdersNoThrow
-            case 0x3c28d86100000000000000000000000000000000000000000000000000000000 { recordAddressesForMatchOrders() }         // matchOrders
-            case 0xd46b02c300000000000000000000000000000000000000000000000000000000 {}                                          // cancelOrder
-            case 0x4ac1478200000000000000000000000000000000000000000000000000000000 {}                                          // batchCancelOrders
-            case 0x4f9559b100000000000000000000000000000000000000000000000000000000 {}                                          // cancelOrdersUpTo
-            default {
-                // Revert with `Error("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR")`
-                mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
-                mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
-                mstore(0x40, 0x00000024494e56414c49445f4f525f424c4f434b45445f45584348414e47455f)
-                mstore(0x60, 0x53454c4543544f52000000000000000000000000000000000000000000000000)
-                mstore(0x80, 0x00000000)
-                // Revert length calculation:
-                // 4   -- error selector
-                // 32  -- offset to string
-                // 32  -- string length field
-                // 64  -- strlen(INVALID_OR_BLOCKED_EXCHANGE_SELECTOR) rounded up to nearest 32-byte word.
-                revert(0, 132)
-            }
-            // solhint-enable no-empty-blocks
-
-            ///// Validate Recorded Addresses /////
-
-            // Load from memory the addresses to validate
-            let addressesToValidate := mload(0x40)
-            let addressesToValidateLength := mload(addressesToValidate)
-            let addressesToValidateElementPtr := add(addressesToValidate, 0x20)
-            let addressesToValidateElementEndPtr := add(addressesToValidateElementPtr, mul(addressesToValidateLength, 0x20))
-
-            // Set free memory pointer to after `addressesToValidate` array.
-            // This is to avoid corruption when making calls in the loop below.
-            let freeMemPtr := addressesToValidateElementEndPtr
-            mstore(0x40, freeMemPtr)
-
-            // Validate addresses
-            let thresholdAssetAddress := sload(THRESHOLD_ASSET_slot)
-            let thresholdBalance := sload(THRESHOLD_BALANCE_slot)
-            // solhint-disable max-line-length 
-            for {let addressToValidate := addressesToValidateElementPtr} lt(addressToValidate, addressesToValidateElementEndPtr) {addressToValidate := add(addressToValidate, 0x20)} {
-                // solhint-enable max-line-length 
-                // Construct calldata for `THRESHOLD_ASSET.balanceOf`
-                mstore(freeMemPtr, 0x70a0823100000000000000000000000000000000000000000000000000000000)
-                mstore(add(freeMemPtr, 0x04), mload(addressToValidate))
-               
-                // call `THRESHOLD_ASSET.balanceOf`
-                let success := call(
-                    gas,                                    // forward all gas
-                    thresholdAssetAddress,                 // call address of asset proxy
-                    0,                                      // don't send any ETH
-                    freeMemPtr,                             // pointer to start of input
-                    0x24,                                   // length of input (one padded address) 
-                    freeMemPtr,                             // write output to next free memory offset
-                    0x20                                    // reserve space for return balance (0x20 bytes)
-                )
-                if eq(success, 0) {
-                    // @TODO Revert with `Error("BALANCE_QUERY_FAILED")`
-                    mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
-                    mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
-                    mstore(0x40, 0x0000001442414c414e43455f51554552595f4641494c45440000000000000000)
-                    mstore(0x60, 0x00000000)
-                    // Revert length calculation:
-                    // 4   -- error selector
-                    // 32  -- offset to string
-                    // 32  -- string length field
-                    // 32  -- strlen(BALANCE_QUERY_FAILED) rounded up to nearest 32-byte word.
-                    revert(0, 100)
-                }
+        // Extract addresses to validate from Exchange calldata
+        address[] memory addressesToValidate = new address[](0);
+        bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
+        if(
+            exchangeFunctionSelector == batchFillOrdersSelector         || 
+            exchangeFunctionSelector == batchFillOrdersNoThrowSelector  || 
+            exchangeFunctionSelector == batchFillOrKillOrdersSelector   ||
+            exchangeFunctionSelector == marketBuyOrdersSelector         ||
+            exchangeFunctionSelector == marketBuyOrdersNoThrowSelector  ||
+            exchangeFunctionSelector == marketSellOrdersSelector        ||
+            exchangeFunctionSelector == marketSellOrdersNoThrowSelector
+        ) {
+            addressesToValidate = loadMakerAddressesFromOrderArray(0);
+            recordAddressToValidate(signerAddress, addressesToValidate);
+        } else if(
+            exchangeFunctionSelector == fillOrderSelector           ||
+            exchangeFunctionSelector == fillOrderNoThrowSelector    ||
+            exchangeFunctionSelector == fillOrKillOrderSelector
+        ) {
+            address makerAddress = loadMakerAddressFromOrder(0);
+            recordAddressToValidate(makerAddress, addressesToValidate);
+            recordAddressToValidate(signerAddress, addressesToValidate);
+        } else if(exchangeFunctionSelector == matchOrdersSelector) {
+            address leftOrderAddress = loadMakerAddressFromOrder(0);
+            recordAddressToValidate(leftOrderAddress, addressesToValidate);
+            address rightOrderAddress = loadMakerAddressFromOrder(1);
+            recordAddressToValidate(rightOrderAddress, addressesToValidate);
+            recordAddressToValidate(signerAddress, addressesToValidate);
+        } else if(
+            exchangeFunctionSelector == cancelOrderSelector         || 
+            exchangeFunctionSelector == batchCancelOrdersSelector   ||
+            exchangeFunctionSelector == cancelOrdersUpToSelector
+        ) {
+            // Do nothing
+        } else {
+            revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
+        }
 
-                // Revert if balance not held
-                let addressBalance := mload(freeMemPtr)
-                if lt(addressBalance, thresholdBalance) {
-                    // Revert with `Error("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD")`
-                    mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
-                    mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
-                    mstore(0x40, 0x0000003441545f4c454153545f4f4e455f414444524553535f444f45535f4e4f)
-                    mstore(0x60, 0x545f4d4545545f42414c414e43455f5448524553484f4c440000000000000000)
-                    mstore(0x80, 0x00000000)
-                    // Revert length calculation:
-                    // 4   -- error selector
-                    // 32  -- offset to string
-                    // 32  -- string length field
-                    // 64  -- strlen(AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD) rounded up to nearest 32-byte word.
-                    revert(0, 132)
-                }
+        // Validate account balances
+        uint256 balanceThreshold = BALANCE_THRESHOLD;
+        IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
+        for(uint i = 0; i < addressesToValidate.length; ++i) {
+            uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
+            if (addressBalance < balanceThreshold) {
+                revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
             }
-
-            // Record validated addresses
-            validatedAddresses := addressesToValidate
         }
-
-        ///// If we hit this point then all addresses are valid /////
-        emit ValidatedAddresses(validatedAddresses);
+        emit ValidatedAddresses(addressesToValidate);
     }
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
index af7a9453b..6aaa729fb 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
@@ -17,7 +17,6 @@
 */
 
 pragma solidity 0.4.24;
-pragma experimental ABIEncoderV2;
 
 import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
 import "../interfaces/IThresholdAsset.sol";
@@ -33,10 +32,10 @@ contract MBalanceThresholdFilterCore {
     IThresholdAsset internal THRESHOLD_ASSET;
 
     // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
-    uint256 internal THRESHOLD_BALANCE;
+    uint256 internal BALANCE_THRESHOLD;
     // solhint-enable var-name-mixedcase
 
-    // Addresses that hold at least `THRESHOLD_BALANCE` of `THRESHOLD_ASSET`
+    // Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET`
     event ValidatedAddresses (
         address[] addresses
     );
@@ -79,5 +78,5 @@ contract MBalanceThresholdFilterCore {
     ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
     ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
     ///      of the addresses whose balance thresholds it checked.
-    function validateBalanceThresholdsOrRevert() internal;
+    function validateBalanceThresholdsOrRevert(address signerAddress) internal;
 }
diff --git a/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol b/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol
new file mode 100644
index 000000000..c361fd075
--- /dev/null
+++ b/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol
@@ -0,0 +1,151 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+
+contract ExchangeSelectors {
+
+  // allowedValidators
+  bytes4 constant allowedValidatorsSelector = 0x7b8e3514;
+  bytes4 constant allowedValidatorsSelectorGenerator = bytes4(keccak256('allowedValidators(address,address)'));
+
+  // assetProxies
+  bytes4 constant assetProxiesSelector = 0x3fd3c997;
+  bytes4 constant assetProxiesSelectorGenerator = bytes4(keccak256('assetProxies(bytes4)'));
+
+  // batchCancelOrders
+  bytes4 constant batchCancelOrdersSelector = 0x4ac14782;
+  bytes4 constant batchCancelOrdersSelectorGenerator = bytes4(keccak256('batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
+
+  // batchFillOrKillOrders
+  bytes4 constant batchFillOrKillOrdersSelector = 0x4d0ae546;
+  bytes4 constant batchFillOrKillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // batchFillOrders
+  bytes4 constant batchFillOrdersSelector = 0x297bb70b;
+  bytes4 constant batchFillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // batchFillOrdersNoThrow
+  bytes4 constant batchFillOrdersNoThrowSelector = 0x50dde190;
+  bytes4 constant batchFillOrdersNoThrowSelectorGenerator = bytes4(keccak256('batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // cancelOrder
+  bytes4 constant cancelOrderSelector = 0xd46b02c3;
+  bytes4 constant cancelOrderSelectorGenerator = bytes4(keccak256('cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
+
+  // cancelOrdersUpTo
+  bytes4 constant cancelOrdersUpToSelector = 0x4f9559b1;
+  bytes4 constant cancelOrdersUpToSelectorGenerator = bytes4(keccak256('cancelOrdersUpTo(uint256)'));
+
+  // cancelled
+  bytes4 constant cancelledSelector = 0x2ac12622;
+  bytes4 constant cancelledSelectorGenerator = bytes4(keccak256('cancelled(bytes32)'));
+
+  // currentContextAddress
+  bytes4 constant currentContextAddressSelector = 0xeea086ba;
+  bytes4 constant currentContextAddressSelectorGenerator = bytes4(keccak256('currentContextAddress()'));
+
+  // executeTransaction
+  bytes4 constant executeTransactionSelector = 0xbfc8bfce;
+  bytes4 constant executeTransactionSelectorGenerator = bytes4(keccak256('executeTransaction(uint256,address,bytes,bytes)'));
+
+  // fillOrKillOrder
+  bytes4 constant fillOrKillOrderSelector = 0x64a3bc15;
+  bytes4 constant fillOrKillOrderSelectorGenerator = bytes4(keccak256('fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // fillOrder
+  bytes4 constant fillOrderSelector = 0xb4be83d5;
+  bytes4 constant fillOrderSelectorGenerator = bytes4(keccak256('fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // fillOrderNoThrow
+  bytes4 constant fillOrderNoThrowSelector = 0x3e228bae;
+  bytes4 constant fillOrderNoThrowSelectorGenerator = bytes4(keccak256('fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // filled
+  bytes4 constant filledSelector = 0x288cdc91;
+  bytes4 constant filledSelectorGenerator = bytes4(keccak256('filled(bytes32)'));
+
+  // getAssetProxy
+  bytes4 constant getAssetProxySelector = 0x60704108;
+  bytes4 constant getAssetProxySelectorGenerator = bytes4(keccak256('getAssetProxy(bytes4)'));
+
+  // getOrderInfo
+  bytes4 constant getOrderInfoSelector = 0xc75e0a81;
+  bytes4 constant getOrderInfoSelectorGenerator = bytes4(keccak256('getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
+
+  // getOrdersInfo
+  bytes4 constant getOrdersInfoSelector = 0x7e9d74dc;
+  bytes4 constant getOrdersInfoSelectorGenerator = bytes4(keccak256('getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
+
+  // isValidSignature
+  bytes4 constant isValidSignatureSelector = 0x93634702;
+  bytes4 constant isValidSignatureSelectorGenerator = bytes4(keccak256('isValidSignature(bytes32,address,bytes)'));
+
+  // marketBuyOrders
+  bytes4 constant marketBuyOrdersSelector = 0xe5fa431b;
+  bytes4 constant marketBuyOrdersSelectorGenerator = bytes4(keccak256('marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketBuyOrdersNoThrow
+  bytes4 constant marketBuyOrdersNoThrowSelector = 0xa3e20380;
+  bytes4 constant marketBuyOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketSellOrders
+  bytes4 constant marketSellOrdersSelector = 0x7e1d9808;
+  bytes4 constant marketSellOrdersSelectorGenerator = bytes4(keccak256('marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketSellOrdersNoThrow
+  bytes4 constant marketSellOrdersNoThrowSelector = 0xdd1c7d18;
+  bytes4 constant marketSellOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // matchOrders
+  bytes4 constant matchOrdersSelector = 0x3c28d861;
+  bytes4 constant matchOrdersSelectorGenerator = bytes4(keccak256('matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'));
+
+  // orderEpoch
+  bytes4 constant orderEpochSelector = 0xd9bfa73e;
+  bytes4 constant orderEpochSelectorGenerator = bytes4(keccak256('orderEpoch(address,address)'));
+
+  // owner
+  bytes4 constant ownerSelector = 0x8da5cb5b;
+  bytes4 constant ownerSelectorGenerator = bytes4(keccak256('owner()'));
+
+  // preSign
+  bytes4 constant preSignSelector = 0x3683ef8e;
+  bytes4 constant preSignSelectorGenerator = bytes4(keccak256('preSign(bytes32,address,bytes)'));
+
+  // preSigned
+  bytes4 constant preSignedSelector = 0x82c174d0;
+  bytes4 constant preSignedSelectorGenerator = bytes4(keccak256('preSigned(bytes32,address)'));
+
+  // registerAssetProxy
+  bytes4 constant registerAssetProxySelector = 0xc585bb93;
+  bytes4 constant registerAssetProxySelectorGenerator = bytes4(keccak256('registerAssetProxy(address)'));
+
+  // setSignatureValidatorApproval
+  bytes4 constant setSignatureValidatorApprovalSelector = 0x77fcce68;
+  bytes4 constant setSignatureValidatorApprovalSelectorGenerator = bytes4(keccak256('setSignatureValidatorApproval(address,bool)'));
+
+  // transactions
+  bytes4 constant transactionsSelector = 0x642f2eaf;
+  bytes4 constant transactionsSelectorGenerator = bytes4(keccak256('transactions(bytes32)'));
+
+  // transferOwnership
+  bytes4 constant transferOwnershipSelector = 0xf2fde38b;
+  bytes4 constant transferOwnershipSelectorGenerator = bytes4(keccak256('transferOwnership(address)'));
+}
\ No newline at end of file
-- 
cgit v1.2.3


From f3a2e3b6f3adb75d1920779df9dabb7cf476a996 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 14:20:11 -0800
Subject: Moved exchange calldata functions to separate mixin

---
 .../MixinBalanceThresholdFilterCore.sol            |  93 ++-----------
 .../utils/ExchangeSelectors/ExchangeSelectors.sol  | 151 ---------------------
 2 files changed, 9 insertions(+), 235 deletions(-)
 delete mode 100644 contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index e78f9ced8..8d15fe6c8 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -18,15 +18,17 @@
 
 pragma solidity 0.4.24;
 
-import "./mixins/MBalanceThresholdFilterCore.sol";
-import "@0x/contracts-utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol";
+import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol";
 import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
+import "./mixins/MBalanceThresholdFilterCore.sol";
+import "./MixinExchangeCalldata.sol";
 
 
 contract MixinBalanceThresholdFilterCore is
     MBalanceThresholdFilterCore,
+    MixinExchangeCalldata,
     LibOrder,
-    ExchangeSelectors
+    LibExchangeSelectors
 {
 
     /// @dev Executes an Exchange transaction iff the maker and taker meet 
@@ -72,82 +74,7 @@ contract MixinBalanceThresholdFilterCore is
         );
     }
 
-    /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
-    ///      which is accessed through `signedExchangeTransaction`.
-    /// @param offset  Offset into the Exchange calldata.
-    /// @return value  Corresponding 32 byte value stored at `offset`.
-    function exchangeCalldataload(uint256 offset)
-        internal
-        returns (bytes32 value)
-    {
-        assembly {
-            // Pointer to exchange transaction
-            // 0x04 for calldata selector
-            // 0x40 to access `signedExchangeTransaction`, which is the third parameter
-            let exchangeTxPtr := calldataload(0x44)
-
-            // Offset into Exchange calldata
-            // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
-            // 0x04 for calldata selector
-            // 0x20 for length field of `signedExchangeTransaction`
-            let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
-            value := calldataload(exchangeCalldataOffset)
-        }
-    }
-
-    /// @dev Convenience function that skips the 4 byte selector when loading
-    ///      from the embedded Exchange calldata.
-    /// @param offset  Offset into the Exchange calldata (minus the 4 byte selector)
-    /// @return value  Corresponding 32 byte value stored at `offset` + 4.
-    function loadExchangeData(uint256 offset)
-        internal
-        returns (bytes32 value)
-    {
-        value = exchangeCalldataload(offset + 4);
-    }
-
-    /// @dev A running list is maintained of addresses to validate. 
-    ///     This function records an address in this array.
-    /// @param addressToValidate  Address to record for validation.
-    function recordAddressToValidate(address addressToValidate, address[] memory addressList) 
-        internal
-    {
-        uint256 newAddressListLength = addressList.length + 1;
-        assembly {
-            // Store new array length
-            mstore(addressList, newAddressListLength)
-            mstore(0x40, add(addressList, add(0x20, mul(0x20, newAddressListLength))))
-        }
-        addressList[newAddressListLength - 1] = addressToValidate;
-    }
-
-    /// @dev Extracts the maker address from an order stored in the Exchange calldata
-    ///      (which is embedded in `signedExchangeTransaction`), and records it in
-    ///      the running list of addresses to validate.
-    /// @param orderParamIndex  Index of the order in the Exchange function's signature
-    function loadMakerAddressFromOrder(uint8 orderParamIndex) internal returns (address makerAddress) {
-        uint256 orderPtr = uint256(loadExchangeData(orderParamIndex * 0x20));
-        makerAddress = address(loadExchangeData(orderPtr));
-    }
-
-    /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
-    ///      (which is embedded in `signedExchangeTransaction`), and records them in
-    ///      the running list of addresses to validate.
-    /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
-    function loadMakerAddressesFromOrderArray(uint8 orderArrayParamIndex)
-        internal
-        returns (address[] makerAddresses)
-    {
-        uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayParamIndex * 0x20));
-        uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
-        uint256 orderArrayElementPtr = orderArrayPtr + 0x20;
-        uint256 orderArrayElementEndPtr = orderArrayElementPtr + (orderArrayLength * 0x20);
-        for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 0x20) {
-            uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
-            address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
-            recordAddressToValidate(makerAddress, makerAddresses);
-        }
-    }
+    
 
     /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
     ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
@@ -188,12 +115,10 @@ contract MixinBalanceThresholdFilterCore is
             recordAddressToValidate(rightOrderAddress, addressesToValidate);
             recordAddressToValidate(signerAddress, addressesToValidate);
         } else if(
-            exchangeFunctionSelector == cancelOrderSelector         || 
-            exchangeFunctionSelector == batchCancelOrdersSelector   ||
-            exchangeFunctionSelector == cancelOrdersUpToSelector
+            exchangeFunctionSelector != cancelOrderSelector         && 
+            exchangeFunctionSelector != batchCancelOrdersSelector   &&
+            exchangeFunctionSelector != cancelOrdersUpToSelector
         ) {
-            // Do nothing
-        } else {
             revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
         }
 
diff --git a/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol b/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol
deleted file mode 100644
index c361fd075..000000000
--- a/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-
-  Copyright 2018 ZeroEx Intl.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-*/
-
-pragma solidity 0.4.24;
-
-
-contract ExchangeSelectors {
-
-  // allowedValidators
-  bytes4 constant allowedValidatorsSelector = 0x7b8e3514;
-  bytes4 constant allowedValidatorsSelectorGenerator = bytes4(keccak256('allowedValidators(address,address)'));
-
-  // assetProxies
-  bytes4 constant assetProxiesSelector = 0x3fd3c997;
-  bytes4 constant assetProxiesSelectorGenerator = bytes4(keccak256('assetProxies(bytes4)'));
-
-  // batchCancelOrders
-  bytes4 constant batchCancelOrdersSelector = 0x4ac14782;
-  bytes4 constant batchCancelOrdersSelectorGenerator = bytes4(keccak256('batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
-
-  // batchFillOrKillOrders
-  bytes4 constant batchFillOrKillOrdersSelector = 0x4d0ae546;
-  bytes4 constant batchFillOrKillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
-
-  // batchFillOrders
-  bytes4 constant batchFillOrdersSelector = 0x297bb70b;
-  bytes4 constant batchFillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
-
-  // batchFillOrdersNoThrow
-  bytes4 constant batchFillOrdersNoThrowSelector = 0x50dde190;
-  bytes4 constant batchFillOrdersNoThrowSelectorGenerator = bytes4(keccak256('batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
-
-  // cancelOrder
-  bytes4 constant cancelOrderSelector = 0xd46b02c3;
-  bytes4 constant cancelOrderSelectorGenerator = bytes4(keccak256('cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
-
-  // cancelOrdersUpTo
-  bytes4 constant cancelOrdersUpToSelector = 0x4f9559b1;
-  bytes4 constant cancelOrdersUpToSelectorGenerator = bytes4(keccak256('cancelOrdersUpTo(uint256)'));
-
-  // cancelled
-  bytes4 constant cancelledSelector = 0x2ac12622;
-  bytes4 constant cancelledSelectorGenerator = bytes4(keccak256('cancelled(bytes32)'));
-
-  // currentContextAddress
-  bytes4 constant currentContextAddressSelector = 0xeea086ba;
-  bytes4 constant currentContextAddressSelectorGenerator = bytes4(keccak256('currentContextAddress()'));
-
-  // executeTransaction
-  bytes4 constant executeTransactionSelector = 0xbfc8bfce;
-  bytes4 constant executeTransactionSelectorGenerator = bytes4(keccak256('executeTransaction(uint256,address,bytes,bytes)'));
-
-  // fillOrKillOrder
-  bytes4 constant fillOrKillOrderSelector = 0x64a3bc15;
-  bytes4 constant fillOrKillOrderSelectorGenerator = bytes4(keccak256('fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
-
-  // fillOrder
-  bytes4 constant fillOrderSelector = 0xb4be83d5;
-  bytes4 constant fillOrderSelectorGenerator = bytes4(keccak256('fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
-
-  // fillOrderNoThrow
-  bytes4 constant fillOrderNoThrowSelector = 0x3e228bae;
-  bytes4 constant fillOrderNoThrowSelectorGenerator = bytes4(keccak256('fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
-
-  // filled
-  bytes4 constant filledSelector = 0x288cdc91;
-  bytes4 constant filledSelectorGenerator = bytes4(keccak256('filled(bytes32)'));
-
-  // getAssetProxy
-  bytes4 constant getAssetProxySelector = 0x60704108;
-  bytes4 constant getAssetProxySelectorGenerator = bytes4(keccak256('getAssetProxy(bytes4)'));
-
-  // getOrderInfo
-  bytes4 constant getOrderInfoSelector = 0xc75e0a81;
-  bytes4 constant getOrderInfoSelectorGenerator = bytes4(keccak256('getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
-
-  // getOrdersInfo
-  bytes4 constant getOrdersInfoSelector = 0x7e9d74dc;
-  bytes4 constant getOrdersInfoSelectorGenerator = bytes4(keccak256('getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
-
-  // isValidSignature
-  bytes4 constant isValidSignatureSelector = 0x93634702;
-  bytes4 constant isValidSignatureSelectorGenerator = bytes4(keccak256('isValidSignature(bytes32,address,bytes)'));
-
-  // marketBuyOrders
-  bytes4 constant marketBuyOrdersSelector = 0xe5fa431b;
-  bytes4 constant marketBuyOrdersSelectorGenerator = bytes4(keccak256('marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketBuyOrdersNoThrow
-  bytes4 constant marketBuyOrdersNoThrowSelector = 0xa3e20380;
-  bytes4 constant marketBuyOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketSellOrders
-  bytes4 constant marketSellOrdersSelector = 0x7e1d9808;
-  bytes4 constant marketSellOrdersSelectorGenerator = bytes4(keccak256('marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketSellOrdersNoThrow
-  bytes4 constant marketSellOrdersNoThrowSelector = 0xdd1c7d18;
-  bytes4 constant marketSellOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // matchOrders
-  bytes4 constant matchOrdersSelector = 0x3c28d861;
-  bytes4 constant matchOrdersSelectorGenerator = bytes4(keccak256('matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'));
-
-  // orderEpoch
-  bytes4 constant orderEpochSelector = 0xd9bfa73e;
-  bytes4 constant orderEpochSelectorGenerator = bytes4(keccak256('orderEpoch(address,address)'));
-
-  // owner
-  bytes4 constant ownerSelector = 0x8da5cb5b;
-  bytes4 constant ownerSelectorGenerator = bytes4(keccak256('owner()'));
-
-  // preSign
-  bytes4 constant preSignSelector = 0x3683ef8e;
-  bytes4 constant preSignSelectorGenerator = bytes4(keccak256('preSign(bytes32,address,bytes)'));
-
-  // preSigned
-  bytes4 constant preSignedSelector = 0x82c174d0;
-  bytes4 constant preSignedSelectorGenerator = bytes4(keccak256('preSigned(bytes32,address)'));
-
-  // registerAssetProxy
-  bytes4 constant registerAssetProxySelector = 0xc585bb93;
-  bytes4 constant registerAssetProxySelectorGenerator = bytes4(keccak256('registerAssetProxy(address)'));
-
-  // setSignatureValidatorApproval
-  bytes4 constant setSignatureValidatorApprovalSelector = 0x77fcce68;
-  bytes4 constant setSignatureValidatorApprovalSelectorGenerator = bytes4(keccak256('setSignatureValidatorApproval(address,bool)'));
-
-  // transactions
-  bytes4 constant transactionsSelector = 0x642f2eaf;
-  bytes4 constant transactionsSelectorGenerator = bytes4(keccak256('transactions(bytes32)'));
-
-  // transferOwnership
-  bytes4 constant transferOwnershipSelector = 0xf2fde38b;
-  bytes4 constant transferOwnershipSelectorGenerator = bytes4(keccak256('transferOwnership(address)'));
-}
\ No newline at end of file
-- 
cgit v1.2.3


From dea6f35b0471913551d58a08f547974701fc0057 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 14:26:11 -0800
Subject: Refactoring balance threshold filter

---
 .../BalanceThresholdFilter.sol                     |   1 -
 .../MixinBalanceThresholdFilterCore.sol            |  63 ++++-----
 .../MixinExchangeCalldata.sol                      | 102 ++++++++++++++
 .../interfaces/IBalanceThresholdFilterCore.sol     |  56 ++++++++
 .../mixins/MBalanceThresholdFilterCore.sol         |  50 ++-----
 .../mixins/MExchangeCalldata.sol                   |  57 ++++++++
 contracts/libs/contracts/libs/LibAddressArray.sol  |  75 ++++++++++
 .../libs/contracts/libs/LibExchangeSelectors.sol   | 151 +++++++++++++++++++++
 8 files changed, 481 insertions(+), 74 deletions(-)
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
 create mode 100644 contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
 create mode 100644 contracts/libs/contracts/libs/LibAddressArray.sol
 create mode 100644 contracts/libs/contracts/libs/LibExchangeSelectors.sol

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
index ea248793f..16cacd461 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol
@@ -17,7 +17,6 @@
 */
 
 pragma solidity 0.4.24;
-pragma experimental ABIEncoderV2;
 
 import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
 import "./interfaces/IThresholdAsset.sol";
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 8d15fe6c8..a8947751a 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -62,8 +62,19 @@ contract MixinBalanceThresholdFilterCore is
     ) 
         external
     {
-        // Validate addresses.
-        validateBalanceThresholdsOrRevert(signerAddress);
+        // Get accounts whose balances must be validated
+        address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
+
+        // Validate account balances
+        uint256 balanceThreshold = BALANCE_THRESHOLD;
+        IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
+        for(uint256 i = 0; i < addressesToValidate.length; ++i) {
+            uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
+            if (addressBalance < balanceThreshold) {
+                revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
+            }
+        }
+        emit ValidatedAddresses(addressesToValidate);
         
         // All addresses are valid. Execute fillOrder.
         EXCHANGE.executeTransaction(
@@ -74,20 +85,15 @@ contract MixinBalanceThresholdFilterCore is
         );
     }
 
-    
-
-    /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
-    ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
-    ///      then this function will revert. Which addresses are validated depends on
-    ///      which Exchange function is to be called (defined by `signedExchangeTransaction` above).
-    ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
-    ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
-    ///      of the addresses whose balance thresholds it checked.
-    function validateBalanceThresholdsOrRevert(address signerAddress)
-        internal
+    /// @dev Constructs an array of addresses to be validated.
+    ///      Addresses depend on which Exchange function is to be called
+    ///      (defined by `signedExchangeTransaction` above).
+    /// @param signerAddress Address of transaction signer.
+    /// @return addressesToValidate Array of addresses to validate.
+    function getAddressesToValidate(address signerAddress)
+        internal pure
+        returns (address[] memory addressesToValidate)
     {
-        // Extract addresses to validate from Exchange calldata
-        address[] memory addressesToValidate = new address[](0);
         bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
         if(
             exchangeFunctionSelector == batchFillOrdersSelector         || 
@@ -99,21 +105,21 @@ contract MixinBalanceThresholdFilterCore is
             exchangeFunctionSelector == marketSellOrdersNoThrowSelector
         ) {
             addressesToValidate = loadMakerAddressesFromOrderArray(0);
-            recordAddressToValidate(signerAddress, addressesToValidate);
+            addressesToValidate = addressesToValidate.append(signerAddress);
         } else if(
             exchangeFunctionSelector == fillOrderSelector           ||
             exchangeFunctionSelector == fillOrderNoThrowSelector    ||
             exchangeFunctionSelector == fillOrKillOrderSelector
         ) {
             address makerAddress = loadMakerAddressFromOrder(0);
-            recordAddressToValidate(makerAddress, addressesToValidate);
-            recordAddressToValidate(signerAddress, addressesToValidate);
+            addressesToValidate = addressesToValidate.append(makerAddress);
+            addressesToValidate = addressesToValidate.append(signerAddress);
         } else if(exchangeFunctionSelector == matchOrdersSelector) {
-            address leftOrderAddress = loadMakerAddressFromOrder(0);
-            recordAddressToValidate(leftOrderAddress, addressesToValidate);
-            address rightOrderAddress = loadMakerAddressFromOrder(1);
-            recordAddressToValidate(rightOrderAddress, addressesToValidate);
-            recordAddressToValidate(signerAddress, addressesToValidate);
+            address leftMakerAddress = loadMakerAddressFromOrder(0);
+            addressesToValidate = addressesToValidate.append(leftMakerAddress);
+            address rightMakerAddress = loadMakerAddressFromOrder(1);
+            addressesToValidate = addressesToValidate.append(rightMakerAddress);
+            addressesToValidate = addressesToValidate.append(signerAddress);
         } else if(
             exchangeFunctionSelector != cancelOrderSelector         && 
             exchangeFunctionSelector != batchCancelOrdersSelector   &&
@@ -121,16 +127,5 @@ contract MixinBalanceThresholdFilterCore is
         ) {
             revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
         }
-
-        // Validate account balances
-        uint256 balanceThreshold = BALANCE_THRESHOLD;
-        IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
-        for(uint i = 0; i < addressesToValidate.length; ++i) {
-            uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
-            if (addressBalance < balanceThreshold) {
-                revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
-            }
-        }
-        emit ValidatedAddresses(addressesToValidate);
     }
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
new file mode 100644
index 000000000..12f601dea
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
@@ -0,0 +1,102 @@
+    
+    /*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "./mixins/MExchangeCalldata.sol";
+import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
+
+
+contract MixinExchangeCalldata is 
+    MExchangeCalldata
+{
+
+    using LibAddressArray for address[];
+
+    /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
+    ///      which is accessed through `signedExchangeTransaction`.
+    /// @param offset  Offset into the Exchange calldata.
+    /// @return value  Corresponding 32 byte value stored at `offset`.
+    function exchangeCalldataload(uint256 offset)
+        internal pure
+        returns (bytes32 value)
+    {
+        assembly {
+            // Pointer to exchange transaction
+            // 0x04 for calldata selector
+            // 0x40 to access `signedExchangeTransaction`, which is the third parameter
+            let exchangeTxPtr := calldataload(0x44)
+
+            // Offset into Exchange calldata
+            // We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
+            // 0x04 for calldata selector
+            // 0x20 for length field of `signedExchangeTransaction`
+            let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
+            value := calldataload(exchangeCalldataOffset)
+        }
+    }
+
+    /// @dev Convenience function that skips the 4 byte selector when loading
+    ///      from the embedded Exchange calldata.
+    /// @param offset  Offset into the Exchange calldata (minus the 4 byte selector)
+    /// @return value  Corresponding 32 byte value stored at `offset` + 4.
+    function loadExchangeData(uint256 offset)
+        internal pure
+        returns (bytes32 value)
+    {
+        value = exchangeCalldataload(offset + 4);
+    }
+
+    /// @dev Extracts the maker address from an order stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`).
+    /// @param orderParamIndex  Index of the order in the Exchange function's signature.
+    /// @return makerAddress The extracted maker address.
+    function loadMakerAddressFromOrder(uint256 orderParamIndex)
+        internal pure
+        returns (address makerAddress)
+    {
+        uint256 orderOffsetInBytes = orderParamIndex * 32;
+        uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
+        makerAddress = address(loadExchangeData(orderPtr));
+        return makerAddress;
+    }
+
+    /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`), and records them in
+    ///      the running list of addresses to validate.
+    /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
+    /// @return makerAddresses The extracted maker addresses.
+    function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
+        internal pure
+        returns (address[] makerAddresses)
+    {
+        uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
+        uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
+        uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
+        uint256 orderArrayLengthInBytes = orderArrayLength * 32;
+        uint256 orderArrayElementPtr = orderArrayPtr + 32;
+        uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
+        for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
+            uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
+            address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
+            makerAddresses = makerAddresses.append(makerAddress);
+        }
+        return makerAddresses;
+    }
+}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
new file mode 100644
index 000000000..37e607be1
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
@@ -0,0 +1,56 @@
+
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+
+
+contract IBalanceThresholdFilterCore {
+    
+    /// @dev Executes an Exchange transaction iff the maker and taker meet 
+    ///      the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR 
+    ///      the exchange function is a cancellation.
+    ///      Supported Exchange functions:
+    ///         - batchFillOrders
+    ///         - batchFillOrdersNoThrow
+    ///         - batchFillOrKillOrders
+    ///         - fillOrder
+    ///         - fillOrderNoThrow
+    ///         - fillOrKillOrder
+    ///         - marketBuyOrders
+    ///         - marketBuyOrdersNoThrow
+    ///         - marketSellOrders
+    ///         - marketSellOrdersNoThrow
+    ///         - matchOrders
+    ///         - cancelOrder
+    ///         - batchCancelOrders
+    ///         - cancelOrdersUpTo
+    ///     Trying to call any other exchange function will throw.
+    /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+    /// @param signerAddress Address of transaction signer.
+    /// @param signedExchangeTransaction AbiV2 encoded calldata.
+    /// @param signature Proof of signer transaction by signer.
+    function executeTransaction(
+        uint256 salt,
+        address signerAddress,
+        bytes signedExchangeTransaction,
+        bytes signature
+    ) 
+        external;
+}
\ No newline at end of file
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
index 6aaa729fb..b8b67e6ee 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol
@@ -20,9 +20,12 @@ pragma solidity 0.4.24;
 
 import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
 import "../interfaces/IThresholdAsset.sol";
+import "../interfaces/IBalanceThresholdFilterCore.sol";
 
 
-contract MBalanceThresholdFilterCore {
+contract MBalanceThresholdFilterCore is
+    IBalanceThresholdFilterCore
+{
 
     // Points to 0x exchange contract
     // solhint-disable var-name-mixedcase
@@ -40,43 +43,12 @@ contract MBalanceThresholdFilterCore {
         address[] addresses
     );
 
-    /// @dev Executes an Exchange transaction iff the maker and taker meet 
-    ///      the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR 
-    ///      the exchange function is a cancellation.
-    ///      Supported Exchange functions:
-    ///         - batchFillOrders
-    ///         - batchFillOrdersNoThrow
-    ///         - batchFillOrKillOrders
-    ///         - fillOrder
-    ///         - fillOrderNoThrow
-    ///         - fillOrKillOrder
-    ///         - marketBuyOrders
-    ///         - marketBuyOrdersNoThrow
-    ///         - marketSellOrders
-    ///         - marketSellOrdersNoThrow
-    ///         - matchOrders
-    ///         - cancelOrder
-    ///         - batchCancelOrders
-    ///         - cancelOrdersUpTo
-    ///     Trying to call any other exchange function will throw.
-    /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+    /// @dev Constructs an array of addresses to be validated.
+    ///      Addresses depend on which Exchange function is to be called
+    ///      (defined by `signedExchangeTransaction` above).
     /// @param signerAddress Address of transaction signer.
-    /// @param signedExchangeTransaction AbiV2 encoded calldata.
-    /// @param signature Proof of signer transaction by signer.
-    function executeTransaction(
-        uint256 salt,
-        address signerAddress,
-        bytes signedExchangeTransaction,
-        bytes signature
-    ) 
-        external;
-
-    /// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
-    ///      for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
-    ///      then this function will revert. Which addresses are validated depends on
-    ///      which Exchange function is to be called (defined by `signedExchangeTransaction` above).
-    ///      No parameters are taken as this function reads arguments directly from calldata, to save gas.
-    ///      If all addresses are valid then this function emits a ValidatedAddresses event, listing all
-    ///      of the addresses whose balance thresholds it checked.
-    function validateBalanceThresholdsOrRevert(address signerAddress) internal;
+    /// @return addressesToValidate Array of addresses to validate.
+    function getAddressesToValidate(address signerAddress)
+        internal pure
+        returns (address[] memory addressesToValidate);
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
new file mode 100644
index 000000000..8e0414c17
--- /dev/null
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
@@ -0,0 +1,57 @@
+    
+    /*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+
+contract MExchangeCalldata {
+
+    /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
+    ///      which is accessed through `signedExchangeTransaction`.
+    /// @param offset  Offset into the Exchange calldata.
+    /// @return value  Corresponding 32 byte value stored at `offset`.
+    function exchangeCalldataload(uint256 offset)
+        internal pure
+        returns (bytes32 value);
+
+    /// @dev Convenience function that skips the 4 byte selector when loading
+    ///      from the embedded Exchange calldata.
+    /// @param offset  Offset into the Exchange calldata (minus the 4 byte selector)
+    /// @return value  Corresponding 32 byte value stored at `offset` + 4.
+    function loadExchangeData(uint256 offset)
+        internal pure
+        returns (bytes32 value);
+
+    /// @dev Extracts the maker address from an order stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`).
+    /// @param orderParamIndex  Index of the order in the Exchange function's signature.
+    /// @return makerAddress The extracted maker address.
+    function loadMakerAddressFromOrder(uint256 orderParamIndex)
+        internal pure
+        returns (address makerAddress);
+
+    /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
+    ///      (which is embedded in `signedExchangeTransaction`), and records them in
+    ///      the running list of addresses to validate.
+    /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
+    /// @return makerAddresses The extracted maker addresses.
+    function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
+        internal pure
+        returns (address[] makerAddresses);
+}
diff --git a/contracts/libs/contracts/libs/LibAddressArray.sol b/contracts/libs/contracts/libs/LibAddressArray.sol
new file mode 100644
index 000000000..db76ddedb
--- /dev/null
+++ b/contracts/libs/contracts/libs/LibAddressArray.sol
@@ -0,0 +1,75 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
+
+
+library LibAddressArray {
+
+    /// @dev Append a new address to an array of addresses.
+    ///      The `addressArray` may need to be reallocated to make space
+    ///      for the new address. Because of this we return the resulting
+    ///      memory location of `addressArray`.
+    /// @param addressToAppend  Address to append.
+    /// @return Array of addresses: [... addressArray, addressToAppend]
+    function append(address[] memory addressArray, address addressToAppend) 
+        internal pure
+        returns (address[])
+    {
+        // Get stats on address array and free memory
+        uint256 freeMemPtr = 0;
+        uint256 addressArrayBeginPtr = 0;
+        uint256 addressArrayEndPtr = 0;
+        uint256 addressArrayLength = addressArray.length;
+        uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);
+        assembly {
+            freeMemPtr := mload(0x40)
+            addressArrayBeginPtr := addressArray
+            addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
+        }
+
+        // If free memory begins at the end of `addressArray`
+        // then we can append `addressToAppend` directly.
+        // Otherwise, we must copy the array to free memory
+        // before appending new values to it.
+        if (freeMemPtr != addressArrayEndPtr) {
+            LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
+            assembly {
+                addressArray := freeMemPtr
+                addressArrayBeginPtr := addressArray
+            }
+        }
+
+        // Append `addressToAppend`
+        addressArrayLength += 1;
+        addressArrayMemSizeInBytes += 32;
+        addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;
+        freeMemPtr = addressArrayEndPtr;
+        assembly {
+            // Store new array length
+            mstore(addressArray, addressArrayLength)
+
+            // Update `freeMemPtr`
+            mstore(0x40, freeMemPtr)
+        }
+        addressArray[addressArrayLength - 1] = addressToAppend;
+        return addressArray;
+    }
+}
diff --git a/contracts/libs/contracts/libs/LibExchangeSelectors.sol b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
new file mode 100644
index 000000000..6a5344340
--- /dev/null
+++ b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
@@ -0,0 +1,151 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+
+contract LibExchangeSelectors {
+
+  // allowedValidators
+  bytes4 constant allowedValidatorsSelector = 0x7b8e3514;
+  bytes4 constant allowedValidatorsSelectorGenerator = bytes4(keccak256('allowedValidators(address,address)'));
+
+  // assetProxies
+  bytes4 constant assetProxiesSelector = 0x3fd3c997;
+  bytes4 constant assetProxiesSelectorGenerator = bytes4(keccak256('assetProxies(bytes4)'));
+
+  // batchCancelOrders
+  bytes4 constant batchCancelOrdersSelector = 0x4ac14782;
+  bytes4 constant batchCancelOrdersSelectorGenerator = bytes4(keccak256('batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
+
+  // batchFillOrKillOrders
+  bytes4 constant batchFillOrKillOrdersSelector = 0x4d0ae546;
+  bytes4 constant batchFillOrKillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // batchFillOrders
+  bytes4 constant batchFillOrdersSelector = 0x297bb70b;
+  bytes4 constant batchFillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // batchFillOrdersNoThrow
+  bytes4 constant batchFillOrdersNoThrowSelector = 0x50dde190;
+  bytes4 constant batchFillOrdersNoThrowSelectorGenerator = bytes4(keccak256('batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+
+  // cancelOrder
+  bytes4 constant cancelOrderSelector = 0xd46b02c3;
+  bytes4 constant cancelOrderSelectorGenerator = bytes4(keccak256('cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
+
+  // cancelOrdersUpTo
+  bytes4 constant cancelOrdersUpToSelector = 0x4f9559b1;
+  bytes4 constant cancelOrdersUpToSelectorGenerator = bytes4(keccak256('cancelOrdersUpTo(uint256)'));
+
+  // cancelled
+  bytes4 constant cancelledSelector = 0x2ac12622;
+  bytes4 constant cancelledSelectorGenerator = bytes4(keccak256('cancelled(bytes32)'));
+
+  // currentContextAddress
+  bytes4 constant currentContextAddressSelector = 0xeea086ba;
+  bytes4 constant currentContextAddressSelectorGenerator = bytes4(keccak256('currentContextAddress()'));
+
+  // executeTransaction
+  bytes4 constant executeTransactionSelector = 0xbfc8bfce;
+  bytes4 constant executeTransactionSelectorGenerator = bytes4(keccak256('executeTransaction(uint256,address,bytes,bytes)'));
+
+  // fillOrKillOrder
+  bytes4 constant fillOrKillOrderSelector = 0x64a3bc15;
+  bytes4 constant fillOrKillOrderSelectorGenerator = bytes4(keccak256('fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // fillOrder
+  bytes4 constant fillOrderSelector = 0xb4be83d5;
+  bytes4 constant fillOrderSelectorGenerator = bytes4(keccak256('fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // fillOrderNoThrow
+  bytes4 constant fillOrderNoThrowSelector = 0x3e228bae;
+  bytes4 constant fillOrderNoThrowSelectorGenerator = bytes4(keccak256('fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+
+  // filled
+  bytes4 constant filledSelector = 0x288cdc91;
+  bytes4 constant filledSelectorGenerator = bytes4(keccak256('filled(bytes32)'));
+
+  // getAssetProxy
+  bytes4 constant getAssetProxySelector = 0x60704108;
+  bytes4 constant getAssetProxySelectorGenerator = bytes4(keccak256('getAssetProxy(bytes4)'));
+
+  // getOrderInfo
+  bytes4 constant getOrderInfoSelector = 0xc75e0a81;
+  bytes4 constant getOrderInfoSelectorGenerator = bytes4(keccak256('getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
+
+  // getOrdersInfo
+  bytes4 constant getOrdersInfoSelector = 0x7e9d74dc;
+  bytes4 constant getOrdersInfoSelectorGenerator = bytes4(keccak256('getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
+
+  // isValidSignature
+  bytes4 constant isValidSignatureSelector = 0x93634702;
+  bytes4 constant isValidSignatureSelectorGenerator = bytes4(keccak256('isValidSignature(bytes32,address,bytes)'));
+
+  // marketBuyOrders
+  bytes4 constant marketBuyOrdersSelector = 0xe5fa431b;
+  bytes4 constant marketBuyOrdersSelectorGenerator = bytes4(keccak256('marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketBuyOrdersNoThrow
+  bytes4 constant marketBuyOrdersNoThrowSelector = 0xa3e20380;
+  bytes4 constant marketBuyOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketSellOrders
+  bytes4 constant marketSellOrdersSelector = 0x7e1d9808;
+  bytes4 constant marketSellOrdersSelectorGenerator = bytes4(keccak256('marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // marketSellOrdersNoThrow
+  bytes4 constant marketSellOrdersNoThrowSelector = 0xdd1c7d18;
+  bytes4 constant marketSellOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
+
+  // matchOrders
+  bytes4 constant matchOrdersSelector = 0x3c28d861;
+  bytes4 constant matchOrdersSelectorGenerator = bytes4(keccak256('matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'));
+
+  // orderEpoch
+  bytes4 constant orderEpochSelector = 0xd9bfa73e;
+  bytes4 constant orderEpochSelectorGenerator = bytes4(keccak256('orderEpoch(address,address)'));
+
+  // owner
+  bytes4 constant ownerSelector = 0x8da5cb5b;
+  bytes4 constant ownerSelectorGenerator = bytes4(keccak256('owner()'));
+
+  // preSign
+  bytes4 constant preSignSelector = 0x3683ef8e;
+  bytes4 constant preSignSelectorGenerator = bytes4(keccak256('preSign(bytes32,address,bytes)'));
+
+  // preSigned
+  bytes4 constant preSignedSelector = 0x82c174d0;
+  bytes4 constant preSignedSelectorGenerator = bytes4(keccak256('preSigned(bytes32,address)'));
+
+  // registerAssetProxy
+  bytes4 constant registerAssetProxySelector = 0xc585bb93;
+  bytes4 constant registerAssetProxySelectorGenerator = bytes4(keccak256('registerAssetProxy(address)'));
+
+  // setSignatureValidatorApproval
+  bytes4 constant setSignatureValidatorApprovalSelector = 0x77fcce68;
+  bytes4 constant setSignatureValidatorApprovalSelectorGenerator = bytes4(keccak256('setSignatureValidatorApproval(address,bool)'));
+
+  // transactions
+  bytes4 constant transactionsSelector = 0x642f2eaf;
+  bytes4 constant transactionsSelectorGenerator = bytes4(keccak256('transactions(bytes32)'));
+
+  // transferOwnership
+  bytes4 constant transferOwnershipSelector = 0xf2fde38b;
+  bytes4 constant transferOwnershipSelectorGenerator = bytes4(keccak256('transferOwnership(address)'));
+}
\ No newline at end of file
-- 
cgit v1.2.3


From b524ac7af2ebf0f00c50ae3c1ad7cd85ab8b6462 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 15:58:58 -0800
Subject: Prettier / Linter on contracts + TS

---
 .../MixinBalanceThresholdFilterCore.sol            |  14 +--
 .../MixinExchangeCalldata.sol                      |   5 +-
 .../interfaces/IBalanceThresholdFilterCore.sol     |   3 +-
 .../mixins/MExchangeCalldata.sol                   |   3 +-
 .../test/extensions/balance_threshold_filter.ts    | 109 ++++++---------------
 5 files changed, 44 insertions(+), 90 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index a8947751a..27767ad98 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -68,7 +68,7 @@ contract MixinBalanceThresholdFilterCore is
         // Validate account balances
         uint256 balanceThreshold = BALANCE_THRESHOLD;
         IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
-        for(uint256 i = 0; i < addressesToValidate.length; ++i) {
+        for (uint256 i = 0; i < addressesToValidate.length; ++i) {
             uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
             if (addressBalance < balanceThreshold) {
                 revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
@@ -95,8 +95,9 @@ contract MixinBalanceThresholdFilterCore is
         returns (address[] memory addressesToValidate)
     {
         bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
-        if(
-            exchangeFunctionSelector == batchFillOrdersSelector         || 
+        // solhint-disable expression-indent
+        if (
+            exchangeFunctionSelector == batchFillOrdersSelector         ||
             exchangeFunctionSelector == batchFillOrdersNoThrowSelector  || 
             exchangeFunctionSelector == batchFillOrKillOrdersSelector   ||
             exchangeFunctionSelector == marketBuyOrdersSelector         ||
@@ -106,7 +107,7 @@ contract MixinBalanceThresholdFilterCore is
         ) {
             addressesToValidate = loadMakerAddressesFromOrderArray(0);
             addressesToValidate = addressesToValidate.append(signerAddress);
-        } else if(
+        } else if (
             exchangeFunctionSelector == fillOrderSelector           ||
             exchangeFunctionSelector == fillOrderNoThrowSelector    ||
             exchangeFunctionSelector == fillOrKillOrderSelector
@@ -114,18 +115,19 @@ contract MixinBalanceThresholdFilterCore is
             address makerAddress = loadMakerAddressFromOrder(0);
             addressesToValidate = addressesToValidate.append(makerAddress);
             addressesToValidate = addressesToValidate.append(signerAddress);
-        } else if(exchangeFunctionSelector == matchOrdersSelector) {
+        } else if (exchangeFunctionSelector == matchOrdersSelector) {
             address leftMakerAddress = loadMakerAddressFromOrder(0);
             addressesToValidate = addressesToValidate.append(leftMakerAddress);
             address rightMakerAddress = loadMakerAddressFromOrder(1);
             addressesToValidate = addressesToValidate.append(rightMakerAddress);
             addressesToValidate = addressesToValidate.append(signerAddress);
-        } else if(
+        } else if (
             exchangeFunctionSelector != cancelOrderSelector         && 
             exchangeFunctionSelector != batchCancelOrdersSelector   &&
             exchangeFunctionSelector != cancelOrdersUpToSelector
         ) {
             revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
         }
+        // solhint-enable expression-indent
     }
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
index 12f601dea..d49b7123f 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
@@ -78,8 +78,7 @@ contract MixinExchangeCalldata is
     }
 
     /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
-    ///      (which is embedded in `signedExchangeTransaction`), and records them in
-    ///      the running list of addresses to validate.
+    ///      (which is embedded in `signedExchangeTransaction`).
     /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
     /// @return makerAddresses The extracted maker addresses.
     function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
@@ -92,7 +91,7 @@ contract MixinExchangeCalldata is
         uint256 orderArrayLengthInBytes = orderArrayLength * 32;
         uint256 orderArrayElementPtr = orderArrayPtr + 32;
         uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
-        for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
+        for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
             uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
             address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
             makerAddresses = makerAddresses.append(makerAddress);
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
index 37e607be1..3d8e2bbd1 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol
@@ -20,7 +20,6 @@
 pragma solidity 0.4.24;
 
 
-
 contract IBalanceThresholdFilterCore {
     
     /// @dev Executes an Exchange transaction iff the maker and taker meet 
@@ -53,4 +52,4 @@ contract IBalanceThresholdFilterCore {
         bytes signature
     ) 
         external;
-}
\ No newline at end of file
+}
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
index 8e0414c17..bf2940fe1 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol
@@ -47,8 +47,7 @@ contract MExchangeCalldata {
         returns (address makerAddress);
 
     /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
-    ///      (which is embedded in `signedExchangeTransaction`), and records them in
-    ///      the running list of addresses to validate.
+    ///      (which is embedded in `signedExchangeTransaction`).
     /// @param orderArrayParamIndex  Index of the order array in the Exchange function's signature
     /// @return makerAddresses The extracted maker addresses.
     function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index 6350c019f..20397b14f 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -5,7 +5,6 @@ import { BigNumber } from '@0x/utils';
 import { Web3Wrapper } from '@0x/web3-wrapper';
 import * as chai from 'chai';
 import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import {
@@ -21,12 +20,9 @@ import {
     ContractName,
     ERC20BalancesByOwner,
     expectTransactionFailedAsync,
-    expectTransactionFailedWithoutReasonAsync,
     OrderFactory,
     OrderStatus,
-    orderUtils,
     provider,
-    SignedTransaction,
     TransactionFactory,
     txDefaults,
     web3Wrapper,
@@ -77,7 +73,6 @@ describe(ContractName.BalanceThresholdFilter, () => {
     let defaultOrderParams: Partial<Order>;
     let validSignedOrder: SignedOrder;
     let validSignedOrder2: SignedOrder;
-    let validSignedFillOrderTx: SignedTransaction;
 
     let erc721BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
     let erc20BalanceThresholdFilterInstance: BalanceThresholdFilterContract;
@@ -257,10 +252,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [
-                validSignedOrder.makerAddress,
-                validTakerAddress,
-            ];
+            const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
@@ -308,7 +300,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
                     badSelectorHex,
                     signatureHex,
                 ),
-                RevertReason.InvalidOrBlockedExchangeSelector
+                RevertReason.InvalidOrBlockedExchangeSelector,
             );
         });
         it('should revert if senderAddress is not set to the valid forwarding contract', async () => {
@@ -319,12 +311,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
             });
             // Call valid forwarder
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.fillOrderAsync(
-                    signedOrderWithBadSenderAddress,
-                    validTakerAddress,
-                    { takerAssetFillAmount },
-                ),
-                RevertReason.FailedExecution
+                erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadSenderAddress, validTakerAddress, {
+                    takerAssetFillAmount,
+                }),
+                RevertReason.FailedExecution,
             );
         });
     });
@@ -339,11 +329,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
             // Execute a valid fill
             const orders = [validSignedOrder, validSignedOrder2];
             const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount];
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(
-                orders,
-                validTakerAddress,
-                { takerAssetFillAmounts },
-            );
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, {
+                takerAssetFillAmounts,
+            });
             // Assert validated addresses
             const expectedValidatedAddresseses = [
                 validSignedOrder.makerAddress,
@@ -647,10 +635,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [
-                validSignedOrder.makerAddress,
-                validTakerAddress,
-            ];
+            const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
@@ -693,11 +678,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
             });
             // Execute transaction
             return expectTransactionFailedAsync(
-                erc721TakerBalanceThresholdWrapper.fillOrderAsync(
-                    signedOrderWithBadMakerAddress,
-                    validTakerAddress,
-                    { takerAssetFillAmount },
-                ),
+                erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadMakerAddress, validTakerAddress, {
+                    takerAssetFillAmount,
+                }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
@@ -724,10 +707,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 { takerAssetFillAmount },
             );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [
-                validSignedOrder.makerAddress,
-                validTakerAddress,
-            ];
+            const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
@@ -780,11 +760,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(
-                    validSignedOrder,
-                    invalidAddress,
-                    { takerAssetFillAmount },
-                ),
+                erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(validSignedOrder, invalidAddress, {
+                    takerAssetFillAmount,
+                }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
@@ -804,10 +782,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 { takerAssetFillAmount: takerAssetFillAmount_ },
             );
             // Assert validated addresses
-            const expectedValidatedAddresseses = [
-                validSignedOrder.makerAddress,
-                validTakerAddress,
-            ];
+            const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
             await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses);
             // Check balances
             const newBalances = await erc20Wrapper.getBalancesAsync();
@@ -860,11 +835,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
         });
         it('should revert if taker does not meet the balance threshold', async () => {
             return expectTransactionFailedAsync(
-                erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(
-                    validSignedOrder,
-                    invalidAddress,
-                    { takerAssetFillAmount },
-                ),
+                erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, invalidAddress, {
+                    takerAssetFillAmount,
+                }),
                 RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold,
             );
         });
@@ -916,14 +889,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
             expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
-                    validSignedOrder.makerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
             );
             expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
-                    validSignedOrder.takerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount),
             );
             expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
@@ -1018,14 +987,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
             // Maker #1
             expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
-                    validSignedOrder.makerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
             );
             expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
-                    validSignedOrder.takerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount),
             );
             expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
@@ -1097,11 +1062,9 @@ describe(ContractName.BalanceThresholdFilter, () => {
                 .times(validSignedOrder.makerAssetAmount)
                 .dividedToIntegerBy(validSignedOrder.takerAssetAmount);
             const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2);
-            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(
-                orders,
-                validTakerAddress,
-                { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
-            );
+            const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, {
+                makerAssetFillAmount: cumulativeMakerAssetFillAmount,
+            });
             // Assert validated addresses
             const expectedValidatedAddresseses = [
                 validSignedOrder.makerAddress,
@@ -1120,14 +1083,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
             expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
-                    validSignedOrder.makerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
             );
             expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
-                    validSignedOrder.takerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount),
             );
             expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
@@ -1224,14 +1183,10 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2);
             // Maker #1
             expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(
-                    validSignedOrder.makerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount),
             );
             expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
-                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(
-                    validSignedOrder.takerAssetAmount,
-                ),
+                erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount),
             );
             expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal(
                 erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee),
-- 
cgit v1.2.3


From bb4ce9b3ad5658b16027c53cb4bad07149dcff4e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 16:02:13 -0800
Subject: Explicit returns

---
 .../BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol          | 1 +
 .../contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol          | 2 ++
 2 files changed, 3 insertions(+)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 27767ad98..3e292c035 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -129,5 +129,6 @@ contract MixinBalanceThresholdFilterCore is
             revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
         }
         // solhint-enable expression-indent
+        return addressesToValidate;
     }
 }
diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
index d49b7123f..bd26a468f 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol
@@ -50,6 +50,7 @@ contract MixinExchangeCalldata is
             let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
             value := calldataload(exchangeCalldataOffset)
         }
+        return value;
     }
 
     /// @dev Convenience function that skips the 4 byte selector when loading
@@ -61,6 +62,7 @@ contract MixinExchangeCalldata is
         returns (bytes32 value)
     {
         value = exchangeCalldataload(offset + 4);
+        return value;
     }
 
     /// @dev Extracts the maker address from an order stored in the Exchange calldata
-- 
cgit v1.2.3


From 25722d81549382617df1c70e833748782ad3e3ac Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 16:10:40 -0800
Subject: Updated comment `Execute fillOrder` -> `Execute exchange function`

---
 .../BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 3e292c035..2917403bd 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -76,7 +76,7 @@ contract MixinBalanceThresholdFilterCore is
         }
         emit ValidatedAddresses(addressesToValidate);
         
-        // All addresses are valid. Execute fillOrder.
+        // All addresses are valid. Execute exchange function.
         EXCHANGE.executeTransaction(
             salt,
             signerAddress,
-- 
cgit v1.2.3


From 1de92659ee5d3cad687919bd3054d24e31461bfa Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 13 Dec 2018 18:07:29 -0800
Subject: Added Changelog for new Extensions

---
 contracts/extensions/CHANGELOG.json | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'contracts')

diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json
index 19ac770af..99bc0265e 100644
--- a/contracts/extensions/CHANGELOG.json
+++ b/contracts/extensions/CHANGELOG.json
@@ -1,4 +1,13 @@
 [
+    {
+        "timestamp": 1544753227,
+        "version": "1.0.3",
+        "changes": [
+            {
+                "note": "Added Balance Threshold Filter"
+            }
+        ]
+    },
     {
         "timestamp": 1544741676,
         "version": "1.0.2",
-- 
cgit v1.2.3


From 00f5b94d0a585ccf4b1df4c9bddb4c19eb86cfe2 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 14 Dec 2018 11:22:52 -0800
Subject: Added `gas` field so tests pass on Geth;

---
 .../test/extensions/balance_threshold_filter.ts    | 36 ++++++++++++++++++----
 1 file changed, 30 insertions(+), 6 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts
index 20397b14f..07199d60b 100644
--- a/contracts/extensions/test/extensions/balance_threshold_filter.ts
+++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts
@@ -428,7 +428,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(
                 orders,
                 validTakerAddress,
-                { takerAssetFillAmounts },
+                {
+                    takerAssetFillAmounts,
+                    // HACK(albrow): We need to hardcode the gas estimate here because
+                    // the Geth gas estimator doesn't work with the way we use
+                    // delegatecall and swallow errors.
+                    gas: 600000,
+                },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
@@ -704,7 +710,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(
                 validSignedOrder,
                 validTakerAddress,
-                { takerAssetFillAmount },
+                {
+                    takerAssetFillAmount,
+                    // HACK(albrow): We need to hardcode the gas estimate here because
+                    // the Geth gas estimator doesn't work with the way we use
+                    // delegatecall and swallow errors.
+                    gas: 600000,
+                },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress];
@@ -963,7 +975,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(
                 orders,
                 validTakerAddress,
-                { takerAssetFillAmount: cumulativeTakerAssetFillAmount },
+                {
+                    takerAssetFillAmount: cumulativeTakerAssetFillAmount,
+                    // HACK(albrow): We need to hardcode the gas estimate here because
+                    // the Geth gas estimator doesn't work with the way we use
+                    // delegatecall and swallow errors.
+                    gas: 600000,
+                },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
@@ -1163,7 +1181,13 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(
                 orders,
                 validTakerAddress,
-                { makerAssetFillAmount: cumulativeMakerAssetFillAmount },
+                {
+                    makerAssetFillAmount: cumulativeMakerAssetFillAmount,
+                    // HACK(albrow): We need to hardcode the gas estimate here because
+                    // the Geth gas estimator doesn't work with the way we use
+                    // delegatecall and swallow errors.
+                    gas: 600000,
+                },
             );
             // Assert validated addresses
             const expectedValidatedAddresseses = [
@@ -1493,7 +1517,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
             // Cancel
             const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(
                 validSignedOrders,
-                validSignedOrder.makerAddress,
+                validSignedOrders[0].makerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
@@ -1560,7 +1584,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
             const cancelOrdersUpToThisSalt = new BigNumber(1);
             const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(
                 cancelOrdersUpToThisSalt,
-                validSignedOrder.makerAddress,
+                validSignedOrders[0].makerAddress,
             );
             // Assert validated addresses
             const expectedValidatedAddresseses: string[] = [];
-- 
cgit v1.2.3


From afe200c4e1bd76d5f2dbfcb7898ca025a7bb3dd6 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 14 Dec 2018 11:26:38 -0800
Subject: Updated changelogs for new contracts

---
 contracts/extensions/CHANGELOG.json | 6 +++---
 contracts/protocol/CHANGELOG.json   | 9 +++++++++
 2 files changed, 12 insertions(+), 3 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json
index 99bc0265e..da4d9c2ba 100644
--- a/contracts/extensions/CHANGELOG.json
+++ b/contracts/extensions/CHANGELOG.json
@@ -1,10 +1,10 @@
 [
     {
-        "timestamp": 1544753227,
-        "version": "1.0.3",
+        "version": "1.1.0",
         "changes": [
             {
-                "note": "Added Balance Threshold Filter"
+                "note": "Added Balance Threshold Filter",
+                "pr": 1383
             }
         ]
     },
diff --git a/contracts/protocol/CHANGELOG.json b/contracts/protocol/CHANGELOG.json
index 5c3798a69..2dca9794a 100644
--- a/contracts/protocol/CHANGELOG.json
+++ b/contracts/protocol/CHANGELOG.json
@@ -1,4 +1,13 @@
 [
+    {
+        "version": "2.2.0",
+        "changes": [
+            {
+                "note": "Added LibAddressArray",
+                "pr": 1383
+            }
+        ]
+    },
     {
         "timestamp": 1544741676,
         "version": "2.1.59",
-- 
cgit v1.2.3


From d2a4fd570622de34a3d8e8a25735b025e3ac5f77 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 18 Dec 2018 11:36:05 -0800
Subject: Added documentation to `LibAddressArray.append` and switched `if` to
 `require` smt

---
 .../MixinBalanceThresholdFilterCore.sol                       |  7 ++++---
 contracts/libs/contracts/libs/LibAddressArray.sol             | 11 ++++++++++-
 2 files changed, 14 insertions(+), 4 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index 2917403bd..ab6989115 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -70,9 +70,10 @@ contract MixinBalanceThresholdFilterCore is
         IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
         for (uint256 i = 0; i < addressesToValidate.length; ++i) {
             uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
-            if (addressBalance < balanceThreshold) {
-                revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
-            }
+            require(
+                addressBalance >= balanceThreshold,
+                "AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
+            );
         }
         emit ValidatedAddresses(addressesToValidate);
         
diff --git a/contracts/libs/contracts/libs/LibAddressArray.sol b/contracts/libs/contracts/libs/LibAddressArray.sol
index db76ddedb..ccae2ac5f 100644
--- a/contracts/libs/contracts/libs/LibAddressArray.sol
+++ b/contracts/libs/contracts/libs/LibAddressArray.sol
@@ -45,11 +45,20 @@ library LibAddressArray {
             addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
         }
 
+        // Cases for `freeMemPtr`:
+        //  `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`
+        //  `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`
+        //  `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.
+        require(
+            freeMemPtr >= addressArrayEndPtr,
+            "INVALID_FREE_MEMORY_PTR"
+        );
+
         // If free memory begins at the end of `addressArray`
         // then we can append `addressToAppend` directly.
         // Otherwise, we must copy the array to free memory
         // before appending new values to it.
-        if (freeMemPtr != addressArrayEndPtr) {
+        if (freeMemPtr > addressArrayEndPtr) {
             LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
             assembly {
                 addressArray := freeMemPtr
-- 
cgit v1.2.3


From ca0ab385218d588aee10502e3d75ade30ad0b5d7 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 18 Dec 2018 11:53:41 -0800
Subject: Fixed solhint errors

---
 .../MixinBalanceThresholdFilterCore.sol            |  28 +--
 .../libs/contracts/libs/LibExchangeSelectors.sol   | 231 +++++++++++----------
 2 files changed, 130 insertions(+), 129 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
index ab6989115..df830f36e 100644
--- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
+++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol
@@ -98,34 +98,34 @@ contract MixinBalanceThresholdFilterCore is
         bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
         // solhint-disable expression-indent
         if (
-            exchangeFunctionSelector == batchFillOrdersSelector         ||
-            exchangeFunctionSelector == batchFillOrdersNoThrowSelector  || 
-            exchangeFunctionSelector == batchFillOrKillOrdersSelector   ||
-            exchangeFunctionSelector == marketBuyOrdersSelector         ||
-            exchangeFunctionSelector == marketBuyOrdersNoThrowSelector  ||
-            exchangeFunctionSelector == marketSellOrdersSelector        ||
-            exchangeFunctionSelector == marketSellOrdersNoThrowSelector
+            exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR              ||
+            exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR     ||
+            exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR      ||
+            exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR              ||
+            exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR     ||
+            exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR             ||
+            exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
         ) {
             addressesToValidate = loadMakerAddressesFromOrderArray(0);
             addressesToValidate = addressesToValidate.append(signerAddress);
         } else if (
-            exchangeFunctionSelector == fillOrderSelector           ||
-            exchangeFunctionSelector == fillOrderNoThrowSelector    ||
-            exchangeFunctionSelector == fillOrKillOrderSelector
+            exchangeFunctionSelector == FILL_ORDER_SELECTOR             ||
+            exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR    ||
+            exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR
         ) {
             address makerAddress = loadMakerAddressFromOrder(0);
             addressesToValidate = addressesToValidate.append(makerAddress);
             addressesToValidate = addressesToValidate.append(signerAddress);
-        } else if (exchangeFunctionSelector == matchOrdersSelector) {
+        } else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
             address leftMakerAddress = loadMakerAddressFromOrder(0);
             addressesToValidate = addressesToValidate.append(leftMakerAddress);
             address rightMakerAddress = loadMakerAddressFromOrder(1);
             addressesToValidate = addressesToValidate.append(rightMakerAddress);
             addressesToValidate = addressesToValidate.append(signerAddress);
         } else if (
-            exchangeFunctionSelector != cancelOrderSelector         && 
-            exchangeFunctionSelector != batchCancelOrdersSelector   &&
-            exchangeFunctionSelector != cancelOrdersUpToSelector
+            exchangeFunctionSelector != CANCEL_ORDER_SELECTOR           &&
+            exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR    &&
+            exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR
         ) {
             revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
         }
diff --git a/contracts/libs/contracts/libs/LibExchangeSelectors.sol b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
index 6a5344340..edb4f9cbd 100644
--- a/contracts/libs/contracts/libs/LibExchangeSelectors.sol
+++ b/contracts/libs/contracts/libs/LibExchangeSelectors.sol
@@ -21,131 +21,132 @@ pragma solidity 0.4.24;
 
 contract LibExchangeSelectors {
 
-  // allowedValidators
-  bytes4 constant allowedValidatorsSelector = 0x7b8e3514;
-  bytes4 constant allowedValidatorsSelectorGenerator = bytes4(keccak256('allowedValidators(address,address)'));
+    // solhint-disable max-line-length
+    // allowedValidators
+    bytes4 constant public ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;
+    bytes4 constant public ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256("allowedValidators(address,address)"));
 
-  // assetProxies
-  bytes4 constant assetProxiesSelector = 0x3fd3c997;
-  bytes4 constant assetProxiesSelectorGenerator = bytes4(keccak256('assetProxies(bytes4)'));
+    // assetProxies
+    bytes4 constant public ASSET_PROXIES_SELECTOR = 0x3fd3c997;
+    bytes4 constant public ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256("assetProxies(bytes4)"));
 
-  // batchCancelOrders
-  bytes4 constant batchCancelOrdersSelector = 0x4ac14782;
-  bytes4 constant batchCancelOrdersSelectorGenerator = bytes4(keccak256('batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
+    // batchCancelOrders
+    bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;
+    bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
 
-  // batchFillOrKillOrders
-  bytes4 constant batchFillOrKillOrdersSelector = 0x4d0ae546;
-  bytes4 constant batchFillOrKillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+    // batchFillOrKillOrders
+    bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;
+    bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
 
-  // batchFillOrders
-  bytes4 constant batchFillOrdersSelector = 0x297bb70b;
-  bytes4 constant batchFillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+    // batchFillOrders
+    bytes4 constant public BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;
+    bytes4 constant public BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
 
-  // batchFillOrdersNoThrow
-  bytes4 constant batchFillOrdersNoThrowSelector = 0x50dde190;
-  bytes4 constant batchFillOrdersNoThrowSelectorGenerator = bytes4(keccak256('batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
+    // batchFillOrdersNoThrow
+    bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;
+    bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
 
-  // cancelOrder
-  bytes4 constant cancelOrderSelector = 0xd46b02c3;
-  bytes4 constant cancelOrderSelectorGenerator = bytes4(keccak256('cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
+    // cancelOrder
+    bytes4 constant public CANCEL_ORDER_SELECTOR = 0xd46b02c3;
+    bytes4 constant public CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
+
+    // cancelOrdersUpTo
+    bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;
+    bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrdersUpTo(uint256)"));
+
+    // cancelled
+    bytes4 constant public CANCELLED_SELECTOR = 0x2ac12622;
+    bytes4 constant public CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256("cancelled(bytes32)"));
+
+    // currentContextAddress
+    bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;
+    bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256("currentContextAddress()"));
+
+    // executeTransaction
+    bytes4 constant public EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;
+    bytes4 constant public EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256("executeTransaction(uint256,address,bytes,bytes)"));
+
+    // fillOrKillOrder
+    bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;
+    bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
+
+    // fillOrder
+    bytes4 constant public FILL_ORDER_SELECTOR = 0xb4be83d5;
+    bytes4 constant public FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
+
+    // fillOrderNoThrow
+    bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;
+    bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
+
+    // filled
+    bytes4 constant public FILLED_SELECTOR = 0x288cdc91;
+    bytes4 constant public FILLED_SELECTOR_GENERATOR = bytes4(keccak256("filled(bytes32)"));
+
+    // getAssetProxy
+    bytes4 constant public GET_ASSET_PROXY_SELECTOR = 0x60704108;
+    bytes4 constant public GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("getAssetProxy(bytes4)"));
+
+    // getOrderInfo
+    bytes4 constant public GET_ORDER_INFO_SELECTOR = 0xc75e0a81;
+    bytes4 constant public GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
+
+    // getOrdersInfo
+    bytes4 constant public GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;
+    bytes4 constant public GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
+
+    // isValidSignature
+    bytes4 constant public IS_VALID_SIGNATURE_SELECTOR = 0x93634702;
+    bytes4 constant public IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256("isValidSignature(bytes32,address,bytes)"));
+
+    // marketBuyOrders
+    bytes4 constant public MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;
+    bytes4 constant public MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
+
+    // marketBuyOrdersNoThrow
+    bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;
+    bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
+
+    // marketSellOrders
+    bytes4 constant public MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;
+    bytes4 constant public MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
+
+    // marketSellOrdersNoThrow
+    bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;
+    bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
+
+    // matchOrders
+    bytes4 constant public MATCH_ORDERS_SELECTOR = 0x3c28d861;
+    bytes4 constant public MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)"));
+
+    // orderEpoch
+    bytes4 constant public ORDER_EPOCH_SELECTOR = 0xd9bfa73e;
+    bytes4 constant public ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256("orderEpoch(address,address)"));
+
+    // owner
+    bytes4 constant public OWNER_SELECTOR = 0x8da5cb5b;
+    bytes4 constant public OWNER_SELECTOR_GENERATOR = bytes4(keccak256("owner()"));
 
-  // cancelOrdersUpTo
-  bytes4 constant cancelOrdersUpToSelector = 0x4f9559b1;
-  bytes4 constant cancelOrdersUpToSelectorGenerator = bytes4(keccak256('cancelOrdersUpTo(uint256)'));
+    // preSign
+    bytes4 constant public PRE_SIGN_SELECTOR = 0x3683ef8e;
+    bytes4 constant public PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256("preSign(bytes32,address,bytes)"));
 
-  // cancelled
-  bytes4 constant cancelledSelector = 0x2ac12622;
-  bytes4 constant cancelledSelectorGenerator = bytes4(keccak256('cancelled(bytes32)'));
+    // preSigned
+    bytes4 constant public PRE_SIGNED_SELECTOR = 0x82c174d0;
+    bytes4 constant public PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256("preSigned(bytes32,address)"));
 
-  // currentContextAddress
-  bytes4 constant currentContextAddressSelector = 0xeea086ba;
-  bytes4 constant currentContextAddressSelectorGenerator = bytes4(keccak256('currentContextAddress()'));
+    // registerAssetProxy
+    bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;
+    bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("registerAssetProxy(address)"));
 
-  // executeTransaction
-  bytes4 constant executeTransactionSelector = 0xbfc8bfce;
-  bytes4 constant executeTransactionSelectorGenerator = bytes4(keccak256('executeTransaction(uint256,address,bytes,bytes)'));
+    // setSignatureValidatorApproval
+    bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;
+    bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256("setSignatureValidatorApproval(address,bool)"));
 
-  // fillOrKillOrder
-  bytes4 constant fillOrKillOrderSelector = 0x64a3bc15;
-  bytes4 constant fillOrKillOrderSelectorGenerator = bytes4(keccak256('fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
+    // transactions
+    bytes4 constant public TRANSACTIONS_SELECTOR = 0x642f2eaf;
+    bytes4 constant public TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256("transactions(bytes32)"));
 
-  // fillOrder
-  bytes4 constant fillOrderSelector = 0xb4be83d5;
-  bytes4 constant fillOrderSelectorGenerator = bytes4(keccak256('fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
-
-  // fillOrderNoThrow
-  bytes4 constant fillOrderNoThrowSelector = 0x3e228bae;
-  bytes4 constant fillOrderNoThrowSelectorGenerator = bytes4(keccak256('fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
-
-  // filled
-  bytes4 constant filledSelector = 0x288cdc91;
-  bytes4 constant filledSelectorGenerator = bytes4(keccak256('filled(bytes32)'));
-
-  // getAssetProxy
-  bytes4 constant getAssetProxySelector = 0x60704108;
-  bytes4 constant getAssetProxySelectorGenerator = bytes4(keccak256('getAssetProxy(bytes4)'));
-
-  // getOrderInfo
-  bytes4 constant getOrderInfoSelector = 0xc75e0a81;
-  bytes4 constant getOrderInfoSelectorGenerator = bytes4(keccak256('getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
-
-  // getOrdersInfo
-  bytes4 constant getOrdersInfoSelector = 0x7e9d74dc;
-  bytes4 constant getOrdersInfoSelectorGenerator = bytes4(keccak256('getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
-
-  // isValidSignature
-  bytes4 constant isValidSignatureSelector = 0x93634702;
-  bytes4 constant isValidSignatureSelectorGenerator = bytes4(keccak256('isValidSignature(bytes32,address,bytes)'));
-
-  // marketBuyOrders
-  bytes4 constant marketBuyOrdersSelector = 0xe5fa431b;
-  bytes4 constant marketBuyOrdersSelectorGenerator = bytes4(keccak256('marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketBuyOrdersNoThrow
-  bytes4 constant marketBuyOrdersNoThrowSelector = 0xa3e20380;
-  bytes4 constant marketBuyOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketSellOrders
-  bytes4 constant marketSellOrdersSelector = 0x7e1d9808;
-  bytes4 constant marketSellOrdersSelectorGenerator = bytes4(keccak256('marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // marketSellOrdersNoThrow
-  bytes4 constant marketSellOrdersNoThrowSelector = 0xdd1c7d18;
-  bytes4 constant marketSellOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
-
-  // matchOrders
-  bytes4 constant matchOrdersSelector = 0x3c28d861;
-  bytes4 constant matchOrdersSelectorGenerator = bytes4(keccak256('matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'));
-
-  // orderEpoch
-  bytes4 constant orderEpochSelector = 0xd9bfa73e;
-  bytes4 constant orderEpochSelectorGenerator = bytes4(keccak256('orderEpoch(address,address)'));
-
-  // owner
-  bytes4 constant ownerSelector = 0x8da5cb5b;
-  bytes4 constant ownerSelectorGenerator = bytes4(keccak256('owner()'));
-
-  // preSign
-  bytes4 constant preSignSelector = 0x3683ef8e;
-  bytes4 constant preSignSelectorGenerator = bytes4(keccak256('preSign(bytes32,address,bytes)'));
-
-  // preSigned
-  bytes4 constant preSignedSelector = 0x82c174d0;
-  bytes4 constant preSignedSelectorGenerator = bytes4(keccak256('preSigned(bytes32,address)'));
-
-  // registerAssetProxy
-  bytes4 constant registerAssetProxySelector = 0xc585bb93;
-  bytes4 constant registerAssetProxySelectorGenerator = bytes4(keccak256('registerAssetProxy(address)'));
-
-  // setSignatureValidatorApproval
-  bytes4 constant setSignatureValidatorApprovalSelector = 0x77fcce68;
-  bytes4 constant setSignatureValidatorApprovalSelectorGenerator = bytes4(keccak256('setSignatureValidatorApproval(address,bool)'));
-
-  // transactions
-  bytes4 constant transactionsSelector = 0x642f2eaf;
-  bytes4 constant transactionsSelectorGenerator = bytes4(keccak256('transactions(bytes32)'));
-
-  // transferOwnership
-  bytes4 constant transferOwnershipSelector = 0xf2fde38b;
-  bytes4 constant transferOwnershipSelectorGenerator = bytes4(keccak256('transferOwnership(address)'));
+    // transferOwnership
+    bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;
+    bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256("transferOwnership(address)"));
 }
\ No newline at end of file
-- 
cgit v1.2.3


From a650d695cede55c61aeb3a24dade828f6cc57844 Mon Sep 17 00:00:00 2001
From: Alex Browne <stephenalexbrowne@gmail.com>
Date: Tue, 18 Dec 2018 16:26:10 -0800
Subject: Fix test-publish failure in contracts packages

---
 contracts/multisig/src/index.ts                     | 2 ++
 contracts/protocol/src/index.ts                     | 1 -
 contracts/protocol/test/exchange/order_validator.ts | 5 ++---
 3 files changed, 4 insertions(+), 4 deletions(-)
 create mode 100644 contracts/multisig/src/index.ts

(limited to 'contracts')

diff --git a/contracts/multisig/src/index.ts b/contracts/multisig/src/index.ts
new file mode 100644
index 000000000..d55f08ea2
--- /dev/null
+++ b/contracts/multisig/src/index.ts
@@ -0,0 +1,2 @@
+export * from './artifacts';
+export * from './wrappers';
diff --git a/contracts/protocol/src/index.ts b/contracts/protocol/src/index.ts
index ba813e7ca..d55f08ea2 100644
--- a/contracts/protocol/src/index.ts
+++ b/contracts/protocol/src/index.ts
@@ -1,3 +1,2 @@
 export * from './artifacts';
 export * from './wrappers';
-export * from '../test/utils';
diff --git a/contracts/protocol/test/exchange/order_validator.ts b/contracts/protocol/test/exchange/order_validator.ts
index 8f53426db..39b173fdd 100644
--- a/contracts/protocol/test/exchange/order_validator.ts
+++ b/contracts/protocol/test/exchange/order_validator.ts
@@ -18,14 +18,13 @@ import * as _ from 'lodash';
 import {
     artifacts,
     ERC20ProxyContract,
-    ERC20Wrapper,
     ERC721ProxyContract,
-    ERC721Wrapper,
     ExchangeContract,
-    ExchangeWrapper,
     OrderValidatorContract,
 } from '../../src';
 
+import { ERC20Wrapper, ERC721Wrapper, ExchangeWrapper } from '../utils';
+
 chaiSetup.configure();
 const expect = chai.expect;
 const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-- 
cgit v1.2.3


From 768e1d541c445dd84395afbd0cb04a1163e3f1c7 Mon Sep 17 00:00:00 2001
From: Alex Browne <stephenalexbrowne@gmail.com>
Date: Tue, 18 Dec 2018 18:22:54 -0800
Subject: Make @0x/contracts-test-utils a dependency instead of a devDependency

---
 contracts/protocol/package.json                     | 2 +-
 contracts/protocol/src/index.ts                     | 1 +
 contracts/protocol/test/exchange/order_validator.ts | 5 +++--
 3 files changed, 5 insertions(+), 3 deletions(-)

(limited to 'contracts')

diff --git a/contracts/protocol/package.json b/contracts/protocol/package.json
index 838189371..122ce07c3 100644
--- a/contracts/protocol/package.json
+++ b/contracts/protocol/package.json
@@ -44,7 +44,6 @@
     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
     "devDependencies": {
         "@0x/abi-gen": "^1.0.19",
-        "@0x/contracts-test-utils": "^1.0.2",
         "@0x/dev-utils": "^1.0.21",
         "@0x/sol-compiler": "^1.1.16",
         "@0x/sol-cov": "^2.1.16",
@@ -75,6 +74,7 @@
         "@0x/contracts-interfaces": "^1.0.2",
         "@0x/contracts-libs": "^1.0.2",
         "@0x/contracts-multisig": "^1.0.2",
+        "@0x/contracts-test-utils": "^1.0.2",
         "@0x/contracts-tokens": "^1.0.2",
         "@0x/contracts-utils": "^1.0.2",
         "@0x/order-utils": "^3.0.7",
diff --git a/contracts/protocol/src/index.ts b/contracts/protocol/src/index.ts
index d55f08ea2..ba813e7ca 100644
--- a/contracts/protocol/src/index.ts
+++ b/contracts/protocol/src/index.ts
@@ -1,2 +1,3 @@
 export * from './artifacts';
 export * from './wrappers';
+export * from '../test/utils';
diff --git a/contracts/protocol/test/exchange/order_validator.ts b/contracts/protocol/test/exchange/order_validator.ts
index 39b173fdd..8f53426db 100644
--- a/contracts/protocol/test/exchange/order_validator.ts
+++ b/contracts/protocol/test/exchange/order_validator.ts
@@ -18,13 +18,14 @@ import * as _ from 'lodash';
 import {
     artifacts,
     ERC20ProxyContract,
+    ERC20Wrapper,
     ERC721ProxyContract,
+    ERC721Wrapper,
     ExchangeContract,
+    ExchangeWrapper,
     OrderValidatorContract,
 } from '../../src';
 
-import { ERC20Wrapper, ERC721Wrapper, ExchangeWrapper } from '../utils';
-
 chaiSetup.configure();
 const expect = chai.expect;
 const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-- 
cgit v1.2.3


From b2edd84b0e935edeadd660a44df3dbceab49e8fe Mon Sep 17 00:00:00 2001
From: Leonid Logvinov <logvinov.leon@gmail.com>
Date: Wed, 19 Dec 2018 13:29:25 +0100
Subject: Add missing contract libs to compiler.json config

---
 contracts/libs/compiler.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/libs/compiler.json b/contracts/libs/compiler.json
index cf7c52a73..31ae13fef 100644
--- a/contracts/libs/compiler.json
+++ b/contracts/libs/compiler.json
@@ -18,5 +18,5 @@
             }
         }
     },
-    "contracts": ["TestLibs", "LibOrder", "LibMath", "LibFillResults", "LibAbiEncoder", "LibEIP712"]
+    "contracts": ["TestLibs", "LibOrder", "LibMath", "LibFillResults", "LibAbiEncoder", "LibEIP712", "LibAssetProxyErrors", "LibConstants"]
 }
-- 
cgit v1.2.3


From abfb358250200f93323851bbb56120f7fdf15dc6 Mon Sep 17 00:00:00 2001
From: Leonid Logvinov <logvinov.leon@gmail.com>
Date: Wed, 19 Dec 2018 14:13:35 +0100
Subject: Add the sol-compiler watch command to all packages

---
 contracts/examples/package.json   | 3 ++-
 contracts/extensions/package.json | 3 ++-
 contracts/interfaces/package.json | 3 ++-
 contracts/libs/package.json       | 3 ++-
 contracts/multisig/package.json   | 3 ++-
 contracts/protocol/package.json   | 3 ++-
 contracts/tokens/package.json     | 3 ++-
 contracts/utils/package.json      | 3 ++-
 8 files changed, 16 insertions(+), 8 deletions(-)

(limited to 'contracts')

diff --git a/contracts/examples/package.json b/contracts/examples/package.json
index 77846241e..37b73f98c 100644
--- a/contracts/examples/package.json
+++ b/contracts/examples/package.json
@@ -13,7 +13,8 @@
         "build": "yarn pre_build && tsc -b",
         "build:ci": "yarn build",
         "pre_build": "run-s compile generate_contract_wrappers",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json
index 2d9ed4dcd..aa5cef462 100644
--- a/contracts/extensions/package.json
+++ b/contracts/extensions/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/interfaces/package.json b/contracts/interfaces/package.json
index 4d3e4b7f9..15385a154 100644
--- a/contracts/interfaces/package.json
+++ b/contracts/interfaces/package.json
@@ -10,7 +10,8 @@
         "build": "yarn pre_build && tsc -b",
         "build:ci": "yarn build",
         "pre_build": "run-s compile generate_contract_wrappers",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/libs/package.json b/contracts/libs/package.json
index fa4b6e523..ce7b97502 100644
--- a/contracts/libs/package.json
+++ b/contracts/libs/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json
index b338f67f7..2d7b4aa05 100644
--- a/contracts/multisig/package.json
+++ b/contracts/multisig/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../packages/abi-gen-templates/contract.handlebars --partials '../../packages/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/protocol/package.json b/contracts/protocol/package.json
index 122ce07c3..d37a0302a 100644
--- a/contracts/protocol/package.json
+++ b/contracts/protocol/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/tokens/package.json b/contracts/tokens/package.json
index 6f8a366dd..79afc4820 100644
--- a/contracts/tokens/package.json
+++ b/contracts/tokens/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
diff --git a/contracts/utils/package.json b/contracts/utils/package.json
index a776bdfbb..cf94af0f6 100644
--- a/contracts/utils/package.json
+++ b/contracts/utils/package.json
@@ -19,7 +19,8 @@
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
-        "compile": "sol-compiler --contracts-dir contracts",
+        "compile": "sol-compiler",
+        "watch": "sol-compiler -w",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
-- 
cgit v1.2.3


From f832e035da0b2b4b4e08cbe9028121a93a2ed0a9 Mon Sep 17 00:00:00 2001
From: Leonid Logvinov <logvinov.leon@gmail.com>
Date: Wed, 19 Dec 2018 15:40:16 +0100
Subject: Run prettier

---
 contracts/libs/compiler.json | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/libs/compiler.json b/contracts/libs/compiler.json
index 31ae13fef..349d3063b 100644
--- a/contracts/libs/compiler.json
+++ b/contracts/libs/compiler.json
@@ -18,5 +18,14 @@
             }
         }
     },
-    "contracts": ["TestLibs", "LibOrder", "LibMath", "LibFillResults", "LibAbiEncoder", "LibEIP712", "LibAssetProxyErrors", "LibConstants"]
+    "contracts": [
+        "TestLibs",
+        "LibOrder",
+        "LibMath",
+        "LibFillResults",
+        "LibAbiEncoder",
+        "LibEIP712",
+        "LibAssetProxyErrors",
+        "LibConstants"
+    ]
 }
-- 
cgit v1.2.3


From a7c3996627aaedfcd0ba37e7e15895480a0b065c Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Tue, 18 Dec 2018 12:08:11 -0800
Subject: Check if amount == 0 before doing division

---
 .../protocol/AssetProxy/MultiAssetProxy.sol        |  5 +++-
 contracts/protocol/test/asset_proxy/proxies.ts     | 32 ++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

(limited to 'contracts')

diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 42231e73b..b42aa79ee 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -182,7 +182,10 @@ contract MultiAssetProxy is
                     let totalAmount := mul(amountsElement, amount)
 
                     // Revert if multiplication resulted in an overflow
-                    if iszero(eq(div(totalAmount, amount), amountsElement)) {
+                    if and(
+                        gt(amount, 0),
+                        iszero(eq(div(totalAmount, amount), amountsElement))
+                    ) {
                         // Revert with `Error("UINT256_OVERFLOW")`
                         mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
                         mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
diff --git a/contracts/protocol/test/asset_proxy/proxies.ts b/contracts/protocol/test/asset_proxy/proxies.ts
index c4bd95905..89c8b390c 100644
--- a/contracts/protocol/test/asset_proxy/proxies.ts
+++ b/contracts/protocol/test/asset_proxy/proxies.ts
@@ -12,6 +12,7 @@ import {
 import {
     artifacts as tokensArtifacts,
     DummyERC20TokenContract,
+    DummyERC20TokenTransferEventArgs,
     DummyERC721ReceiverContract,
     DummyERC721TokenContract,
     DummyMultipleReturnERC20TokenContract,
@@ -22,6 +23,7 @@ import { assetDataUtils } from '@0x/order-utils';
 import { RevertReason } from '@0x/types';
 import { BigNumber } from '@0x/utils';
 import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
@@ -738,6 +740,36 @@ describe('Asset Transfer Proxies', () => {
                     erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
                 );
             });
+            it('should dispatch an ERC20 transfer when input amount is 0', async () => {
+                const inputAmount = constants.ZERO_AMOUNT;
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const amounts = [erc20Amount];
+                const nestedAssetData = [erc20AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts });
+                const tx = await logDecoder.getTxWithDecodedLogsAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                );
+                expect(tx.logs.length).to.be.equal(1);
+                const log = tx.logs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>;
+                const transferEventName = 'Transfer';
+                expect(log.event).to.equal(transferEventName);
+                expect(log.args._value).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                expect(newBalances).to.deep.equal(erc20Balances);
+            });
             it('should successfully transfer multiple of the same ERC20 token', async () => {
                 const inputAmount = new BigNumber(1);
                 const erc20Amount1 = new BigNumber(10);
-- 
cgit v1.2.3


From 2a2260de45925bc309b6d6baf990d5ea6a171a90 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Tue, 18 Dec 2018 15:55:24 -0800
Subject: Use more efficient check for overflow

---
 .../protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'contracts')

diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index b42aa79ee..4285725d0 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -181,11 +181,11 @@ contract MultiAssetProxy is
                     let amountsElement := calldataload(add(amountsContentsStart, i))
                     let totalAmount := mul(amountsElement, amount)
 
-                    // Revert if multiplication resulted in an overflow
-                    if and(
-                        gt(amount, 0),
-                        iszero(eq(div(totalAmount, amount), amountsElement))
-                    ) {
+                    // Revert if `amount` != 0 and multiplication resulted in an overflow 
+                    if iszero(or(
+                        iszero(amount),
+                        eq(div(totalAmount, amount), amountsElement)
+                    )) {
                         // Revert with `Error("UINT256_OVERFLOW")`
                         mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
                         mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
-- 
cgit v1.2.3


From 04729c44b451bcf4818048621c890960bb7f8afb Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 19 Dec 2018 11:27:10 -0800
Subject: Add note about input validation

---
 contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'contracts')

diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 4285725d0..5bc32c214 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -33,6 +33,9 @@ contract MultiAssetProxy is
     function ()
         external
     {
+        // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification.
+        // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively expensive
+        // and we therefore do not check for overflows in these scenarios.
         assembly {
             // The first 4 bytes of calldata holds the function selector
             let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
-- 
cgit v1.2.3


From 99e32869e602e9b01d74048af23594986aa639a1 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 19 Dec 2018 14:35:28 -0800
Subject: Use more efficient equality checks

---
 contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'contracts')

diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 5bc32c214..377325384 100644
--- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -148,7 +148,7 @@ contract MultiAssetProxy is
                 let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
 
                 // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
-                if iszero(eq(amountsLen, nestedAssetDataLen)) {
+                if sub(amountsLen, nestedAssetDataLen) {
                     // Revert with `Error("LENGTH_MISMATCH")`
                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
@@ -236,7 +236,7 @@ contract MultiAssetProxy is
 
                     // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
                     // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
-                    if iszero(eq(currentAssetProxyId, assetProxyId)) {
+                    if sub(currentAssetProxyId, assetProxyId) {
                         // Update `assetProxyId`
                         assetProxyId := currentAssetProxyId
                         // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
-- 
cgit v1.2.3


From 8e5f0f9c5cffd44108b427585e571bec9eeb1b40 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Thu, 20 Dec 2018 09:11:13 -0800
Subject: Update CHANGELOG

---
 contracts/protocol/CHANGELOG.json | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'contracts')

diff --git a/contracts/protocol/CHANGELOG.json b/contracts/protocol/CHANGELOG.json
index 2dca9794a..be374d892 100644
--- a/contracts/protocol/CHANGELOG.json
+++ b/contracts/protocol/CHANGELOG.json
@@ -5,6 +5,10 @@
             {
                 "note": "Added LibAddressArray",
                 "pr": 1383
+            },
+            {
+                "note": "Add validation and comments to MultiAssetProxy",
+                "pr": 1455
             }
         ]
     },
-- 
cgit v1.2.3


From b786836db61de22fa290d94ac3f12fe5342aecc7 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Tue, 2 Oct 2018 16:22:35 -0700
Subject: feat: Add OrderMatcher contract that takes spread in multiple assets
 by calling `matchOrders` followed by `fillOrder`

---
 contracts/extensions/compiler.json                 |   2 +-
 .../contracts/OrderMatcher/MixinAssets.sol         | 192 ++++++++++++
 .../contracts/OrderMatcher/MixinMatchOrders.sol    | 323 +++++++++++++++++++++
 .../contracts/OrderMatcher/OrderMatcher.sol        |  37 +++
 .../contracts/OrderMatcher/interfaces/IAssets.sol  |  43 +++
 .../OrderMatcher/interfaces/IMatchOrders.sol       |  43 +++
 .../OrderMatcher/interfaces/IOrderMatcher.sol      |  31 ++
 .../contracts/OrderMatcher/libs/LibConstants.sol   |  53 ++++
 .../contracts/OrderMatcher/mixins/MAssets.sol      |  71 +++++
 contracts/protocol/src/artifacts/index.ts          |   2 +
 10 files changed, 796 insertions(+), 1 deletion(-)
 create mode 100644 contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
 create mode 100644 contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol

(limited to 'contracts')

diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json
index e6ed0c215..1e21e6e6a 100644
--- a/contracts/extensions/compiler.json
+++ b/contracts/extensions/compiler.json
@@ -18,5 +18,5 @@
             }
         }
     },
-    "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder"]
+    "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher"]
 }
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
new file mode 100644
index 000000000..a2bc95e4b
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
@@ -0,0 +1,192 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../utils/LibBytes/LibBytes.sol";
+import "../../utils/Ownable/Ownable.sol";
+import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../tokens/ERC721Token/IERC721Token.sol";
+import "./mixins/MAssets.sol";
+import "./libs/LibConstants.sol";
+
+
+contract MixinAssets is
+    MAssets,
+    Ownable,
+    LibConstants
+{
+    using LibBytes for bytes;
+
+    /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to 
+    ///      function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
+    ///      used to withdraw assets that were accidentally sent to this contract.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to withdraw.
+    function withdrawAsset(
+        bytes assetData,
+        uint256 amount
+    )
+        external
+        onlyOwner
+    {
+        transferAssetToSender(assetData, amount);
+    }
+
+    /// @dev Approves or disapproves an AssetProxy to spend asset.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveAssetProxy(
+        bytes assetData,
+        uint256 amount
+    )
+        external
+        onlyOwner
+    {
+        bytes4 proxyId = assetData.readBytes4(0);
+
+        if (proxyId == ERC20_DATA_ID) {
+            approveERC20Token(assetData, amount);
+        } else if (proxyId == ERC721_DATA_ID) {
+            approveERC721Token(assetData, amount);
+        } else {
+            revert("UNSUPPORTED_ASSET_PROXY");
+        }
+    }
+
+    /// @dev Transfers given amount of asset to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferAssetToSender(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal
+    {
+        bytes4 proxyId = assetData.readBytes4(0);
+
+        if (proxyId == ERC20_DATA_ID) {
+            transferERC20Token(assetData, amount);
+        } else if (proxyId == ERC721_DATA_ID) {
+            transferERC721Token(assetData, amount);
+        } else {
+            revert("UNSUPPORTED_ASSET_PROXY");
+        }
+    }
+
+    /// @dev Decodes ERC20 assetData and transfers given amount to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferERC20Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal
+    {
+        address token = assetData.readAddress(16);
+
+        // Transfer tokens.
+        // We do a raw call so we can check the success separate
+        // from the return data.
+        bool success = token.call(abi.encodeWithSelector(
+            ERC20_TRANSFER_SELECTOR,
+            msg.sender,
+            amount
+        ));
+        require(
+            success,
+            "TRANSFER_FAILED"
+        );
+        
+        // Check return data.
+        // If there is no return data, we assume the token incorrectly
+        // does not return a bool. In this case we expect it to revert
+        // on failure, which was handled above.
+        // If the token does return data, we require that it is a single
+        // value that evaluates to true.
+        assembly {
+            if returndatasize {
+                success := 0
+                if eq(returndatasize, 32) {
+                    // First 64 bytes of memory are reserved scratch space
+                    returndatacopy(0, 0, 32)
+                    success := mload(0)
+                }
+            }
+        }
+        require(
+            success,
+            "TRANSFER_FAILED"
+        );
+    }
+
+    /// @dev Decodes ERC721 assetData and transfers given amount to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferERC721Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal
+    {
+        require(
+            amount == 1,
+            "INVALID_AMOUNT"
+        );
+        // Decode asset data.
+        address token = assetData.readAddress(16);
+        uint256 tokenId = assetData.readUint256(36);
+
+        // Perform transfer.
+        IERC721Token(token).transferFrom(
+            address(this),
+            msg.sender,
+            tokenId
+        );
+    }
+
+    /// @dev Sets approval for ERC20 AssetProxy.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveERC20Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal
+    {
+        address token = assetData.readAddress(16);
+        require(
+            IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount),
+            "APPROVAL_FAILED"
+        );
+    }
+
+    /// @dev Sets approval for ERC721 AssetProxy.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveERC721Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal
+    {
+        address token = assetData.readAddress(16);
+        bool approval = amount >= 1;
+        IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval);
+    }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
new file mode 100644
index 000000000..1c7cce675
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -0,0 +1,323 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../utils/Ownable/Ownable.sol";
+import "./libs/LibConstants.sol";
+
+
+contract MixinMatchOrders is
+    Ownable,
+    LibConstants
+{        
+    // The below assembly in the fallback function is functionaly equivalent to the following Solidity code:
+    /*
+        /// @dev Match two complementary orders that have a profitable spread.
+        ///      Each order is filled at their respective price point. However, the calculations are
+        ///      carried out as though the orders are both being filled at the right order's price point.
+        ///      The profit made by the left order is then used to fill the right order as much as possible.
+        ///      This results in a spread being taken in terms of both assets. The spread is held within this contract.
+        /// @param leftOrder First order to match.
+        /// @param rightOrder Second order to match.
+        /// @param leftSignature Proof that order was created by the left maker.
+        /// @param rightSignature Proof that order was created by the right maker.
+        function matchOrders(
+            LibOrder.Order memory leftOrder,
+            LibOrder.Order memory rightOrder,
+            bytes memory leftSignature,
+            bytes memory rightSignature
+        )
+            public
+            onlyOwner
+        {
+            // Match orders, maximally filling `leftOrder`
+            LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
+                leftOrder,
+                rightOrder,
+                leftSignature,
+                rightSignature
+            );
+
+            // If a spread was taken, use the spread to fill remaining amount of `rightOrder`
+            // Only attempt to fill `rightOrder` if a spread was taken and if not already completely filled
+            uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
+            if (leftMakerAssetSpreadAmount > 0 && matchedFillResults.right.takerAssetFilledAmount < rightOrder.takerAssetAmount) {
+                // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
+                rightOrder.makerAssetData = leftOrder.takerAssetData;
+                rightOrder.takerAssetData = leftOrder.makerAssetData;
+
+                // We do not need to pass in a signature since it was already validated in the `matchOrders` call
+                EXCHANGE.fillOrder(
+                    rightOrder,
+                    leftMakerAssetSpreadAmount,
+                    ""
+                );
+            }
+        }
+    */
+    // solhint-disable-next-line payable-fallback
+    function ()
+        external
+    {
+        assembly {
+            // The first 4 bytes of calldata holds the function selector
+            // `matchOrders` selector = 0x3c28d861
+            if eq(
+                and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000),
+                0x3c28d86100000000000000000000000000000000000000000000000000000000
+            ) {
+
+                // Load address of `owner`
+                let owner := sload(owner_slot)
+
+                // Revert if `msg.sender` != `owner`
+                if iszero(eq(owner, caller)) {
+                    // Revert with `Error("ONLY_CONTRACT_OWNER")`
+                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                    mstore(64, 0x000000134f4e4c595f434f4e54524143545f4f574e4552000000000000000000)
+                    mstore(96, 0)
+                    revert(0, 100)
+                }
+
+                // Load address of Exchange contract
+                let exchange := sload(EXCHANGE_slot)
+
+                // Copy calldata to memory
+                // The calldata should be identical to the the ABIv2 encoded data required to call `EXCHANGE.matchOrders`
+                calldatacopy(0, 0, calldatasize())
+
+                // At this point, calldata and memory have the following layout:
+
+                // | Offset                    | Length  | Contents                                    |
+                // |---------------------------|---------|-------------------------------------------- |
+                // | 0                         | 4       | `matchOrders` function selector             |
+                // |                           | 4 * 32  | function parameters:                        |
+                // | 4                         |         |   1. offset to leftOrder (*)                |
+                // | 36                        |         |   2. offset to rightOrder (*)               |
+                // | 68                        |         |   3. offset to leftSignature (*)            |
+                // | 100                       |         |   4. offset to rightSignature (*)           |
+                // |                           | 12 * 32 | leftOrder:                                  |
+                // | 132                       |         |   1.  senderAddress                         |
+                // | 164                       |         |   2.  makerAddress                          |
+                // | 196                       |         |   3.  takerAddress                          |
+                // | 228                       |         |   4.  feeRecipientAddress                   |
+                // | 260                       |         |   5.  makerAssetAmount                      |
+                // | 292                       |         |   6.  takerAssetAmount                      |
+                // | 324                       |         |   7.  makerFeeAmount                        |
+                // | 356                       |         |   8.  takerFeeAmount                        |
+                // | 388                       |         |   9.  expirationTimeSeconds                 |
+                // | 420                       |         |   10. salt                                  |
+                // | 452                       |         |   11. offset to leftMakerAssetData (*)      |
+                // | 484                       |         |   12. offset to leftTakerAssetData (*)      |
+                // |                           | 12 * 32 | rightOrder:                                 |
+                // | 516                       |         |   1.  senderAddress                         |
+                // | 548                       |         |   2.  makerAddress                          |
+                // | 580                       |         |   3.  takerAddress                          |
+                // | 612                       |         |   4.  feeRecipientAddress                   |
+                // | 644                       |         |   5.  makerAssetAmount                      |
+                // | 676                       |         |   6.  takerAssetAmount                      |
+                // | 708                       |         |   7.  makerFeeAmount                        |
+                // | 740                       |         |   8.  takerFeeAmount                        |
+                // | 772                       |         |   9.  expirationTimeSeconds                 |
+                // | 804                       |         |   10. salt                                  |
+                // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
+                // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
+                // | 900                       | 32      | leftMakerAssetData Length                   |
+                // | 932                       | a       | leftMakerAssetData Contents                 |
+                // | 932 + a                   | 32      | leftTakerAssetData Length                   |
+                // | 964 + a                   | b       | leftTakerAssetData Contents                 |
+                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
+                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
+                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
+                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
+                // | 1028 + a + b + c + d      | 32      | leftSignature Length                        |
+                // | 1060 + a + b + c + d      | e       | leftSignature Contents                      |
+                // | 1060 + a + b + c + d + e  | 32      | rightSignature Length                       |
+                // | 1092 + a + b + c + d + e  | f       | rightSignature Contents                     |
+
+                // Call `EXCHANGE.matchOrders`
+                let matchOrdersSuccess := call(
+                    gas,             // forward all gas
+                    exchange,        // call address of Exchange contract
+                    0,               // transfer 0 wei
+                    0,               // input starts at 0
+                    calldatasize(),  // length of input
+                    0,               // write output over output
+                    288              // length of output is 288 bytes
+                )
+
+                if iszero(matchOrdersSuccess) {
+                    // Revert with reason if `matchOrders` call was unsuccessful
+                    revert(0, returndatasize())
+                }
+
+                // After calling `matchOrders`, the relevant parts of memory are:
+
+                // | Offset                    | Length  | Contents                                    |
+                // |---------------------------|---------|-------------------------------------------- |
+                // |                           | 9 * 32  | matchedFillResults                          |
+                // | 0                         |         |   1. left.makerAssetFilledAmount            |
+                // | 32                        |         |   2. left.takerAssetFilledAmount            |
+                // | 64                        |         |   3. left.makerFeePaid                      |
+                // | 96                        |         |   4. left.takerFeePaid                      |
+                // | 128                       |         |   5. right.makerAssetFilledAmount           |
+                // | 160                       |         |   6. right.takerAssetFilledAmount           |
+                // | 192                       |         |   7. right.makerFeePaid                     |
+                // | 224                       |         |   8. right.takerFeePaid                     |
+                // | 256                       |         |   9. leftMakerAssetSpreadAmount             |
+                // |                           | 12 * 32 | rightOrder:                                 |
+                // | 516                       |         |   1.  senderAddress                         |
+                // | 548                       |         |   2.  makerAddress                          |
+                // | 580                       |         |   3.  takerAddress                          |
+                // | 612                       |         |   4.  feeRecipientAddress                   |
+                // | 644                       |         |   5.  makerAssetAmount                      |
+                // | 676                       |         |   6.  takerAssetAmount                      |
+                // | 708                       |         |   7.  makerFeeAmount                        |
+                // | 740                       |         |   8.  takerFeeAmount                        |
+                // | 772                       |         |   9.  expirationTimeSeconds                 |
+                // | 804                       |         |   10. salt                                  |
+                // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
+                // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
+
+                let rightOrderStart := add(calldataload(36), 4)
+
+                // Only call `fillOrder` if a spread was taken and `rightOrder` has not been completely filled
+                if and(
+                    gt(mload(256), 0),                                       // gt(leftMakerAssetSpreadAmount, 0)
+                    lt(mload(160), calldataload(add(rightOrderStart, 160)))  // lt(rightOrderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
+                ) {
+                    
+                    // We want the following layout in memory before calling `fillOrder`:
+
+                    // | Offset                    | Length  | Contents                                    |
+                    // |---------------------------|---------|-------------------------------------------- |
+                    // | 416                       | 4       | `fillOrder` function selector               |
+                    // |                           | 3 * 32  | function parameters:                        |
+                    // | 420                       |         |   1. offset to rightOrder (*)               |
+                    // | 452                       |         |   2. takerAssetFillAmount                   |
+                    // | 484                       |         |   3. offset to rightSignature (*)           |
+                    // |                           | 12 * 32 | rightOrder:                                 |
+                    // | 516                       |         |   1.  senderAddress                         |
+                    // | 548                       |         |   2.  makerAddress                          |
+                    // | 580                       |         |   3.  takerAddress                          |
+                    // | 612                       |         |   4.  feeRecipientAddress                   |
+                    // | 644                       |         |   5.  makerAssetAmount                      |
+                    // | 676                       |         |   6.  takerAssetAmount                      |
+                    // | 708                       |         |   7.  makerFeeAmount                        |
+                    // | 740                       |         |   8.  takerFeeAmount                        |
+                    // | 772                       |         |   9.  expirationTimeSeconds                 |
+                    // | 804                       |         |   10. salt                                  |
+                    // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
+                    // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
+                    // | 900                       | 32      | rightMakerAssetData Length                  |
+                    // | 932                       | a       | rightMakerAssetData Contents                |
+                    // | 932 + a                   | 32      | rightTakerAssetData Length                  |
+                    // | 964                       | b       | rightTakerAssetData Contents                |
+                    // | 964 + b                   | 32      | rightSigature Length (always 0)             |
+
+                    // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
+                    // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
+                    // that the `rightMakerAssetData` and `rightTakerAssetData` in calldata are empty
+
+                    let leftOrderStart := add(calldataload(4), 4)
+
+                    // Calculate locations of `leftMakerAssetData` and `leftTakerAssetData` in calldata
+                    let leftMakerAssetDataStart := add(
+                        leftOrderStart,
+                        calldataload(add(leftOrderStart, 320))  // offset to `leftMakerAssetData`
+                    )
+                    let leftTakerAssetDataStart := add(
+                        leftOrderStart,
+                        calldataload(add(leftOrderStart, 352))  // offset to `leftTakerAssetData`
+                    )
+
+                    // Load lengths of `leftMakerAssetData` and `leftTakerAssetData`
+                    let leftMakerAssetDataLen := calldataload(leftMakerAssetDataStart)
+                    let leftTakerAssetDataLen := calldataload(leftTakerAssetDataStart)
+
+                    // Write offset to `rightMakerAssetData` 
+                    mstore(add(rightOrderStart, 320), 384)
+
+                    // Write offset to `rightTakerAssetData`
+                    let rightTakerAssetDataOffset := add(416, leftTakerAssetDataLen)
+                    mstore(add(rightOrderStart, 352), rightTakerAssetDataOffset)
+
+                    // Copy `leftTakerAssetData` from calldata onto `rightMakerAssetData` in memory
+                    calldatacopy(
+                        add(rightOrderStart, 384),  // `rightMakerAssetDataStart`
+                        leftTakerAssetDataStart,
+                        add(leftTakerAssetDataLen, 32)
+                    )
+
+                    // Copy `leftMakerAssetData` from calldata onto `rightTakerAssetData` in memory
+                    calldatacopy(
+                        add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
+                        leftMakerAssetDataStart,
+                        add(leftMakerAssetDataLen, 32)
+                    )
+
+                    // Write length of signature (always 0 since signature was previously validated)
+                    let rightSignatureStart := add(
+                        add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
+                        add(leftMakerAssetDataLen, 32)                    
+                    )
+                    mstore(rightSignatureStart, 0)
+
+                    let cdStart := sub(rightOrderStart, 100)
+
+                    // `fillOrder` selector = 0xb4be83d5
+                    mstore(cdStart, 0xb4be83d500000000000000000000000000000000000000000000000000000000)
+
+                    // Write offset to `rightOrder`
+                    mstore(add(cdStart, 4), 96)
+
+                    // Write `takerAssetFillAmount`
+                    mstore(add(cdStart, 36), mload(256))
+
+                    // Write offset to `rightSignature`
+                    mstore(add(cdStart, 68), sub(rightSignatureStart, add(cdStart, 4)))
+
+                    let fillOrderSuccess := call(
+                        gas,                                         // forward all gas
+                        exchange,                                    // call address of Exchange contract
+                        0,                                           // transfer 0 wei
+                        cdStart,                                     // start of input
+                        sub(add(rightSignatureStart, 32), cdStart),  // length of input is end - start
+                        0,                                           // write output over input
+                        128                                          // length of output is 128 bytes
+                    )
+
+                    if fillOrderSuccess {
+                        return(0, 0)
+                    }
+                
+                    // Revert with reason if `fillOrder` call was unsuccessful
+                    revert(0, returndatasize())
+                }
+
+                // Return if `matchOrders` call successful and `fillOrder` was not called
+                return(0, 0)
+            }
+
+            // Revert if undefined function is called
+            revert(0, 0)
+        }
+    }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
new file mode 100644
index 000000000..b6f1566cf
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
@@ -0,0 +1,37 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../utils/Ownable/Ownable.sol";
+import "./libs/LibConstants.sol";
+import "./MixinMatchOrders.sol";
+import "./MixinAssets.sol";
+
+
+// solhint-disable no-empty-blocks
+contract OrderMatcher is
+    MixinMatchOrders,
+    MixinAssets
+{
+    constructor (address _exchange)
+        public
+        LibConstants(_exchange)
+        Ownable()
+    {}
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
new file mode 100644
index 000000000..a0b3aa4c7
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol
@@ -0,0 +1,43 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+
+contract IAssets {
+
+    /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to 
+    ///      function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
+    ///      used to withdraw assets that were accidentally sent to this contract.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to withdraw.
+    function withdrawAsset(
+        bytes assetData,
+        uint256 amount
+    )
+        external;
+
+    /// @dev Approves or disapproves an AssetProxy to spend asset.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveAssetProxy(
+        bytes assetData,
+        uint256 amount
+    )
+        external;
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
new file mode 100644
index 000000000..455259238
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
@@ -0,0 +1,43 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "../../../protocol/Exchange/libs/LibOrder.sol";
+
+
+contract IMatchOrders {
+
+    /// @dev Match two complementary orders that have a profitable spread.
+    ///      Each order is filled at their respective price point. However, the calculations are
+    ///      carried out as though the orders are both being filled at the right order's price point.
+    ///      The profit made by the left order is then used to fill the right order as much as possible.
+    ///      This results in a spread being taken in terms of both assets. The spread is held within this contract.
+    /// @param leftOrder First order to match.
+    /// @param rightOrder Second order to match.
+    /// @param leftSignature Proof that order was created by the left maker.
+    /// @param rightSignature Proof that order was created by the right maker.
+    function matchOrders(
+        LibOrder.Order memory leftOrder,
+        LibOrder.Order memory rightOrder,
+        bytes memory leftSignature,
+        bytes memory rightSignature
+    )
+        public;
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
new file mode 100644
index 000000000..ed4aee925
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
@@ -0,0 +1,31 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../../utils/Ownable/IOwnable.sol";
+import "./IMatchOrders.sol";
+import "./IAssets.sol";
+
+
+// solhint-disable no-empty-blocks
+contract IOrderMatcher is
+    IOwnable,
+    IMatchOrders,
+    IAssets
+{}
diff --git a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
new file mode 100644
index 000000000..a7c170b42
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
@@ -0,0 +1,53 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../../protocol/Exchange/interfaces/IExchange.sol";
+
+
+contract LibConstants {
+
+    bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
+    bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
+    bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
+ 
+     // solhint-disable var-name-mixedcase
+    IExchange internal EXCHANGE;
+    address internal ERC20_PROXY_ADDRESS;
+    address internal ERC721_PROXY_ADDRESS;
+    // solhint-enable var-name-mixedcase
+
+    constructor (address _exchange)
+        public
+    {
+        EXCHANGE = IExchange(_exchange);
+
+        ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
+        require(
+            ERC20_PROXY_ADDRESS != address(0),
+            "UNREGISTERED_ASSET_PROXY"
+        );
+
+        ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID);
+        require(
+            ERC721_PROXY_ADDRESS != address(0),
+            "UNREGISTERED_ASSET_PROXY"
+        );
+    }
+}
diff --git a/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol
new file mode 100644
index 000000000..32cfddf1c
--- /dev/null
+++ b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol
@@ -0,0 +1,71 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../interfaces/IAssets.sol";
+
+
+contract MAssets is
+    IAssets
+{
+    /// @dev Transfers given amount of asset to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferAssetToSender(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal;
+
+    /// @dev Decodes ERC20 assetData and transfers given amount to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferERC20Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal;
+
+    /// @dev Decodes ERC721 assetData and transfers given amount to sender.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to transfer to sender.
+    function transferERC721Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal;
+
+    /// @dev Sets approval for ERC20 AssetProxy.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveERC20Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal;
+
+    /// @dev Sets approval for ERC721 AssetProxy.
+    /// @param assetData Byte array encoded for the respective asset proxy.
+    /// @param amount Amount of asset to approve for respective proxy.
+    function approveERC721Token(
+        bytes memory assetData,
+        uint256 amount
+    )
+        internal;
+}
diff --git a/contracts/protocol/src/artifacts/index.ts b/contracts/protocol/src/artifacts/index.ts
index 1d53ceb04..2a9de78d2 100644
--- a/contracts/protocol/src/artifacts/index.ts
+++ b/contracts/protocol/src/artifacts/index.ts
@@ -6,6 +6,7 @@ import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json';
 import * as Exchange from '../../generated-artifacts/Exchange.json';
 import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json';
 import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json';
+import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
 import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
 import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json';
 import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json';
@@ -20,6 +21,7 @@ export const artifacts = {
     Exchange: Exchange as ContractArtifact,
     MixinAuthorizable: MixinAuthorizable as ContractArtifact,
     MultiAssetProxy: MultiAssetProxy as ContractArtifact,
+    OrderMatcher: OrderMatcher as ContractArtifact,
     OrderValidator: OrderValidator as ContractArtifact,
     TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
     TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact,
-- 
cgit v1.2.3


From 2fa8b8d1d054015bfac49401c4f6eb5af9309603 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 17 Oct 2018 13:10:51 -0700
Subject: Add OrderMatcher tests

---
 contracts/extensions/test/extensions/forwarder.ts | 3 +--
 contracts/protocol/src/wrappers/index.ts          | 1 +
 contracts/protocol/tsconfig.json                  | 1 +
 contracts/test-utils/src/constants.ts             | 1 +
 4 files changed, 4 insertions(+), 2 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts
index 4027f493d..69939ed04 100644
--- a/contracts/extensions/test/extensions/forwarder.ts
+++ b/contracts/extensions/test/extensions/forwarder.ts
@@ -48,7 +48,6 @@ describe(ContractName.Forwarder, () => {
     let owner: string;
     let takerAddress: string;
     let feeRecipientAddress: string;
-    let otherAddress: string;
     let defaultMakerAssetAddress: string;
     let zrxAssetData: string;
     let wethAssetData: string;
@@ -78,7 +77,7 @@ describe(ContractName.Forwarder, () => {
     before(async () => {
         await blockchainLifecycle.startAsync();
         const accounts = await web3Wrapper.getAvailableAddressesAsync();
-        const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts);
+        const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
 
         const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 });
         const transaction = await web3Wrapper.getTransactionByHashAsync(txHash);
diff --git a/contracts/protocol/src/wrappers/index.ts b/contracts/protocol/src/wrappers/index.ts
index ac951d269..13f16f44f 100644
--- a/contracts/protocol/src/wrappers/index.ts
+++ b/contracts/protocol/src/wrappers/index.ts
@@ -3,6 +3,7 @@ export * from '../../generated-wrappers/erc20_proxy';
 export * from '../../generated-wrappers/erc721_proxy';
 export * from '../../generated-wrappers/exchange';
 export * from '../../generated-wrappers/mixin_authorizable';
+export * from '../../generated-wrappers/order_matcher';
 export * from '../../generated-wrappers/order_validator';
 export * from '../../generated-wrappers/test_asset_proxy_dispatcher';
 export * from '../../generated-wrappers/test_asset_proxy_owner';
diff --git a/contracts/protocol/tsconfig.json b/contracts/protocol/tsconfig.json
index 989d3ef2b..7e4ce5eb4 100644
--- a/contracts/protocol/tsconfig.json
+++ b/contracts/protocol/tsconfig.json
@@ -13,6 +13,7 @@
         "./generated-artifacts/Exchange.json",
         "./generated-artifacts/MixinAuthorizable.json",
         "./generated-artifacts/MultiAssetProxy.json",
+        "./generated-artifacts/OrderMatcher.json",
         "./generated-artifacts/OrderValidator.json",
         "./generated-artifacts/TestAssetProxyDispatcher.json",
         "./generated-artifacts/TestAssetProxyOwner.json",
diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts
index d2c3ab512..f631dc81a 100644
--- a/contracts/test-utils/src/constants.ts
+++ b/contracts/test-utils/src/constants.ts
@@ -29,6 +29,7 @@ export const constants = {
     MAX_TOKEN_TRANSFERFROM_GAS: 80000,
     MAX_TOKEN_APPROVE_GAS: 60000,
     MAX_TRANSFER_FROM_GAS: 150000,
+    MAX_MATCH_ORDERS_GAS: 400000,
     DUMMY_TOKEN_NAME: '',
     DUMMY_TOKEN_SYMBOL: '',
     DUMMY_TOKEN_DECIMALS: new BigNumber(18),
-- 
cgit v1.2.3


From b6f4c5c7da7d0afe65c0e3dba97aa64e11934595 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Sun, 9 Dec 2018 15:03:45 -0800
Subject: Fix build and add back tests

---
 contracts/core/test/extensions/order_matcher.ts    | 772 +++++++++++++++++++++
 .../contracts/OrderMatcher/MixinAssets.sol         |   4 +-
 .../contracts/OrderMatcher/MixinMatchOrders.sol    |   2 +-
 .../contracts/OrderMatcher/OrderMatcher.sol        |   2 +-
 4 files changed, 776 insertions(+), 4 deletions(-)
 create mode 100644 contracts/core/test/extensions/order_matcher.ts

(limited to 'contracts')

diff --git a/contracts/core/test/extensions/order_matcher.ts b/contracts/core/test/extensions/order_matcher.ts
new file mode 100644
index 000000000..e61d0f8e0
--- /dev/null
+++ b/contracts/core/test/extensions/order_matcher.ts
@@ -0,0 +1,772 @@
+import {
+    chaiSetup,
+    constants,
+    ERC20BalancesByOwner,
+    expectContractCreationFailedAsync,
+    expectTransactionFailedAsync,
+    LogDecoder,
+    OrderFactory,
+    provider,
+    sendTransactionResult,
+    txDefaults,
+    web3Wrapper,
+} from '@0x/contracts-test-utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { RevertReason } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
+import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
+import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
+import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
+import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange';
+import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
+import { artifacts } from '../../src/artifacts';
+import { ERC20Wrapper } from '../utils/erc20_wrapper';
+import { ExchangeWrapper } from '../utils/exchange_wrapper';
+
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+chaiSetup.configure();
+const expect = chai.expect;
+// tslint:disable:no-unnecessary-type-assertion
+describe('OrderMatcher', () => {
+    let makerAddressLeft: string;
+    let makerAddressRight: string;
+    let owner: string;
+    let takerAddress: string;
+    let feeRecipientAddressLeft: string;
+    let feeRecipientAddressRight: string;
+
+    let erc20TokenA: DummyERC20TokenContract;
+    let erc20TokenB: DummyERC20TokenContract;
+    let zrxToken: DummyERC20TokenContract;
+    let exchange: ExchangeContract;
+    let erc20Proxy: ERC20ProxyContract;
+    let erc721Proxy: ERC721ProxyContract;
+    let orderMatcher: OrderMatcherContract;
+
+    let erc20BalancesByOwner: ERC20BalancesByOwner;
+    let exchangeWrapper: ExchangeWrapper;
+    let erc20Wrapper: ERC20Wrapper;
+    let orderFactoryLeft: OrderFactory;
+    let orderFactoryRight: OrderFactory;
+
+    let leftMakerAssetData: string;
+    let leftTakerAssetData: string;
+    let defaultERC20MakerAssetAddress: string;
+    let defaultERC20TakerAssetAddress: string;
+
+    before(async () => {
+        await blockchainLifecycle.startAsync();
+    });
+    after(async () => {
+        await blockchainLifecycle.revertAsync();
+    });
+    before(async () => {
+        // Create accounts
+        const accounts = await web3Wrapper.getAvailableAddressesAsync();
+        // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
+        // but that is invalid syntax as of TypeScript version >= 2.8. We don't
+        // have the right fine-grained configuration options in TSLint,
+        // Prettier, or TypeScript, to reconcile this, so we will just have to
+        // wait for them to sort it out. We disable TSLint and Prettier for
+        // this part of the code for now. This occurs several times in this
+        // file. See https://github.com/prettier/prettier/issues/4624.
+        // prettier-ignore
+        const usedAddresses = ([
+            owner,
+            makerAddressLeft,
+            makerAddressRight,
+            takerAddress,
+            feeRecipientAddressLeft,
+            // tslint:disable-next-line:trailing-comma
+            feeRecipientAddressRight
+        ] = _.slice(accounts, 0, 6));
+        // Create wrappers
+        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
+        // Deploy ERC20 token & ERC20 proxy
+        const numDummyErc20ToDeploy = 3;
+        [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
+            numDummyErc20ToDeploy,
+            constants.DUMMY_TOKEN_DECIMALS,
+        );
+        erc20Proxy = await erc20Wrapper.deployProxyAsync();
+        await erc20Wrapper.setBalancesAndAllowancesAsync();
+        // Deploy ERC721 proxy
+        erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(artifacts.ERC721Proxy, provider, txDefaults);
+        // Depoy exchange
+        exchange = await ExchangeContract.deployFrom0xArtifactAsync(
+            artifacts.Exchange,
+            provider,
+            txDefaults,
+            assetDataUtils.encodeERC20AssetData(zrxToken.address),
+        );
+        exchangeWrapper = new ExchangeWrapper(exchange, provider);
+        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+        await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+        // Authorize ERC20 trades by exchange
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        // Deploy OrderMatcher
+        orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
+            artifacts.OrderMatcher,
+            provider,
+            txDefaults,
+            exchange.address,
+        );
+        // Set default addresses
+        defaultERC20MakerAssetAddress = erc20TokenA.address;
+        defaultERC20TakerAssetAddress = erc20TokenB.address;
+        leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
+        leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
+        // Set OrderMatcher balances and allowances
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await orderMatcher.approveAssetProxy.sendTransactionAsync(
+                leftMakerAssetData,
+                constants.INITIAL_ERC20_ALLOWANCE,
+            ),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await orderMatcher.approveAssetProxy.sendTransactionAsync(
+                leftTakerAssetData,
+                constants.INITIAL_ERC20_ALLOWANCE,
+            ),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        // Create default order parameters
+        const defaultOrderParamsLeft = {
+            ...constants.STATIC_ORDER_PARAMS,
+            makerAddress: makerAddressLeft,
+            exchangeAddress: exchange.address,
+            makerAssetData: leftMakerAssetData,
+            takerAssetData: leftTakerAssetData,
+            feeRecipientAddress: feeRecipientAddressLeft,
+            makerFee: constants.ZERO_AMOUNT,
+            takerFee: constants.ZERO_AMOUNT,
+        };
+        const defaultOrderParamsRight = {
+            ...constants.STATIC_ORDER_PARAMS,
+            makerAddress: makerAddressRight,
+            exchangeAddress: exchange.address,
+            makerAssetData: leftTakerAssetData,
+            takerAssetData: leftMakerAssetData,
+            feeRecipientAddress: feeRecipientAddressRight,
+            makerFee: constants.ZERO_AMOUNT,
+            takerFee: constants.ZERO_AMOUNT,
+        };
+        const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
+        orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
+        const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
+        orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
+    });
+    beforeEach(async () => {
+        await blockchainLifecycle.startAsync();
+    });
+    afterEach(async () => {
+        await blockchainLifecycle.revertAsync();
+    });
+    describe('constructor', () => {
+        it('should revert if assetProxy is unregistered', async () => {
+            const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
+                artifacts.Exchange,
+                provider,
+                txDefaults,
+                constants.NULL_BYTES,
+            );
+            return expectContractCreationFailedAsync(
+                (OrderMatcherContract.deployFrom0xArtifactAsync(
+                    artifacts.OrderMatcher,
+                    provider,
+                    txDefaults,
+                    exchangeInstance.address,
+                ) as any) as sendTransactionResult,
+                RevertReason.UnregisteredAssetProxy,
+            );
+        });
+    });
+    describe('matchOrders', () => {
+        beforeEach(async () => {
+            erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
+        });
+        it('should revert if not called by owner', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: takerAddress,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+        it('should transfer the correct amounts when orders completely fill each other', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+        });
+        it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
+        });
+        it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it('should not call fillOrder when rightOrder is completely filled after matchOrders call', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            const logDecoder = new LogDecoder(web3Wrapper, artifacts);
+            const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+            );
+            const fillLogs = _.filter(
+                txReceipt.logs,
+                log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
+            );
+            expect(fillLogs.length).to.be.equal(2);
+        });
+        it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
+            });
+            const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
+            const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
+                .times(signedOrderRight.makerAssetAmount)
+                .dividedToIntegerBy(signedOrderRight.takerAssetAmount);
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
+                amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
+                leftTakerAssetSpreadAmount,
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            signedOrderRight.makerAssetData = constants.NULL_BYTES;
+            signedOrderRight.takerAssetData = constants.NULL_BYTES;
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it('should revert with the correct reason if matchOrders call reverts', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.InvalidOrderSignature,
+            );
+        });
+        it('should revert with the correct reason if fillOrder call reverts', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Matcher will not have enough allowance to fill rightOrder
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
+                    from: owner,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.TransferFailed,
+            );
+        });
+    });
+    describe('withdrawAsset', () => {
+        it('should allow owner to withdraw ERC20 tokens', async () => {
+            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+                    from: owner,
+                }),
+            );
+            const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+        });
+        it('should allow owner to withdraw ERC721 tokens', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                artifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const tokenId = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
+            const withdrawAmount = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
+            expect(erc721Owner).to.be.equal(owner);
+        });
+        it('should revert if not called by owner', async () => {
+            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+            await expectTransactionFailedAsync(
+                orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+                    from: takerAddress,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+    });
+    describe('approveAssetProxy', () => {
+        it('should be able to set an allowance for ERC20 tokens', async () => {
+            const allowance = new BigNumber(55465465426546);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
+                    from: owner,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
+            expect(newAllowance).to.be.bignumber.equal(allowance);
+        });
+        it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                artifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+            const allowance = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+            expect(isApproved).to.be.equal(true);
+        });
+        it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                artifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+            const allowance = new BigNumber(2);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+            expect(isApproved).to.be.equal(true);
+        });
+        it('should revert if not called by owner', async () => {
+            const approval = new BigNumber(1);
+            await expectTransactionFailedAsync(
+                orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
+                    from: takerAddress,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+    });
+});
+// tslint:disable:max-file-line-count
+// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
index a2bc95e4b..43e19c19e 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
@@ -18,8 +18,8 @@
 
 pragma solidity 0.4.24;
 
-import "../../utils/LibBytes/LibBytes.sol";
-import "../../utils/Ownable/Ownable.sol";
+import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 import "../../tokens/ERC20Token/IERC20Token.sol";
 import "../../tokens/ERC721Token/IERC721Token.sol";
 import "./mixins/MAssets.sol";
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
index 1c7cce675..ffe037ee7 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -18,8 +18,8 @@
 
 pragma solidity 0.4.24;
 
-import "../../utils/Ownable/Ownable.sol";
 import "./libs/LibConstants.sol";
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 
 
 contract MixinMatchOrders is
diff --git a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
index b6f1566cf..7136c8c82 100644
--- a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
+++ b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
@@ -18,7 +18,7 @@
 
 pragma solidity 0.4.24;
 
-import "../../utils/Ownable/Ownable.sol";
+import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 import "./libs/LibConstants.sol";
 import "./MixinMatchOrders.sol";
 import "./MixinAssets.sol";
-- 
cgit v1.2.3


From 0a5ecec3e222ae0c5e70e0d3092e57df5dfb75cd Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 12 Dec 2018 16:44:28 -0800
Subject: update comments

---
 contracts/core/test/extensions/order_matcher.ts              | 12 ++++++------
 contracts/extensions/contracts/OrderMatcher/MixinAssets.sol  |  7 +++++--
 .../extensions/contracts/OrderMatcher/MixinMatchOrders.sol   |  5 +++--
 .../contracts/OrderMatcher/interfaces/IMatchOrders.sol       |  2 +-
 .../contracts/OrderMatcher/interfaces/IOrderMatcher.sol      |  2 +-
 .../extensions/contracts/OrderMatcher/libs/LibConstants.sol  |  2 +-
 6 files changed, 17 insertions(+), 13 deletions(-)

(limited to 'contracts')

diff --git a/contracts/core/test/extensions/order_matcher.ts b/contracts/core/test/extensions/order_matcher.ts
index e61d0f8e0..4ea95bc49 100644
--- a/contracts/core/test/extensions/order_matcher.ts
+++ b/contracts/core/test/extensions/order_matcher.ts
@@ -11,6 +11,7 @@ import {
     txDefaults,
     web3Wrapper,
 } from '@0x/contracts-test-utils';
+import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
 import { BlockchainLifecycle } from '@0x/dev-utils';
 import { assetDataUtils } from '@0x/order-utils';
 import { RevertReason } from '@0x/types';
@@ -20,8 +21,6 @@ import * as chai from 'chai';
 import { LogWithDecodedArgs } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
 import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
 import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
 import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange';
@@ -444,7 +443,7 @@ describe('OrderMatcher', () => {
                 signedOrderLeft.signature,
                 signedOrderRight.signature,
             );
-            const logDecoder = new LogDecoder(web3Wrapper, artifacts);
+            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts });
             const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
                 await web3Wrapper.sendTransactionAsync({
                     data,
@@ -457,6 +456,7 @@ describe('OrderMatcher', () => {
                 txReceipt.logs,
                 log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
             );
+            // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
             expect(fillLogs.length).to.be.equal(2);
         });
         it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
@@ -680,7 +680,7 @@ describe('OrderMatcher', () => {
         });
         it('should allow owner to withdraw ERC721 tokens', async () => {
             const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                artifacts.DummyERC721Token,
+                tokenArtifacts.DummyERC721Token,
                 provider,
                 txDefaults,
                 constants.DUMMY_TOKEN_NAME,
@@ -725,7 +725,7 @@ describe('OrderMatcher', () => {
         });
         it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
             const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                artifacts.DummyERC721Token,
+                tokenArtifacts.DummyERC721Token,
                 provider,
                 txDefaults,
                 constants.DUMMY_TOKEN_NAME,
@@ -742,7 +742,7 @@ describe('OrderMatcher', () => {
         });
         it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
             const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                artifacts.DummyERC721Token,
+                tokenArtifacts.DummyERC721Token,
                 provider,
                 txDefaults,
                 constants.DUMMY_TOKEN_NAME,
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
index 43e19c19e..323998705 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
@@ -20,8 +20,8 @@ pragma solidity 0.4.24;
 
 import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
 import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
-import "../../tokens/ERC721Token/IERC721Token.sol";
+import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
+import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
 import "./mixins/MAssets.sol";
 import "./libs/LibConstants.sol";
 
@@ -98,6 +98,7 @@ contract MixinAssets is
     )
         internal
     {
+        // 4 byte id + 12 0 bytes before ABI encoded token address.
         address token = assetData.readAddress(16);
 
         // Transfer tokens.
@@ -149,7 +150,9 @@ contract MixinAssets is
             "INVALID_AMOUNT"
         );
         // Decode asset data.
+        // 4 byte id + 12 0 bytes before ABI encoded token address.
         address token = assetData.readAddress(16);
+        // 4 byte id + 32 byte ABI encoded token address before token id.
         uint256 tokenId = assetData.readUint256(36);
 
         // Perform transfer.
diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
index ffe037ee7..866523190 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -230,7 +230,7 @@ contract MixinMatchOrders is
                     // | 932                       | a       | rightMakerAssetData Contents                |
                     // | 932 + a                   | 32      | rightTakerAssetData Length                  |
                     // | 964                       | b       | rightTakerAssetData Contents                |
-                    // | 964 + b                   | 32      | rightSigature Length (always 0)             |
+                    // | 964 + b                   | 32      | rightSignature Length (always 0)            |
 
                     // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
                     // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
@@ -280,6 +280,7 @@ contract MixinMatchOrders is
                     )
                     mstore(rightSignatureStart, 0)
 
+                    // function selector (4 bytes) + 3 params (3 * 32 bytes) must be stored before `rightOrderStart`
                     let cdStart := sub(rightOrderStart, 100)
 
                     // `fillOrder` selector = 0xb4be83d5
@@ -288,7 +289,7 @@ contract MixinMatchOrders is
                     // Write offset to `rightOrder`
                     mstore(add(cdStart, 4), 96)
 
-                    // Write `takerAssetFillAmount`
+                    // Write `takerAssetFillAmount`, which will be the `leftMakerAssetSpreadAmount` received from the `matchOrders` call
                     mstore(add(cdStart, 36), mload(256))
 
                     // Write offset to `rightSignature`
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
index 455259238..19bcbb326 100644
--- a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol
@@ -19,7 +19,7 @@
 pragma solidity 0.4.24;
 pragma experimental ABIEncoderV2;
 
-import "../../../protocol/Exchange/libs/LibOrder.sol";
+import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
 
 
 contract IMatchOrders {
diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
index ed4aee925..9b6ea26d8 100644
--- a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
+++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol
@@ -18,7 +18,7 @@
 
 pragma solidity 0.4.24;
 
-import "../../../utils/Ownable/IOwnable.sol";
+import "@0x/contract-utils/contracts/utils/Ownable/IOwnable.sol";
 import "./IMatchOrders.sol";
 import "./IAssets.sol";
 
diff --git a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
index a7c170b42..43bbdeec2 100644
--- a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
+++ b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
@@ -18,7 +18,7 @@
 
 pragma solidity 0.4.24;
 
-import "../../../protocol/Exchange/interfaces/IExchange.sol";
+import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
 
 
 contract LibConstants {
-- 
cgit v1.2.3


From 6b5b8fe8e05e497b6f4db4d3b0aa675d0bbdff50 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 12 Dec 2018 17:26:46 -0800
Subject: Fix build after rebase

---
 contracts/core/test/extensions/order_matcher.ts    | 772 --------------------
 contracts/extensions/package.json                  |   2 +-
 contracts/extensions/src/artifacts/index.ts        |   2 +
 contracts/extensions/src/wrappers/index.ts         |   1 +
 .../extensions/test/extensions/order_matcher.ts    | 780 +++++++++++++++++++++
 contracts/extensions/tsconfig.json                 |   3 +-
 contracts/protocol/src/artifacts/index.ts          |   2 -
 contracts/protocol/src/wrappers/index.ts           |   1 -
 contracts/protocol/tsconfig.json                   |   1 -
 9 files changed, 786 insertions(+), 778 deletions(-)
 delete mode 100644 contracts/core/test/extensions/order_matcher.ts
 create mode 100644 contracts/extensions/test/extensions/order_matcher.ts

(limited to 'contracts')

diff --git a/contracts/core/test/extensions/order_matcher.ts b/contracts/core/test/extensions/order_matcher.ts
deleted file mode 100644
index 4ea95bc49..000000000
--- a/contracts/core/test/extensions/order_matcher.ts
+++ /dev/null
@@ -1,772 +0,0 @@
-import {
-    chaiSetup,
-    constants,
-    ERC20BalancesByOwner,
-    expectContractCreationFailedAsync,
-    expectTransactionFailedAsync,
-    LogDecoder,
-    OrderFactory,
-    provider,
-    sendTransactionResult,
-    txDefaults,
-    web3Wrapper,
-} from '@0x/contracts-test-utils';
-import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange';
-import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
-import { artifacts } from '../../src/artifacts';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-chaiSetup.configure();
-const expect = chai.expect;
-// tslint:disable:no-unnecessary-type-assertion
-describe('OrderMatcher', () => {
-    let makerAddressLeft: string;
-    let makerAddressRight: string;
-    let owner: string;
-    let takerAddress: string;
-    let feeRecipientAddressLeft: string;
-    let feeRecipientAddressRight: string;
-
-    let erc20TokenA: DummyERC20TokenContract;
-    let erc20TokenB: DummyERC20TokenContract;
-    let zrxToken: DummyERC20TokenContract;
-    let exchange: ExchangeContract;
-    let erc20Proxy: ERC20ProxyContract;
-    let erc721Proxy: ERC721ProxyContract;
-    let orderMatcher: OrderMatcherContract;
-
-    let erc20BalancesByOwner: ERC20BalancesByOwner;
-    let exchangeWrapper: ExchangeWrapper;
-    let erc20Wrapper: ERC20Wrapper;
-    let orderFactoryLeft: OrderFactory;
-    let orderFactoryRight: OrderFactory;
-
-    let leftMakerAssetData: string;
-    let leftTakerAssetData: string;
-    let defaultERC20MakerAssetAddress: string;
-    let defaultERC20TakerAssetAddress: string;
-
-    before(async () => {
-        await blockchainLifecycle.startAsync();
-    });
-    after(async () => {
-        await blockchainLifecycle.revertAsync();
-    });
-    before(async () => {
-        // Create accounts
-        const accounts = await web3Wrapper.getAvailableAddressesAsync();
-        // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
-        // but that is invalid syntax as of TypeScript version >= 2.8. We don't
-        // have the right fine-grained configuration options in TSLint,
-        // Prettier, or TypeScript, to reconcile this, so we will just have to
-        // wait for them to sort it out. We disable TSLint and Prettier for
-        // this part of the code for now. This occurs several times in this
-        // file. See https://github.com/prettier/prettier/issues/4624.
-        // prettier-ignore
-        const usedAddresses = ([
-            owner,
-            makerAddressLeft,
-            makerAddressRight,
-            takerAddress,
-            feeRecipientAddressLeft,
-            // tslint:disable-next-line:trailing-comma
-            feeRecipientAddressRight
-        ] = _.slice(accounts, 0, 6));
-        // Create wrappers
-        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-        // Deploy ERC20 token & ERC20 proxy
-        const numDummyErc20ToDeploy = 3;
-        [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
-            numDummyErc20ToDeploy,
-            constants.DUMMY_TOKEN_DECIMALS,
-        );
-        erc20Proxy = await erc20Wrapper.deployProxyAsync();
-        await erc20Wrapper.setBalancesAndAllowancesAsync();
-        // Deploy ERC721 proxy
-        erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(artifacts.ERC721Proxy, provider, txDefaults);
-        // Depoy exchange
-        exchange = await ExchangeContract.deployFrom0xArtifactAsync(
-            artifacts.Exchange,
-            provider,
-            txDefaults,
-            assetDataUtils.encodeERC20AssetData(zrxToken.address),
-        );
-        exchangeWrapper = new ExchangeWrapper(exchange, provider);
-        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
-        await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-        // Authorize ERC20 trades by exchange
-        await web3Wrapper.awaitTransactionSuccessAsync(
-            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
-                from: owner,
-            }),
-            constants.AWAIT_TRANSACTION_MINED_MS,
-        );
-        // Deploy OrderMatcher
-        orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
-            artifacts.OrderMatcher,
-            provider,
-            txDefaults,
-            exchange.address,
-        );
-        // Set default addresses
-        defaultERC20MakerAssetAddress = erc20TokenA.address;
-        defaultERC20TakerAssetAddress = erc20TokenB.address;
-        leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
-        leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
-        // Set OrderMatcher balances and allowances
-        await web3Wrapper.awaitTransactionSuccessAsync(
-            await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
-                from: owner,
-            }),
-            constants.AWAIT_TRANSACTION_MINED_MS,
-        );
-        await web3Wrapper.awaitTransactionSuccessAsync(
-            await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
-                from: owner,
-            }),
-            constants.AWAIT_TRANSACTION_MINED_MS,
-        );
-        await web3Wrapper.awaitTransactionSuccessAsync(
-            await orderMatcher.approveAssetProxy.sendTransactionAsync(
-                leftMakerAssetData,
-                constants.INITIAL_ERC20_ALLOWANCE,
-            ),
-            constants.AWAIT_TRANSACTION_MINED_MS,
-        );
-        await web3Wrapper.awaitTransactionSuccessAsync(
-            await orderMatcher.approveAssetProxy.sendTransactionAsync(
-                leftTakerAssetData,
-                constants.INITIAL_ERC20_ALLOWANCE,
-            ),
-            constants.AWAIT_TRANSACTION_MINED_MS,
-        );
-        // Create default order parameters
-        const defaultOrderParamsLeft = {
-            ...constants.STATIC_ORDER_PARAMS,
-            makerAddress: makerAddressLeft,
-            exchangeAddress: exchange.address,
-            makerAssetData: leftMakerAssetData,
-            takerAssetData: leftTakerAssetData,
-            feeRecipientAddress: feeRecipientAddressLeft,
-            makerFee: constants.ZERO_AMOUNT,
-            takerFee: constants.ZERO_AMOUNT,
-        };
-        const defaultOrderParamsRight = {
-            ...constants.STATIC_ORDER_PARAMS,
-            makerAddress: makerAddressRight,
-            exchangeAddress: exchange.address,
-            makerAssetData: leftTakerAssetData,
-            takerAssetData: leftMakerAssetData,
-            feeRecipientAddress: feeRecipientAddressRight,
-            makerFee: constants.ZERO_AMOUNT,
-            takerFee: constants.ZERO_AMOUNT,
-        };
-        const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
-        orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
-        const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
-        orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
-    });
-    beforeEach(async () => {
-        await blockchainLifecycle.startAsync();
-    });
-    afterEach(async () => {
-        await blockchainLifecycle.revertAsync();
-    });
-    describe('constructor', () => {
-        it('should revert if assetProxy is unregistered', async () => {
-            const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
-                artifacts.Exchange,
-                provider,
-                txDefaults,
-                constants.NULL_BYTES,
-            );
-            return expectContractCreationFailedAsync(
-                (OrderMatcherContract.deployFrom0xArtifactAsync(
-                    artifacts.OrderMatcher,
-                    provider,
-                    txDefaults,
-                    exchangeInstance.address,
-                ) as any) as sendTransactionResult,
-                RevertReason.UnregisteredAssetProxy,
-            );
-        });
-    });
-    describe('matchOrders', () => {
-        beforeEach(async () => {
-            erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
-        });
-        it('should revert if not called by owner', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
-            });
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await expectTransactionFailedAsync(
-                web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: takerAddress,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                RevertReason.OnlyContractOwner,
-            );
-        });
-        it('should transfer the correct amounts when orders completely fill each other', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
-            });
-            // Match signedOrderLeft with signedOrderRight
-            const expectedTransferAmounts = {
-                // Left Maker
-                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
-                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
-                // Right Maker
-                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
-                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
-                // Taker
-                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
-            };
-            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
-            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByRightMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByRightMaker,
-                ),
-            );
-            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
-            );
-        });
-        it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-            });
-            // Match signedOrderLeft with signedOrderRight
-            const expectedTransferAmounts = {
-                // Left Maker
-                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
-                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
-                // Right Maker
-                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
-                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
-            };
-            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
-            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByRightMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByRightMaker,
-                ),
-            );
-            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
-        });
-        it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
-            });
-            // Match signedOrderLeft with signedOrderRight
-            const expectedTransferAmounts = {
-                // Left Maker
-                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
-                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
-                // Right Maker
-                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
-                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
-                // Taker
-                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
-                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
-            };
-            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            // Match signedOrderLeft with signedOrderRight
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
-            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByRightMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByRightMaker,
-                ),
-            );
-            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
-            );
-            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
-            );
-        });
-        it('should not call fillOrder when rightOrder is completely filled after matchOrders call', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-            });
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts });
-            const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-            );
-            const fillLogs = _.filter(
-                txReceipt.logs,
-                log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
-            );
-            // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
-            expect(fillLogs.length).to.be.equal(2);
-        });
-        it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
-            });
-            const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
-            const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
-                .times(signedOrderRight.makerAssetAmount)
-                .dividedToIntegerBy(signedOrderRight.takerAssetAmount);
-            // Match signedOrderLeft with signedOrderRight
-            const expectedTransferAmounts = {
-                // Left Maker
-                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
-                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
-                // Right Maker
-                amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
-                amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
-                // Taker
-                leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
-                leftTakerAssetSpreadAmount,
-            };
-            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            // Match signedOrderLeft with signedOrderRight
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
-            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByRightMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByRightMaker,
-                ),
-            );
-            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
-            );
-            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
-            );
-        });
-        it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
-            });
-            // Match signedOrderLeft with signedOrderRight
-            const expectedTransferAmounts = {
-                // Left Maker
-                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
-                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
-                // Right Maker
-                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
-                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
-                // Taker
-                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
-                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
-            };
-            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            // Match signedOrderLeft with signedOrderRight
-            signedOrderRight.makerAssetData = constants.NULL_BYTES;
-            signedOrderRight.takerAssetData = constants.NULL_BYTES;
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
-            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
-            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
-                    expectedTransferAmounts.amountSoldByRightMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByLeftMaker,
-                ),
-            );
-            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
-                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
-                    expectedTransferAmounts.amountBoughtByRightMaker,
-                ),
-            );
-            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
-            );
-            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
-                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
-            );
-        });
-        it('should revert with the correct reason if matchOrders call reverts', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-            });
-            signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await expectTransactionFailedAsync(
-                web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                RevertReason.InvalidOrderSignature,
-            );
-        });
-        it('should revert with the correct reason if fillOrder call reverts', async () => {
-            // Create orders to match
-            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-            });
-            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
-                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
-            });
-            // Matcher will not have enough allowance to fill rightOrder
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
-                    from: owner,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const data = exchange.matchOrders.getABIEncodedTransactionData(
-                signedOrderLeft,
-                signedOrderRight,
-                signedOrderLeft.signature,
-                signedOrderRight.signature,
-            );
-            await expectTransactionFailedAsync(
-                web3Wrapper.sendTransactionAsync({
-                    data,
-                    to: orderMatcher.address,
-                    from: owner,
-                    gas: constants.MAX_MATCH_ORDERS_GAS,
-                }),
-                RevertReason.TransferFailed,
-            );
-        });
-    });
-    describe('withdrawAsset', () => {
-        it('should allow owner to withdraw ERC20 tokens', async () => {
-            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
-                    from: owner,
-                }),
-            );
-            const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
-        });
-        it('should allow owner to withdraw ERC721 tokens', async () => {
-            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                tokenArtifacts.DummyERC721Token,
-                provider,
-                txDefaults,
-                constants.DUMMY_TOKEN_NAME,
-                constants.DUMMY_TOKEN_SYMBOL,
-            );
-            const tokenId = new BigNumber(1);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
-            const withdrawAmount = new BigNumber(1);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
-            expect(erc721Owner).to.be.equal(owner);
-        });
-        it('should revert if not called by owner', async () => {
-            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
-            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
-            await expectTransactionFailedAsync(
-                orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
-                    from: takerAddress,
-                }),
-                RevertReason.OnlyContractOwner,
-            );
-        });
-    });
-    describe('approveAssetProxy', () => {
-        it('should be able to set an allowance for ERC20 tokens', async () => {
-            const allowance = new BigNumber(55465465426546);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
-                    from: owner,
-                }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
-            expect(newAllowance).to.be.bignumber.equal(allowance);
-        });
-        it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
-            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                tokenArtifacts.DummyERC721Token,
-                provider,
-                txDefaults,
-                constants.DUMMY_TOKEN_NAME,
-                constants.DUMMY_TOKEN_SYMBOL,
-            );
-            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
-            const allowance = new BigNumber(1);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
-            expect(isApproved).to.be.equal(true);
-        });
-        it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
-            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
-                tokenArtifacts.DummyERC721Token,
-                provider,
-                txDefaults,
-                constants.DUMMY_TOKEN_NAME,
-                constants.DUMMY_TOKEN_SYMBOL,
-            );
-            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
-            const allowance = new BigNumber(2);
-            await web3Wrapper.awaitTransactionSuccessAsync(
-                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
-                constants.AWAIT_TRANSACTION_MINED_MS,
-            );
-            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
-            expect(isApproved).to.be.equal(true);
-        });
-        it('should revert if not called by owner', async () => {
-            const approval = new BigNumber(1);
-            await expectTransactionFailedAsync(
-                orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
-                    from: takerAddress,
-                }),
-                RevertReason.OnlyContractOwner,
-            );
-        });
-    });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json
index aa5cef462..d0caa030e 100644
--- a/contracts/extensions/package.json
+++ b/contracts/extensions/package.json
@@ -32,7 +32,7 @@
         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
     },
     "config": {
-        "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder).json"
+        "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher).json"
     },
     "repository": {
         "type": "git",
diff --git a/contracts/extensions/src/artifacts/index.ts b/contracts/extensions/src/artifacts/index.ts
index ebf0b8050..a8bd34b4e 100644
--- a/contracts/extensions/src/artifacts/index.ts
+++ b/contracts/extensions/src/artifacts/index.ts
@@ -3,9 +3,11 @@ import { ContractArtifact } from 'ethereum-types';
 import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
 import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
 import * as Forwarder from '../../generated-artifacts/Forwarder.json';
+import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
 
 export const artifacts = {
     BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
     DutchAuction: DutchAuction as ContractArtifact,
     Forwarder: Forwarder as ContractArtifact,
+    OrderMatcher: OrderMatcher as ContractArtifact,
 };
diff --git a/contracts/extensions/src/wrappers/index.ts b/contracts/extensions/src/wrappers/index.ts
index 8a8122caa..4d075ee13 100644
--- a/contracts/extensions/src/wrappers/index.ts
+++ b/contracts/extensions/src/wrappers/index.ts
@@ -1,3 +1,4 @@
 export * from '../../generated-wrappers/balance_threshold_filter';
 export * from '../../generated-wrappers/dutch_auction';
 export * from '../../generated-wrappers/forwarder';
+export * from '../../generated-wrappers/order_matcher';
diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts
new file mode 100644
index 000000000..45002b324
--- /dev/null
+++ b/contracts/extensions/test/extensions/order_matcher.ts
@@ -0,0 +1,780 @@
+import {
+    artifacts as protocolArtifacts,
+    ERC20ProxyContract,
+    ERC20Wrapper,
+    ERC721ProxyContract,
+    ExchangeContract,
+    ExchangeFillEventArgs,
+    ExchangeWrapper,
+} from '@0x/contracts-protocol';
+import {
+    chaiSetup,
+    constants,
+    ERC20BalancesByOwner,
+    expectContractCreationFailedAsync,
+    expectTransactionFailedAsync,
+    LogDecoder,
+    OrderFactory,
+    provider,
+    sendTransactionResult,
+    txDefaults,
+    web3Wrapper,
+} from '@0x/contracts-test-utils';
+import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { RevertReason } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as chai from 'chai';
+import { LogWithDecodedArgs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
+import { artifacts } from '../../src/artifacts';
+
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+chaiSetup.configure();
+const expect = chai.expect;
+// tslint:disable:no-unnecessary-type-assertion
+describe('OrderMatcher', () => {
+    let makerAddressLeft: string;
+    let makerAddressRight: string;
+    let owner: string;
+    let takerAddress: string;
+    let feeRecipientAddressLeft: string;
+    let feeRecipientAddressRight: string;
+
+    let erc20TokenA: DummyERC20TokenContract;
+    let erc20TokenB: DummyERC20TokenContract;
+    let zrxToken: DummyERC20TokenContract;
+    let exchange: ExchangeContract;
+    let erc20Proxy: ERC20ProxyContract;
+    let erc721Proxy: ERC721ProxyContract;
+    let orderMatcher: OrderMatcherContract;
+
+    let erc20BalancesByOwner: ERC20BalancesByOwner;
+    let exchangeWrapper: ExchangeWrapper;
+    let erc20Wrapper: ERC20Wrapper;
+    let orderFactoryLeft: OrderFactory;
+    let orderFactoryRight: OrderFactory;
+
+    let leftMakerAssetData: string;
+    let leftTakerAssetData: string;
+    let defaultERC20MakerAssetAddress: string;
+    let defaultERC20TakerAssetAddress: string;
+
+    before(async () => {
+        await blockchainLifecycle.startAsync();
+    });
+    after(async () => {
+        await blockchainLifecycle.revertAsync();
+    });
+    before(async () => {
+        // Create accounts
+        const accounts = await web3Wrapper.getAvailableAddressesAsync();
+        // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
+        // but that is invalid syntax as of TypeScript version >= 2.8. We don't
+        // have the right fine-grained configuration options in TSLint,
+        // Prettier, or TypeScript, to reconcile this, so we will just have to
+        // wait for them to sort it out. We disable TSLint and Prettier for
+        // this part of the code for now. This occurs several times in this
+        // file. See https://github.com/prettier/prettier/issues/4624.
+        // prettier-ignore
+        const usedAddresses = ([
+            owner,
+            makerAddressLeft,
+            makerAddressRight,
+            takerAddress,
+            feeRecipientAddressLeft,
+            // tslint:disable-next-line:trailing-comma
+            feeRecipientAddressRight
+        ] = _.slice(accounts, 0, 6));
+        // Create wrappers
+        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
+        // Deploy ERC20 token & ERC20 proxy
+        const numDummyErc20ToDeploy = 3;
+        [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
+            numDummyErc20ToDeploy,
+            constants.DUMMY_TOKEN_DECIMALS,
+        );
+        erc20Proxy = await erc20Wrapper.deployProxyAsync();
+        await erc20Wrapper.setBalancesAndAllowancesAsync();
+        // Deploy ERC721 proxy
+        erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
+            protocolArtifacts.ERC721Proxy,
+            provider,
+            txDefaults,
+        );
+        // Depoy exchange
+        exchange = await ExchangeContract.deployFrom0xArtifactAsync(
+            protocolArtifacts.Exchange,
+            provider,
+            txDefaults,
+            assetDataUtils.encodeERC20AssetData(zrxToken.address),
+        );
+        exchangeWrapper = new ExchangeWrapper(exchange, provider);
+        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+        await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+        // Authorize ERC20 trades by exchange
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        // Deploy OrderMatcher
+        orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
+            artifacts.OrderMatcher,
+            provider,
+            txDefaults,
+            exchange.address,
+        );
+        // Set default addresses
+        defaultERC20MakerAssetAddress = erc20TokenA.address;
+        defaultERC20TakerAssetAddress = erc20TokenB.address;
+        leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
+        leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
+        // Set OrderMatcher balances and allowances
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await orderMatcher.approveAssetProxy.sendTransactionAsync(
+                leftMakerAssetData,
+                constants.INITIAL_ERC20_ALLOWANCE,
+            ),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await orderMatcher.approveAssetProxy.sendTransactionAsync(
+                leftTakerAssetData,
+                constants.INITIAL_ERC20_ALLOWANCE,
+            ),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        // Create default order parameters
+        const defaultOrderParamsLeft = {
+            ...constants.STATIC_ORDER_PARAMS,
+            makerAddress: makerAddressLeft,
+            exchangeAddress: exchange.address,
+            makerAssetData: leftMakerAssetData,
+            takerAssetData: leftTakerAssetData,
+            feeRecipientAddress: feeRecipientAddressLeft,
+            makerFee: constants.ZERO_AMOUNT,
+            takerFee: constants.ZERO_AMOUNT,
+        };
+        const defaultOrderParamsRight = {
+            ...constants.STATIC_ORDER_PARAMS,
+            makerAddress: makerAddressRight,
+            exchangeAddress: exchange.address,
+            makerAssetData: leftTakerAssetData,
+            takerAssetData: leftMakerAssetData,
+            feeRecipientAddress: feeRecipientAddressRight,
+            makerFee: constants.ZERO_AMOUNT,
+            takerFee: constants.ZERO_AMOUNT,
+        };
+        const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
+        orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
+        const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
+        orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
+    });
+    beforeEach(async () => {
+        await blockchainLifecycle.startAsync();
+    });
+    afterEach(async () => {
+        await blockchainLifecycle.revertAsync();
+    });
+    describe('constructor', () => {
+        it('should revert if assetProxy is unregistered', async () => {
+            const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
+                protocolArtifacts.Exchange,
+                provider,
+                txDefaults,
+                constants.NULL_BYTES,
+            );
+            return expectContractCreationFailedAsync(
+                (OrderMatcherContract.deployFrom0xArtifactAsync(
+                    artifacts.OrderMatcher,
+                    provider,
+                    txDefaults,
+                    exchangeInstance.address,
+                ) as any) as sendTransactionResult,
+                RevertReason.UnregisteredAssetProxy,
+            );
+        });
+    });
+    describe('matchOrders', () => {
+        beforeEach(async () => {
+            erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
+        });
+        it('should revert if not called by owner', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: takerAddress,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+        it('should transfer the correct amounts when orders completely fill each other', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+        });
+        it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
+        });
+        it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it('should not call fillOrder when rightOrder is completely filled after matchOrders call', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts });
+            const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+            );
+            const fillLogs = _.filter(
+                txReceipt.logs,
+                log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
+            );
+            // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
+            expect(fillLogs.length).to.be.equal(2);
+        });
+        it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
+            });
+            const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
+            const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
+                .times(signedOrderRight.makerAssetAmount)
+                .dividedToIntegerBy(signedOrderRight.takerAssetAmount);
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
+                amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
+                leftTakerAssetSpreadAmount,
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Match signedOrderLeft with signedOrderRight
+            const expectedTransferAmounts = {
+                // Left Maker
+                amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
+                amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
+                // Right Maker
+                amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
+                amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
+                // Taker
+                leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
+                leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
+            };
+            const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            // Match signedOrderLeft with signedOrderRight
+            signedOrderRight.makerAssetData = constants.NULL_BYTES;
+            signedOrderRight.takerAssetData = constants.NULL_BYTES;
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
+            const newErc20Balances = await erc20Wrapper.getBalancesAsync();
+            expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
+                    expectedTransferAmounts.amountSoldByRightMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByLeftMaker,
+                ),
+            );
+            expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
+                erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
+                    expectedTransferAmounts.amountBoughtByRightMaker,
+                ),
+            );
+            expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
+            );
+            expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
+                initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
+            );
+        });
+        it('should revert with the correct reason if matchOrders call reverts', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+            });
+            signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.InvalidOrderSignature,
+            );
+        });
+        it('should revert with the correct reason if fillOrder call reverts', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
+            });
+            // Matcher will not have enough allowance to fill rightOrder
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
+                    from: owner,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            await expectTransactionFailedAsync(
+                web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+                RevertReason.TransferFailed,
+            );
+        });
+    });
+    describe('withdrawAsset', () => {
+        it('should allow owner to withdraw ERC20 tokens', async () => {
+            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+                    from: owner,
+                }),
+            );
+            const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+        });
+        it('should allow owner to withdraw ERC721 tokens', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                tokenArtifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const tokenId = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
+            const withdrawAmount = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
+            expect(erc721Owner).to.be.equal(owner);
+        });
+        it('should revert if not called by owner', async () => {
+            const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
+            expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
+            await expectTransactionFailedAsync(
+                orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
+                    from: takerAddress,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+    });
+    describe('approveAssetProxy', () => {
+        it('should be able to set an allowance for ERC20 tokens', async () => {
+            const allowance = new BigNumber(55465465426546);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
+                    from: owner,
+                }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
+            expect(newAllowance).to.be.bignumber.equal(allowance);
+        });
+        it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                tokenArtifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+            const allowance = new BigNumber(1);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+            expect(isApproved).to.be.equal(true);
+        });
+        it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
+            const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
+                tokenArtifacts.DummyERC721Token,
+                provider,
+                txDefaults,
+                constants.DUMMY_TOKEN_NAME,
+                constants.DUMMY_TOKEN_SYMBOL,
+            );
+            const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
+            const allowance = new BigNumber(2);
+            await web3Wrapper.awaitTransactionSuccessAsync(
+                await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
+                constants.AWAIT_TRANSACTION_MINED_MS,
+            );
+            const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
+            expect(isApproved).to.be.equal(true);
+        });
+        it('should revert if not called by owner', async () => {
+            const approval = new BigNumber(1);
+            await expectTransactionFailedAsync(
+                orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
+                    from: takerAddress,
+                }),
+                RevertReason.OnlyContractOwner,
+            );
+        });
+    });
+});
+// tslint:disable:max-file-line-count
+// tslint:enable:no-unnecessary-type-assertion
diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json
index a303e3f5c..506c283aa 100644
--- a/contracts/extensions/tsconfig.json
+++ b/contracts/extensions/tsconfig.json
@@ -9,7 +9,8 @@
     "files": [
         "./generated-artifacts/BalanceThresholdFilter.json",
         "./generated-artifacts/DutchAuction.json",
-        "./generated-artifacts/Forwarder.json"
+        "./generated-artifacts/Forwarder.json",
+        "./generated-artifacts/OrderMatcher.json"
     ],
     "exclude": ["./deploy/solc/solc_bin"]
 }
diff --git a/contracts/protocol/src/artifacts/index.ts b/contracts/protocol/src/artifacts/index.ts
index 2a9de78d2..1d53ceb04 100644
--- a/contracts/protocol/src/artifacts/index.ts
+++ b/contracts/protocol/src/artifacts/index.ts
@@ -6,7 +6,6 @@ import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json';
 import * as Exchange from '../../generated-artifacts/Exchange.json';
 import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json';
 import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json';
-import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
 import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
 import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json';
 import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json';
@@ -21,7 +20,6 @@ export const artifacts = {
     Exchange: Exchange as ContractArtifact,
     MixinAuthorizable: MixinAuthorizable as ContractArtifact,
     MultiAssetProxy: MultiAssetProxy as ContractArtifact,
-    OrderMatcher: OrderMatcher as ContractArtifact,
     OrderValidator: OrderValidator as ContractArtifact,
     TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
     TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact,
diff --git a/contracts/protocol/src/wrappers/index.ts b/contracts/protocol/src/wrappers/index.ts
index 13f16f44f..ac951d269 100644
--- a/contracts/protocol/src/wrappers/index.ts
+++ b/contracts/protocol/src/wrappers/index.ts
@@ -3,7 +3,6 @@ export * from '../../generated-wrappers/erc20_proxy';
 export * from '../../generated-wrappers/erc721_proxy';
 export * from '../../generated-wrappers/exchange';
 export * from '../../generated-wrappers/mixin_authorizable';
-export * from '../../generated-wrappers/order_matcher';
 export * from '../../generated-wrappers/order_validator';
 export * from '../../generated-wrappers/test_asset_proxy_dispatcher';
 export * from '../../generated-wrappers/test_asset_proxy_owner';
diff --git a/contracts/protocol/tsconfig.json b/contracts/protocol/tsconfig.json
index 7e4ce5eb4..989d3ef2b 100644
--- a/contracts/protocol/tsconfig.json
+++ b/contracts/protocol/tsconfig.json
@@ -13,7 +13,6 @@
         "./generated-artifacts/Exchange.json",
         "./generated-artifacts/MixinAuthorizable.json",
         "./generated-artifacts/MultiAssetProxy.json",
-        "./generated-artifacts/OrderMatcher.json",
         "./generated-artifacts/OrderValidator.json",
         "./generated-artifacts/TestAssetProxyDispatcher.json",
         "./generated-artifacts/TestAssetProxyOwner.json",
-- 
cgit v1.2.3


From e74b24bbdb1f6f53e5437ae3d3b2ebc2aa2adba6 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 17 Dec 2018 12:59:39 -0800
Subject: Update comments and hard code function selector constants

---
 .../contracts/OrderMatcher/MixinMatchOrders.sol    | 100 ++++++++++-----------
 .../contracts/OrderMatcher/libs/LibConstants.sol   |   9 +-
 2 files changed, 56 insertions(+), 53 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
index 866523190..c691b732f 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -126,23 +126,23 @@ contract MixinMatchOrders is
                 // | 420                       |         |   10. salt                                  |
                 // | 452                       |         |   11. offset to leftMakerAssetData (*)      |
                 // | 484                       |         |   12. offset to leftTakerAssetData (*)      |
+                // | 516                       | 32      | leftMakerAssetData Length                   |
+                // | 548                       | a       | leftMakerAssetData Contents                 |
+                // | 548 + a                   | 32      | leftTakerAssetData Length                   |
+                // | 580 + a                   | b       | leftTakerAssetData Contents                 |
                 // |                           | 12 * 32 | rightOrder:                                 |
-                // | 516                       |         |   1.  senderAddress                         |
-                // | 548                       |         |   2.  makerAddress                          |
-                // | 580                       |         |   3.  takerAddress                          |
-                // | 612                       |         |   4.  feeRecipientAddress                   |
-                // | 644                       |         |   5.  makerAssetAmount                      |
-                // | 676                       |         |   6.  takerAssetAmount                      |
-                // | 708                       |         |   7.  makerFeeAmount                        |
-                // | 740                       |         |   8.  takerFeeAmount                        |
-                // | 772                       |         |   9.  expirationTimeSeconds                 |
-                // | 804                       |         |   10. salt                                  |
-                // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
-                // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
-                // | 900                       | 32      | leftMakerAssetData Length                   |
-                // | 932                       | a       | leftMakerAssetData Contents                 |
-                // | 932 + a                   | 32      | leftTakerAssetData Length                   |
-                // | 964 + a                   | b       | leftTakerAssetData Contents                 |
+                // | 580 + a + b               |         |   1.  senderAddress                         |
+                // | 612 + a + b               |         |   2.  makerAddress                          |
+                // | 644 + a + b               |         |   3.  takerAddress                          |
+                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
+                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
+                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
+                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
+                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
+                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
+                // | 868 + a + b               |         |   10. salt                                  |
+                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
+                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
                 // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
                 // | 996 + a + b               | c       | rightMakerAssetData Contents                |
                 // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
@@ -159,7 +159,7 @@ contract MixinMatchOrders is
                     0,               // transfer 0 wei
                     0,               // input starts at 0
                     calldatasize(),  // length of input
-                    0,               // write output over output
+                    0,               // write output over input
                     288              // length of output is 288 bytes
                 )
 
@@ -183,18 +183,18 @@ contract MixinMatchOrders is
                 // | 224                       |         |   8. right.takerFeePaid                     |
                 // | 256                       |         |   9. leftMakerAssetSpreadAmount             |
                 // |                           | 12 * 32 | rightOrder:                                 |
-                // | 516                       |         |   1.  senderAddress                         |
-                // | 548                       |         |   2.  makerAddress                          |
-                // | 580                       |         |   3.  takerAddress                          |
-                // | 612                       |         |   4.  feeRecipientAddress                   |
-                // | 644                       |         |   5.  makerAssetAmount                      |
-                // | 676                       |         |   6.  takerAssetAmount                      |
-                // | 708                       |         |   7.  makerFeeAmount                        |
-                // | 740                       |         |   8.  takerFeeAmount                        |
-                // | 772                       |         |   9.  expirationTimeSeconds                 |
-                // | 804                       |         |   10. salt                                  |
-                // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
-                // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
+                // | 580 + a + b               |         |   1.  senderAddress                         |
+                // | 612 + a + b               |         |   2.  makerAddress                          |
+                // | 644 + a + b               |         |   3.  takerAddress                          |
+                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
+                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
+                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
+                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
+                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
+                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
+                // | 868 + a + b               |         |   10. salt                                  |
+                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
+                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
 
                 let rightOrderStart := add(calldataload(36), 4)
 
@@ -208,29 +208,29 @@ contract MixinMatchOrders is
 
                     // | Offset                    | Length  | Contents                                    |
                     // |---------------------------|---------|-------------------------------------------- |
-                    // | 416                       | 4       | `fillOrder` function selector               |
+                    // | 480 + a + b               | 4       | `fillOrder` function selector               |
                     // |                           | 3 * 32  | function parameters:                        |
-                    // | 420                       |         |   1. offset to rightOrder (*)               |
-                    // | 452                       |         |   2. takerAssetFillAmount                   |
-                    // | 484                       |         |   3. offset to rightSignature (*)           |
+                    // | 484 + a + b               |         |   1. offset to rightOrder (*)               |
+                    // | 516 + a + b               |         |   2. takerAssetFillAmount                   |
+                    // | 548 + a + b               |         |   3. offset to rightSignature (*)           |
                     // |                           | 12 * 32 | rightOrder:                                 |
-                    // | 516                       |         |   1.  senderAddress                         |
-                    // | 548                       |         |   2.  makerAddress                          |
-                    // | 580                       |         |   3.  takerAddress                          |
-                    // | 612                       |         |   4.  feeRecipientAddress                   |
-                    // | 644                       |         |   5.  makerAssetAmount                      |
-                    // | 676                       |         |   6.  takerAssetAmount                      |
-                    // | 708                       |         |   7.  makerFeeAmount                        |
-                    // | 740                       |         |   8.  takerFeeAmount                        |
-                    // | 772                       |         |   9.  expirationTimeSeconds                 |
-                    // | 804                       |         |   10. salt                                  |
-                    // | 836                       |         |   11. offset to rightMakerAssetData (*)     |
-                    // | 868                       |         |   12. offset to rightTakerAssetData (*)     |
-                    // | 900                       | 32      | rightMakerAssetData Length                  |
-                    // | 932                       | a       | rightMakerAssetData Contents                |
-                    // | 932 + a                   | 32      | rightTakerAssetData Length                  |
-                    // | 964                       | b       | rightTakerAssetData Contents                |
-                    // | 964 + b                   | 32      | rightSignature Length (always 0)            |
+                    // | 580 + a + b               |         |   1.  senderAddress                         |
+                    // | 612 + a + b               |         |   2.  makerAddress                          |
+                    // | 644 + a + b               |         |   3.  takerAddress                          |
+                    // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
+                    // | 708 + a + b               |         |   5.  makerAssetAmount                      |
+                    // | 740 + a + b               |         |   6.  takerAssetAmount                      |
+                    // | 772 + a + b               |         |   7.  makerFeeAmount                        |
+                    // | 804 + a + b               |         |   8.  takerFeeAmount                        |
+                    // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
+                    // | 868 + a + b               |         |   10. salt                                  |
+                    // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
+                    // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
+                    // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
+                    // | 996 + a + b               | c       | rightMakerAssetData Contents                |
+                    // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
+                    // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
+                    // | 1028 + a + b + c + d      | 32      | rightSignature Length (always 0)            |
 
                     // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
                     // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
diff --git a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
index 43bbdeec2..bd6a5e0ee 100644
--- a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
+++ b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol
@@ -23,9 +23,12 @@ import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
 
 contract LibConstants {
 
-    bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
-    bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
-    bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
+    // bytes4(keccak256("transfer(address,uint256)"))
+    bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
+    // bytes4(keccak256("ERC20Token(address)"))
+    bytes4 constant internal ERC20_DATA_ID = 0xf47261b0;
+    // bytes4(keccak256("ERC721Token(address,uint256)"))
+    bytes4 constant internal ERC721_DATA_ID = 0x02571792;
  
      // solhint-disable var-name-mixedcase
     IExchange internal EXCHANGE;
-- 
cgit v1.2.3


From 90fcf59a3257df91653324a48e031bdc080f841b Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 17 Dec 2018 22:07:12 -0800
Subject: Add getOrderInfo check before calling fillOrder

---
 .../contracts/OrderMatcher/MixinMatchOrders.sol    | 322 +++++++++++++--------
 .../extensions/test/extensions/order_matcher.ts    |  44 ++-
 2 files changed, 242 insertions(+), 124 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
index c691b732f..b6bc83af9 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -25,7 +25,7 @@ import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 contract MixinMatchOrders is
     Ownable,
     LibConstants
-{        
+{
     // The below assembly in the fallback function is functionaly equivalent to the following Solidity code:
     /*
         /// @dev Match two complementary orders that have a profitable spread.
@@ -54,21 +54,33 @@ contract MixinMatchOrders is
                 rightSignature
             );
 
-            // If a spread was taken, use the spread to fill remaining amount of `rightOrder`
-            // Only attempt to fill `rightOrder` if a spread was taken and if not already completely filled
             uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
-            if (leftMakerAssetSpreadAmount > 0 && matchedFillResults.right.takerAssetFilledAmount < rightOrder.takerAssetAmount) {
-                // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
-                rightOrder.makerAssetData = leftOrder.takerAssetData;
-                rightOrder.takerAssetData = leftOrder.makerAssetData;
-
-                // We do not need to pass in a signature since it was already validated in the `matchOrders` call
-                EXCHANGE.fillOrder(
-                    rightOrder,
-                    leftMakerAssetSpreadAmount,
-                    ""
-                );
+            uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
+
+            // Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
+            if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
+                return;
+            }
+
+            // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
+            rightOrder.makerAssetData = leftOrder.takerAssetData;
+            rightOrder.takerAssetData = leftOrder.makerAssetData;
+
+            // Query `rightOrder` info to check if it has been completely filled
+            // We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
+            OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
+
+            // Do not attempt to call `fillOrder` if order has been completely filled
+            if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
+                return;
             }
+
+            // We do not need to pass in a signature since it was already validated in the `matchOrders` call
+            EXCHANGE.fillOrder(
+                rightOrder,
+                leftMakerAssetSpreadAmount,
+                ""
+            );
         }
     */
     // solhint-disable-next-line payable-fallback
@@ -101,7 +113,11 @@ contract MixinMatchOrders is
 
                 // Copy calldata to memory
                 // The calldata should be identical to the the ABIv2 encoded data required to call `EXCHANGE.matchOrders`
-                calldatacopy(0, 0, calldatasize())
+                calldatacopy(
+                    0,              // copy to memory at 0
+                    0,              // copy from calldata at 0
+                    calldatasize()  // copy all calldata
+                )
 
                 // At this point, calldata and memory have the following layout:
 
@@ -153,7 +169,7 @@ contract MixinMatchOrders is
                 // | 1092 + a + b + c + d + e  | f       | rightSignature Contents                     |
 
                 // Call `EXCHANGE.matchOrders`
-                let matchOrdersSuccess := call(
+                let success := call(
                     gas,             // forward all gas
                     exchange,        // call address of Exchange contract
                     0,               // transfer 0 wei
@@ -163,12 +179,17 @@ contract MixinMatchOrders is
                     288              // length of output is 288 bytes
                 )
 
-                if iszero(matchOrdersSuccess) {
-                    // Revert with reason if `matchOrders` call was unsuccessful
+                if iszero(success) {
+                    // Revert with reason if `EXCHANGE.matchOrders` call was unsuccessful
+                    returndatacopy(
+                        0,                // copy to memory at 0
+                        0,                // copy from return data at 0
+                        returndatasize()  // copy all return data
+                    )
                     revert(0, returndatasize())
                 }
 
-                // After calling `matchOrders`, the relevant parts of memory are:
+                // After calling `matchOrders`, the return data is layed out in memory as:
 
                 // | Offset                    | Length  | Contents                                    |
                 // |---------------------------|---------|-------------------------------------------- |
@@ -182,6 +203,67 @@ contract MixinMatchOrders is
                 // | 192                       |         |   7. right.makerFeePaid                     |
                 // | 224                       |         |   8. right.takerFeePaid                     |
                 // | 256                       |         |   9. leftMakerAssetSpreadAmount             |
+
+                let rightOrderStart := add(calldataload(36), 4)
+    
+                // If no spread was taken or if the entire `rightOrderTakerAssetAmount` has been filled, there is no need to call `EXCHANGE.fillOrder`.
+                if or(
+                    iszero(mload(256)),                                      // iszero(leftMakerAssetSpreadAmount)
+                    eq(mload(160), calldataload(add(rightOrderStart, 160)))  // eq(rightOrderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
+                ) {
+                    return(0, 0)
+                }
+
+                // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
+                // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
+                // that the `rightMakerAssetData` and `rightTakerAssetData` in calldata are empty
+
+                let leftOrderStart := add(calldataload(4), 4)
+
+                // Calculate locations of `leftMakerAssetData` and `leftTakerAssetData` in calldata
+                let leftMakerAssetDataStart := add(
+                    leftOrderStart,
+                    calldataload(add(leftOrderStart, 320))  // offset to `leftMakerAssetData`
+                )
+                let leftTakerAssetDataStart := add(
+                    leftOrderStart,
+                    calldataload(add(leftOrderStart, 352))  // offset to `leftTakerAssetData`
+                )
+
+                // Load lengths of `leftMakerAssetData` and `leftTakerAssetData`
+                let leftMakerAssetDataLen := calldataload(leftMakerAssetDataStart)
+                let leftTakerAssetDataLen := calldataload(leftTakerAssetDataStart)
+
+                // Write offset to `rightMakerAssetData` 
+                mstore(add(rightOrderStart, 320), 384)
+
+                // Write offset to `rightTakerAssetData`
+                let rightTakerAssetDataOffset := add(416, leftTakerAssetDataLen)
+                mstore(add(rightOrderStart, 352), rightTakerAssetDataOffset)
+
+                // Copy `leftTakerAssetData` from calldata onto `rightMakerAssetData` in memory
+                calldatacopy(
+                    add(rightOrderStart, 384),  // `rightMakerAssetDataStart`
+                    leftTakerAssetDataStart,
+                    add(leftTakerAssetDataLen, 32)
+                )
+
+                // Copy `leftMakerAssetData` from calldata onto `rightTakerAssetData` in memory
+                calldatacopy(
+                    add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
+                    leftMakerAssetDataStart,
+                    add(leftMakerAssetDataLen, 32)
+                )
+
+                // We must call `EXCHANGE.getOrderInfo(rightOrder)` before calling `EXCHANGE.fillOrder` to ensure that the order
+                // has not already been entirely filled (which is possible if an order was partially filled before the `matchOrders` call).
+                // We want the following layout in memory before calling `getOrderInfo`:
+
+                // | Offset                    | Length  | Contents                                    |
+                // |---------------------------|---------|-------------------------------------------- |
+                // | 544 + a + b               | 4       | `getOrderInfo` function selector            |
+                // |                           | 3 * 32  | function parameters:                        |
+                // | 548 + a + b               |         |   1. offset to rightOrder (*)               |
                 // |                           | 12 * 32 | rightOrder:                                 |
                 // | 580 + a + b               |         |   1.  senderAddress                         |
                 // | 612 + a + b               |         |   2.  makerAddress                          |
@@ -195,126 +277,124 @@ contract MixinMatchOrders is
                 // | 868 + a + b               |         |   10. salt                                  |
                 // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
                 // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
+                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
+                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
+                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
+                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
 
-                let rightOrderStart := add(calldataload(36), 4)
+                // function selector (4 bytes) + 1 param (32 bytes) must be stored before `rightOrderStart`
+                let cdStart := sub(rightOrderStart, 36)
 
-                // Only call `fillOrder` if a spread was taken and `rightOrder` has not been completely filled
-                if and(
-                    gt(mload(256), 0),                                       // gt(leftMakerAssetSpreadAmount, 0)
-                    lt(mload(160), calldataload(add(rightOrderStart, 160)))  // lt(rightOrderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
-                ) {
-                    
-                    // We want the following layout in memory before calling `fillOrder`:
-
-                    // | Offset                    | Length  | Contents                                    |
-                    // |---------------------------|---------|-------------------------------------------- |
-                    // | 480 + a + b               | 4       | `fillOrder` function selector               |
-                    // |                           | 3 * 32  | function parameters:                        |
-                    // | 484 + a + b               |         |   1. offset to rightOrder (*)               |
-                    // | 516 + a + b               |         |   2. takerAssetFillAmount                   |
-                    // | 548 + a + b               |         |   3. offset to rightSignature (*)           |
-                    // |                           | 12 * 32 | rightOrder:                                 |
-                    // | 580 + a + b               |         |   1.  senderAddress                         |
-                    // | 612 + a + b               |         |   2.  makerAddress                          |
-                    // | 644 + a + b               |         |   3.  takerAddress                          |
-                    // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
-                    // | 708 + a + b               |         |   5.  makerAssetAmount                      |
-                    // | 740 + a + b               |         |   6.  takerAssetAmount                      |
-                    // | 772 + a + b               |         |   7.  makerFeeAmount                        |
-                    // | 804 + a + b               |         |   8.  takerFeeAmount                        |
-                    // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
-                    // | 868 + a + b               |         |   10. salt                                  |
-                    // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
-                    // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
-                    // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
-                    // | 996 + a + b               | c       | rightMakerAssetData Contents                |
-                    // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
-                    // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
-                    // | 1028 + a + b + c + d      | 32      | rightSignature Length (always 0)            |
-
-                    // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
-                    // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
-                    // that the `rightMakerAssetData` and `rightTakerAssetData` in calldata are empty
-
-                    let leftOrderStart := add(calldataload(4), 4)
-
-                    // Calculate locations of `leftMakerAssetData` and `leftTakerAssetData` in calldata
-                    let leftMakerAssetDataStart := add(
-                        leftOrderStart,
-                        calldataload(add(leftOrderStart, 320))  // offset to `leftMakerAssetData`
-                    )
-                    let leftTakerAssetDataStart := add(
-                        leftOrderStart,
-                        calldataload(add(leftOrderStart, 352))  // offset to `leftTakerAssetData`
-                    )
+                // `getOrderInfo` selector = 0xc75e0a81
+                mstore(cdStart, 0xc75e0a8100000000000000000000000000000000000000000000000000000000)
 
-                    // Load lengths of `leftMakerAssetData` and `leftTakerAssetData`
-                    let leftMakerAssetDataLen := calldataload(leftMakerAssetDataStart)
-                    let leftTakerAssetDataLen := calldataload(leftTakerAssetDataStart)
+                // Write offset to `rightOrder`
+                mstore(add(cdStart, 4), 32)
 
-                    // Write offset to `rightMakerAssetData` 
-                    mstore(add(rightOrderStart, 320), 384)
+                let rightOrderEnd := add(
+                    add(rightOrderStart, 484),
+                    add(leftMakerAssetDataLen, leftTakerAssetDataLen)                    
+                )
 
-                    // Write offset to `rightTakerAssetData`
-                    let rightTakerAssetDataOffset := add(416, leftTakerAssetDataLen)
-                    mstore(add(rightOrderStart, 352), rightTakerAssetDataOffset)
+                // Call `EXCHANGE.getOrderInfo(rightOrder)`
+                success := staticcall(
+                    gas,                          // forward all gas
+                    exchange,                     // call address of Exchange contract
+                    cdStart,                      // start of input
+                    sub(rightOrderEnd, cdStart),  // length of input
+                    0,                            // write output over old output
+                    96                            // output is 96 bytes
+                )
 
-                    // Copy `leftTakerAssetData` from calldata onto `rightMakerAssetData` in memory
-                    calldatacopy(
-                        add(rightOrderStart, 384),  // `rightMakerAssetDataStart`
-                        leftTakerAssetDataStart,
-                        add(leftTakerAssetDataLen, 32)
-                    )
+                // After calling `EXCHANGE.getOrderInfo`, the return data is layed out in memory as:
 
-                    // Copy `leftMakerAssetData` from calldata onto `rightTakerAssetData` in memory
-                    calldatacopy(
-                        add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
-                        leftMakerAssetDataStart,
-                        add(leftMakerAssetDataLen, 32)
-                    )
+                // | Offset                    | Length  | Contents                                    |
+                // |---------------------------|---------|-------------------------------------------- |
+                // |                           | 3 * 32  | orderInfo                                   |
+                // | 0                         |         |   1. orderStatus                            |
+                // | 32                        |         |   2. orderHash                              |
+                // | 64                        |         |   3. orderTakerAssetFilledAmount            |
+
+                // We do not need to check if the `getOrderInfo` call was successful because it has no possibility of reverting
+                // If order has been entirely filled, there is no need to call `EXCHANGE.fillOrder`
+                // eq(orderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
+                if eq(mload(64), calldataload(add(rightOrderStart, 160))) {
+                    return(0, 0)
+                }
 
-                    // Write length of signature (always 0 since signature was previously validated)
-                    let rightSignatureStart := add(
-                        add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
-                        add(leftMakerAssetDataLen, 32)                    
-                    )
-                    mstore(rightSignatureStart, 0)
+                // We want the following layout in memory before calling `EXCHANGE.fillOrder`:
 
-                    // function selector (4 bytes) + 3 params (3 * 32 bytes) must be stored before `rightOrderStart`
-                    let cdStart := sub(rightOrderStart, 100)
+                // | Offset                    | Length  | Contents                                    |
+                // |---------------------------|---------|-------------------------------------------- |
+                // | 480 + a + b               | 4       | `fillOrder` function selector               |
+                // |                           | 3 * 32  | function parameters:                        |
+                // | 484 + a + b               |         |   1. offset to rightOrder (*)               |
+                // | 516 + a + b               |         |   2. takerAssetFillAmount                   |
+                // | 548 + a + b               |         |   3. offset to rightSignature (*)           |
+                // |                           | 12 * 32 | rightOrder:                                 |
+                // | 580 + a + b               |         |   1.  senderAddress                         |
+                // | 612 + a + b               |         |   2.  makerAddress                          |
+                // | 644 + a + b               |         |   3.  takerAddress                          |
+                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
+                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
+                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
+                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
+                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
+                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
+                // | 868 + a + b               |         |   10. salt                                  |
+                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
+                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
+                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
+                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
+                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
+                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
+                // | 1028 + a + b + c + d      | 32      | rightSignature Length (always 0)            |
 
-                    // `fillOrder` selector = 0xb4be83d5
-                    mstore(cdStart, 0xb4be83d500000000000000000000000000000000000000000000000000000000)
+                // Write length of signature (always 0 since signature was previously validated)
+                mstore(rightOrderEnd, 0)
 
-                    // Write offset to `rightOrder`
-                    mstore(add(cdStart, 4), 96)
+                // function selector (4 bytes) + 3 params (3 * 32 bytes) must be stored before `rightOrderStart`
+                cdStart := sub(rightOrderStart, 100)
 
-                    // Write `takerAssetFillAmount`, which will be the `leftMakerAssetSpreadAmount` received from the `matchOrders` call
-                    mstore(add(cdStart, 36), mload(256))
+                // `fillOrder` selector = 0xb4be83d5
+                mstore(cdStart, 0xb4be83d500000000000000000000000000000000000000000000000000000000)
 
-                    // Write offset to `rightSignature`
-                    mstore(add(cdStart, 68), sub(rightSignatureStart, add(cdStart, 4)))
+                // Write offset to `rightOrder`
+                mstore(add(cdStart, 4), 96)
 
-                    let fillOrderSuccess := call(
-                        gas,                                         // forward all gas
-                        exchange,                                    // call address of Exchange contract
-                        0,                                           // transfer 0 wei
-                        cdStart,                                     // start of input
-                        sub(add(rightSignatureStart, 32), cdStart),  // length of input is end - start
-                        0,                                           // write output over input
-                        128                                          // length of output is 128 bytes
-                    )
+                // Write `takerAssetFillAmount`, which will be the `leftMakerAssetSpreadAmount` received from the `matchOrders` call
+                mstore(add(cdStart, 36), mload(256))
 
-                    if fillOrderSuccess {
-                        return(0, 0)
-                    }
-                
-                    // Revert with reason if `fillOrder` call was unsuccessful
+                // Write offset to `rightSignature`
+                mstore(
+                    add(cdStart, 68),
+                    sub(rightOrderEnd, add(cdStart, 4))
+                )
+
+                // Call `EXCHANGE.fillOrder(rightOrder, leftMakerAssetSpreadAmount, "")`
+                success := call(
+                    gas,                                   // forward all gas
+                    exchange,                              // call address of Exchange contract
+                    0,                                     // transfer 0 wei
+                    cdStart,                               // start of input
+                    add(sub(rightOrderEnd, cdStart), 32),  // length of input is end - start
+                    0,                                     // write output over input
+                    0                                      // do not write output to memory
+                )
+
+                if iszero(success) {
+                    // Revert with reason if `EXCHANGE.fillOrder` call was unsuccessful
+                    returndatacopy(
+                        0,                // copy to memory at 0
+                        0,                // copy from return data at 0
+                        returndatasize()  // copy all return data
+                    )
                     revert(0, returndatasize())
                 }
-
-                // Return if `matchOrders` call successful and `fillOrder` was not called
+                
+                // Return if `EXCHANGE.fillOrder` did not revert
                 return(0, 0)
+            
             }
 
             // Revert if undefined function is called
diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts
index 45002b324..acb46ced4 100644
--- a/contracts/extensions/test/extensions/order_matcher.ts
+++ b/contracts/extensions/test/extensions/order_matcher.ts
@@ -435,7 +435,7 @@ describe('OrderMatcher', () => {
                 initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
             );
         });
-        it('should not call fillOrder when rightOrder is completely filled after matchOrders call', async () => {
+        it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => {
             // Create orders to match
             const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
                 makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
@@ -443,7 +443,45 @@ describe('OrderMatcher', () => {
             });
             const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
                 makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
-                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            const data = exchange.matchOrders.getABIEncodedTransactionData(
+                signedOrderLeft,
+                signedOrderRight,
+                signedOrderLeft.signature,
+                signedOrderRight.signature,
+            );
+            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
+            const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
+                await web3Wrapper.sendTransactionAsync({
+                    data,
+                    to: orderMatcher.address,
+                    from: owner,
+                    gas: constants.MAX_MATCH_ORDERS_GAS,
+                }),
+            );
+            const fillLogs = _.filter(
+                txReceipt.logs,
+                log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
+            );
+            // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
+            expect(fillLogs.length).to.be.equal(2);
+        });
+        it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => {
+            // Create orders to match
+            const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+            });
+            const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
+                makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
+                takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
+            });
+            await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, {
+                takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5),
+            });
+            await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, {
+                takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5),
             });
             const data = exchange.matchOrders.getABIEncodedTransactionData(
                 signedOrderLeft,
@@ -451,7 +489,7 @@ describe('OrderMatcher', () => {
                 signedOrderLeft.signature,
                 signedOrderRight.signature,
             );
-            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts });
+            const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
             const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
                 await web3Wrapper.sendTransactionAsync({
                     data,
-- 
cgit v1.2.3


From 58be23ac9798dfb0c8dd5146aa41872b03dff174 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 19 Dec 2018 14:15:25 -0800
Subject: Remove assembly version of matchOrders

---
 .../contracts/OrderMatcher/MixinMatchOrders.sol    | 420 +++------------------
 .../contracts/OrderMatcher/OrderMatcher.sol        |   1 +
 2 files changed, 52 insertions(+), 369 deletions(-)

(limited to 'contracts')

diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
index b6bc83af9..f75cecdc1 100644
--- a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
+++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol
@@ -17,8 +17,11 @@
 */
 
 pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
 
 import "./libs/LibConstants.sol";
+import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
+import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
 import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 
 
@@ -26,379 +29,58 @@ contract MixinMatchOrders is
     Ownable,
     LibConstants
 {
-    // The below assembly in the fallback function is functionaly equivalent to the following Solidity code:
-    /*
-        /// @dev Match two complementary orders that have a profitable spread.
-        ///      Each order is filled at their respective price point. However, the calculations are
-        ///      carried out as though the orders are both being filled at the right order's price point.
-        ///      The profit made by the left order is then used to fill the right order as much as possible.
-        ///      This results in a spread being taken in terms of both assets. The spread is held within this contract.
-        /// @param leftOrder First order to match.
-        /// @param rightOrder Second order to match.
-        /// @param leftSignature Proof that order was created by the left maker.
-        /// @param rightSignature Proof that order was created by the right maker.
-        function matchOrders(
-            LibOrder.Order memory leftOrder,
-            LibOrder.Order memory rightOrder,
-            bytes memory leftSignature,
-            bytes memory rightSignature
-        )
-            public
-            onlyOwner
-        {
-            // Match orders, maximally filling `leftOrder`
-            LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
-                leftOrder,
-                rightOrder,
-                leftSignature,
-                rightSignature
-            );
-
-            uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
-            uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
-
-            // Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
-            if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
-                return;
-            }
-
-            // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
-            rightOrder.makerAssetData = leftOrder.takerAssetData;
-            rightOrder.takerAssetData = leftOrder.makerAssetData;
-
-            // Query `rightOrder` info to check if it has been completely filled
-            // We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
-            OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
-
-            // Do not attempt to call `fillOrder` if order has been completely filled
-            if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
-                return;
-            }
-
-            // We do not need to pass in a signature since it was already validated in the `matchOrders` call
-            EXCHANGE.fillOrder(
-                rightOrder,
-                leftMakerAssetSpreadAmount,
-                ""
-            );
-        }
-    */
-    // solhint-disable-next-line payable-fallback
-    function ()
-        external
+    /// @dev Match two complementary orders that have a profitable spread.
+    ///      Each order is filled at their respective price point. However, the calculations are
+    ///      carried out as though the orders are both being filled at the right order's price point.
+    ///      The profit made by the left order is then used to fill the right order as much as possible.
+    ///      This results in a spread being taken in terms of both assets. The spread is held within this contract.
+    /// @param leftOrder First order to match.
+    /// @param rightOrder Second order to match.
+    /// @param leftSignature Proof that order was created by the left maker.
+    /// @param rightSignature Proof that order was created by the right maker.
+    function matchOrders(
+        LibOrder.Order memory leftOrder,
+        LibOrder.Order memory rightOrder,
+        bytes memory leftSignature,
+        bytes memory rightSignature
+    )
+        public
+        onlyOwner
     {
-        assembly {
-            // The first 4 bytes of calldata holds the function selector
-            // `matchOrders` selector = 0x3c28d861
-            if eq(
-                and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000),
-                0x3c28d86100000000000000000000000000000000000000000000000000000000
-            ) {
-
-                // Load address of `owner`
-                let owner := sload(owner_slot)
-
-                // Revert if `msg.sender` != `owner`
-                if iszero(eq(owner, caller)) {
-                    // Revert with `Error("ONLY_CONTRACT_OWNER")`
-                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
-                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
-                    mstore(64, 0x000000134f4e4c595f434f4e54524143545f4f574e4552000000000000000000)
-                    mstore(96, 0)
-                    revert(0, 100)
-                }
-
-                // Load address of Exchange contract
-                let exchange := sload(EXCHANGE_slot)
-
-                // Copy calldata to memory
-                // The calldata should be identical to the the ABIv2 encoded data required to call `EXCHANGE.matchOrders`
-                calldatacopy(
-                    0,              // copy to memory at 0
-                    0,              // copy from calldata at 0
-                    calldatasize()  // copy all calldata
-                )
-
-                // At this point, calldata and memory have the following layout:
-
-                // | Offset                    | Length  | Contents                                    |
-                // |---------------------------|---------|-------------------------------------------- |
-                // | 0                         | 4       | `matchOrders` function selector             |
-                // |                           | 4 * 32  | function parameters:                        |
-                // | 4                         |         |   1. offset to leftOrder (*)                |
-                // | 36                        |         |   2. offset to rightOrder (*)               |
-                // | 68                        |         |   3. offset to leftSignature (*)            |
-                // | 100                       |         |   4. offset to rightSignature (*)           |
-                // |                           | 12 * 32 | leftOrder:                                  |
-                // | 132                       |         |   1.  senderAddress                         |
-                // | 164                       |         |   2.  makerAddress                          |
-                // | 196                       |         |   3.  takerAddress                          |
-                // | 228                       |         |   4.  feeRecipientAddress                   |
-                // | 260                       |         |   5.  makerAssetAmount                      |
-                // | 292                       |         |   6.  takerAssetAmount                      |
-                // | 324                       |         |   7.  makerFeeAmount                        |
-                // | 356                       |         |   8.  takerFeeAmount                        |
-                // | 388                       |         |   9.  expirationTimeSeconds                 |
-                // | 420                       |         |   10. salt                                  |
-                // | 452                       |         |   11. offset to leftMakerAssetData (*)      |
-                // | 484                       |         |   12. offset to leftTakerAssetData (*)      |
-                // | 516                       | 32      | leftMakerAssetData Length                   |
-                // | 548                       | a       | leftMakerAssetData Contents                 |
-                // | 548 + a                   | 32      | leftTakerAssetData Length                   |
-                // | 580 + a                   | b       | leftTakerAssetData Contents                 |
-                // |                           | 12 * 32 | rightOrder:                                 |
-                // | 580 + a + b               |         |   1.  senderAddress                         |
-                // | 612 + a + b               |         |   2.  makerAddress                          |
-                // | 644 + a + b               |         |   3.  takerAddress                          |
-                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
-                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
-                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
-                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
-                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
-                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
-                // | 868 + a + b               |         |   10. salt                                  |
-                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
-                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
-                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
-                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
-                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
-                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
-                // | 1028 + a + b + c + d      | 32      | leftSignature Length                        |
-                // | 1060 + a + b + c + d      | e       | leftSignature Contents                      |
-                // | 1060 + a + b + c + d + e  | 32      | rightSignature Length                       |
-                // | 1092 + a + b + c + d + e  | f       | rightSignature Contents                     |
-
-                // Call `EXCHANGE.matchOrders`
-                let success := call(
-                    gas,             // forward all gas
-                    exchange,        // call address of Exchange contract
-                    0,               // transfer 0 wei
-                    0,               // input starts at 0
-                    calldatasize(),  // length of input
-                    0,               // write output over input
-                    288              // length of output is 288 bytes
-                )
-
-                if iszero(success) {
-                    // Revert with reason if `EXCHANGE.matchOrders` call was unsuccessful
-                    returndatacopy(
-                        0,                // copy to memory at 0
-                        0,                // copy from return data at 0
-                        returndatasize()  // copy all return data
-                    )
-                    revert(0, returndatasize())
-                }
-
-                // After calling `matchOrders`, the return data is layed out in memory as:
-
-                // | Offset                    | Length  | Contents                                    |
-                // |---------------------------|---------|-------------------------------------------- |
-                // |                           | 9 * 32  | matchedFillResults                          |
-                // | 0                         |         |   1. left.makerAssetFilledAmount            |
-                // | 32                        |         |   2. left.takerAssetFilledAmount            |
-                // | 64                        |         |   3. left.makerFeePaid                      |
-                // | 96                        |         |   4. left.takerFeePaid                      |
-                // | 128                       |         |   5. right.makerAssetFilledAmount           |
-                // | 160                       |         |   6. right.takerAssetFilledAmount           |
-                // | 192                       |         |   7. right.makerFeePaid                     |
-                // | 224                       |         |   8. right.takerFeePaid                     |
-                // | 256                       |         |   9. leftMakerAssetSpreadAmount             |
-
-                let rightOrderStart := add(calldataload(36), 4)
-    
-                // If no spread was taken or if the entire `rightOrderTakerAssetAmount` has been filled, there is no need to call `EXCHANGE.fillOrder`.
-                if or(
-                    iszero(mload(256)),                                      // iszero(leftMakerAssetSpreadAmount)
-                    eq(mload(160), calldataload(add(rightOrderStart, 160)))  // eq(rightOrderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
-                ) {
-                    return(0, 0)
-                }
-
-                // We assume that `leftOrder.makerAssetData == rightOrder.takerAssetData` and `leftOrder.takerAssetData == rightOrder.makerAssetData`
-                // `EXCHANGE.matchOrders` already makes this assumption, so it is likely
-                // that the `rightMakerAssetData` and `rightTakerAssetData` in calldata are empty
-
-                let leftOrderStart := add(calldataload(4), 4)
-
-                // Calculate locations of `leftMakerAssetData` and `leftTakerAssetData` in calldata
-                let leftMakerAssetDataStart := add(
-                    leftOrderStart,
-                    calldataload(add(leftOrderStart, 320))  // offset to `leftMakerAssetData`
-                )
-                let leftTakerAssetDataStart := add(
-                    leftOrderStart,
-                    calldataload(add(leftOrderStart, 352))  // offset to `leftTakerAssetData`
-                )
-
-                // Load lengths of `leftMakerAssetData` and `leftTakerAssetData`
-                let leftMakerAssetDataLen := calldataload(leftMakerAssetDataStart)
-                let leftTakerAssetDataLen := calldataload(leftTakerAssetDataStart)
-
-                // Write offset to `rightMakerAssetData` 
-                mstore(add(rightOrderStart, 320), 384)
-
-                // Write offset to `rightTakerAssetData`
-                let rightTakerAssetDataOffset := add(416, leftTakerAssetDataLen)
-                mstore(add(rightOrderStart, 352), rightTakerAssetDataOffset)
-
-                // Copy `leftTakerAssetData` from calldata onto `rightMakerAssetData` in memory
-                calldatacopy(
-                    add(rightOrderStart, 384),  // `rightMakerAssetDataStart`
-                    leftTakerAssetDataStart,
-                    add(leftTakerAssetDataLen, 32)
-                )
-
-                // Copy `leftMakerAssetData` from calldata onto `rightTakerAssetData` in memory
-                calldatacopy(
-                    add(rightOrderStart, rightTakerAssetDataOffset),  // `rightTakerAssetDataStart`
-                    leftMakerAssetDataStart,
-                    add(leftMakerAssetDataLen, 32)
-                )
-
-                // We must call `EXCHANGE.getOrderInfo(rightOrder)` before calling `EXCHANGE.fillOrder` to ensure that the order
-                // has not already been entirely filled (which is possible if an order was partially filled before the `matchOrders` call).
-                // We want the following layout in memory before calling `getOrderInfo`:
-
-                // | Offset                    | Length  | Contents                                    |
-                // |---------------------------|---------|-------------------------------------------- |
-                // | 544 + a + b               | 4       | `getOrderInfo` function selector            |
-                // |                           | 3 * 32  | function parameters:                        |
-                // | 548 + a + b               |         |   1. offset to rightOrder (*)               |
-                // |                           | 12 * 32 | rightOrder:                                 |
-                // | 580 + a + b               |         |   1.  senderAddress                         |
-                // | 612 + a + b               |         |   2.  makerAddress                          |
-                // | 644 + a + b               |         |   3.  takerAddress                          |
-                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
-                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
-                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
-                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
-                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
-                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
-                // | 868 + a + b               |         |   10. salt                                  |
-                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
-                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
-                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
-                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
-                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
-                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
-
-                // function selector (4 bytes) + 1 param (32 bytes) must be stored before `rightOrderStart`
-                let cdStart := sub(rightOrderStart, 36)
-
-                // `getOrderInfo` selector = 0xc75e0a81
-                mstore(cdStart, 0xc75e0a8100000000000000000000000000000000000000000000000000000000)
-
-                // Write offset to `rightOrder`
-                mstore(add(cdStart, 4), 32)
-
-                let rightOrderEnd := add(
-                    add(rightOrderStart, 484),
-                    add(leftMakerAssetDataLen, leftTakerAssetDataLen)                    
-                )
-
-                // Call `EXCHANGE.getOrderInfo(rightOrder)`
-                success := staticcall(
-                    gas,                          // forward all gas
-                    exchange,                     // call address of Exchange contract
-                    cdStart,                      // start of input
-                    sub(rightOrderEnd, cdStart),  // length of input
-                    0,                            // write output over old output
-                    96                            // output is 96 bytes
-                )
-
-                // After calling `EXCHANGE.getOrderInfo`, the return data is layed out in memory as:
-
-                // | Offset                    | Length  | Contents                                    |
-                // |---------------------------|---------|-------------------------------------------- |
-                // |                           | 3 * 32  | orderInfo                                   |
-                // | 0                         |         |   1. orderStatus                            |
-                // | 32                        |         |   2. orderHash                              |
-                // | 64                        |         |   3. orderTakerAssetFilledAmount            |
-
-                // We do not need to check if the `getOrderInfo` call was successful because it has no possibility of reverting
-                // If order has been entirely filled, there is no need to call `EXCHANGE.fillOrder`
-                // eq(orderTakerAssetFilledAmount, rightOrderTakerAssetAmount)
-                if eq(mload(64), calldataload(add(rightOrderStart, 160))) {
-                    return(0, 0)
-                }
-
-                // We want the following layout in memory before calling `EXCHANGE.fillOrder`:
-
-                // | Offset                    | Length  | Contents                                    |
-                // |---------------------------|---------|-------------------------------------------- |
-                // | 480 + a + b               | 4       | `fillOrder` function selector               |
-                // |                           | 3 * 32  | function parameters:                        |
-                // | 484 + a + b               |         |   1. offset to rightOrder (*)               |
-                // | 516 + a + b               |         |   2. takerAssetFillAmount                   |
-                // | 548 + a + b               |         |   3. offset to rightSignature (*)           |
-                // |                           | 12 * 32 | rightOrder:                                 |
-                // | 580 + a + b               |         |   1.  senderAddress                         |
-                // | 612 + a + b               |         |   2.  makerAddress                          |
-                // | 644 + a + b               |         |   3.  takerAddress                          |
-                // | 676 + a + b               |         |   4.  feeRecipientAddress                   |
-                // | 708 + a + b               |         |   5.  makerAssetAmount                      |
-                // | 740 + a + b               |         |   6.  takerAssetAmount                      |
-                // | 772 + a + b               |         |   7.  makerFeeAmount                        |
-                // | 804 + a + b               |         |   8.  takerFeeAmount                        |
-                // | 836 + a + b               |         |   9.  expirationTimeSeconds                 |
-                // | 868 + a + b               |         |   10. salt                                  |
-                // | 900 + a + b               |         |   11. offset to rightMakerAssetData (*)     |
-                // | 932 + a + b               |         |   12. offset to rightTakerAssetData (*)     |
-                // | 964 + a + b               | 32      | rightMakerAssetData Length                  |
-                // | 996 + a + b               | c       | rightMakerAssetData Contents                |
-                // | 996 + a + b + c           | 32      | rightTakerAssetData Length                  |
-                // | 1028 + a + b + c          | d       | rightTakerAssetData Contents                |
-                // | 1028 + a + b + c + d      | 32      | rightSignature Length (always 0)            |
-
-                // Write length of signature (always 0 since signature was previously validated)
-                mstore(rightOrderEnd, 0)
-
-                // function selector (4 bytes) + 3 params (3 * 32 bytes) must be stored before `rightOrderStart`
-                cdStart := sub(rightOrderStart, 100)
-
-                // `fillOrder` selector = 0xb4be83d5
-                mstore(cdStart, 0xb4be83d500000000000000000000000000000000000000000000000000000000)
-
-                // Write offset to `rightOrder`
-                mstore(add(cdStart, 4), 96)
-
-                // Write `takerAssetFillAmount`, which will be the `leftMakerAssetSpreadAmount` received from the `matchOrders` call
-                mstore(add(cdStart, 36), mload(256))
-
-                // Write offset to `rightSignature`
-                mstore(
-                    add(cdStart, 68),
-                    sub(rightOrderEnd, add(cdStart, 4))
-                )
+        // Match orders, maximally filling `leftOrder`
+        LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
+            leftOrder,
+            rightOrder,
+            leftSignature,
+            rightSignature
+        );
+
+        uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
+        uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
+
+        // Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
+        if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
+            return;
+        }
 
-                // Call `EXCHANGE.fillOrder(rightOrder, leftMakerAssetSpreadAmount, "")`
-                success := call(
-                    gas,                                   // forward all gas
-                    exchange,                              // call address of Exchange contract
-                    0,                                     // transfer 0 wei
-                    cdStart,                               // start of input
-                    add(sub(rightOrderEnd, cdStart), 32),  // length of input is end - start
-                    0,                                     // write output over input
-                    0                                      // do not write output to memory
-                )
+        // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
+        rightOrder.makerAssetData = leftOrder.takerAssetData;
+        rightOrder.takerAssetData = leftOrder.makerAssetData;
 
-                if iszero(success) {
-                    // Revert with reason if `EXCHANGE.fillOrder` call was unsuccessful
-                    returndatacopy(
-                        0,                // copy to memory at 0
-                        0,                // copy from return data at 0
-                        returndatasize()  // copy all return data
-                    )
-                    revert(0, returndatasize())
-                }
-                
-                // Return if `EXCHANGE.fillOrder` did not revert
-                return(0, 0)
-            
-            }
+        // Query `rightOrder` info to check if it has been completely filled
+        // We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
+        LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
 
-            // Revert if undefined function is called
-            revert(0, 0)
+        // Do not attempt to call `fillOrder` if order has been completely filled
+        if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
+            return;
         }
+
+        // We do not need to pass in a signature since it was already validated in the `matchOrders` call
+        EXCHANGE.fillOrder(
+            rightOrder,
+            leftMakerAssetSpreadAmount,
+            ""
+        );
     }
 }
diff --git a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
index 7136c8c82..4879b7bca 100644
--- a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
+++ b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
@@ -17,6 +17,7 @@
 */
 
 pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
 
 import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
 import "./libs/LibConstants.sol";
-- 
cgit v1.2.3


From fbfb6eb45e60aa1439162559df16444344322092 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Thu, 20 Dec 2018 09:13:19 -0800
Subject: Update CHANGELOG

---
 contracts/extensions/CHANGELOG.json | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'contracts')

diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json
index da4d9c2ba..4f2b54988 100644
--- a/contracts/extensions/CHANGELOG.json
+++ b/contracts/extensions/CHANGELOG.json
@@ -5,6 +5,10 @@
             {
                 "note": "Added Balance Threshold Filter",
                 "pr": 1383
+            },
+            {
+                "note": "Add OrderMatcher",
+                "pr": 1117
             }
         ]
     },
-- 
cgit v1.2.3