From 6f88e9bdbdd8f44c45053b8c17c84411f9499084 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Tue, 21 Aug 2018 16:06:21 -0700
Subject: Add internal fill functions, add reentrancy guard to public functions
 that make external calls

---
 .../2.0.0/protocol/Exchange/MixinExchangeCore.sol  | 86 ++++++++++++++--------
 .../2.0.0/protocol/Exchange/MixinMatchOrders.sol   |  3 +
 .../protocol/Exchange/MixinWrapperFunctions.sol    | 46 +++++++++---
 .../protocol/Exchange/mixins/MExchangeCore.sol     | 13 ++++
 .../protocol/Exchange/mixins/MWrapperFunctions.sol | 40 ++++++++++
 .../utils/ReentrancyGuard/ReentrancyGuard.sol      |  1 -
 6 files changed, 148 insertions(+), 41 deletions(-)
 create mode 100644 packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol

diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
index f3a0591b2..d00323b15 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol
@@ -19,6 +19,7 @@
 pragma solidity 0.4.24;
 pragma experimental ABIEncoderV2;
 
+import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
 import "./libs/LibConstants.sol";
 import "./libs/LibFillResults.sol";
 import "./libs/LibOrder.sol";
@@ -30,6 +31,7 @@ import "./mixins/MAssetProxyDispatcher.sol";
 
 
 contract MixinExchangeCore is
+    ReentrancyGuard,
     LibConstants,
     LibMath,
     LibOrder,
@@ -86,43 +88,14 @@ contract MixinExchangeCore is
         bytes memory signature
     )
         public
+        nonReentrant
         returns (FillResults memory fillResults)
     {
-        // Fetch order info
-        OrderInfo memory orderInfo = getOrderInfo(order);
-
-        // Fetch taker address
-        address takerAddress = getCurrentContextAddress();
-
-        // Get amount of takerAsset to fill
-        uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
-        uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
-
-        // Validate context
-        assertValidFill(
+        fillResults = fillOrderInternal(
             order,
-            orderInfo,
-            takerAddress,
             takerAssetFillAmount,
-            takerAssetFilledAmount,
             signature
         );
-
-        // Compute proportional fill amounts
-        fillResults = calculateFillResults(order, takerAssetFilledAmount);
-
-        // Update exchange internal state
-        updateFilledState(
-            order,
-            takerAddress,
-            orderInfo.orderHash,
-            orderInfo.orderTakerAssetFilledAmount,
-            fillResults
-        );
-    
-        // Settle order
-        settleOrder(order, takerAddress, fillResults);
-
         return fillResults;
     }
 
@@ -203,6 +176,57 @@ contract MixinExchangeCore is
         return orderInfo;
     }
 
+    /// @dev Fills the input order.
+    /// @param order Order struct containing order specifications.
+    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
+    /// @param signature Proof that order has been created by maker.
+    /// @return Amounts filled and fees paid by maker and taker.
+    function fillOrderInternal(
+        Order memory order,
+        uint256 takerAssetFillAmount,
+        bytes memory signature
+    )
+        internal
+        returns (FillResults memory fillResults)
+    {
+        // Fetch order info
+        OrderInfo memory orderInfo = getOrderInfo(order);
+
+        // Fetch taker address
+        address takerAddress = getCurrentContextAddress();
+
+        // Get amount of takerAsset to fill
+        uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
+        uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
+
+        // Validate context
+        assertValidFill(
+            order,
+            orderInfo,
+            takerAddress,
+            takerAssetFillAmount,
+            takerAssetFilledAmount,
+            signature
+        );
+
+        // Compute proportional fill amounts
+        fillResults = calculateFillResults(order, takerAssetFilledAmount);
+
+        // Update exchange internal state
+        updateFilledState(
+            order,
+            takerAddress,
+            orderInfo.orderHash,
+            orderInfo.orderTakerAssetFilledAmount,
+            fillResults
+        );
+    
+        // Settle order
+        settleOrder(order, takerAddress, fillResults);
+
+        return fillResults;
+    }
+
     /// @dev Updates state with results of a fill order.
     /// @param order that was filled.
     /// @param takerAddress Address of taker who filled the order.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
index 20f4b1c33..25220a673 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol
@@ -14,6 +14,7 @@
 pragma solidity 0.4.24;
 pragma experimental ABIEncoderV2;
 
+import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
 import "./libs/LibConstants.sol";
 import "./libs/LibMath.sol";
 import "./libs/LibOrder.sol";
@@ -25,6 +26,7 @@ import "./mixins/MAssetProxyDispatcher.sol";
 
 
 contract MixinMatchOrders is
+    ReentrancyGuard,
     LibConstants,
     LibMath,
     MAssetProxyDispatcher,
@@ -48,6 +50,7 @@ contract MixinMatchOrders is
         bytes memory rightSignature
     )
         public
+        nonReentrant
         returns (LibFillResults.MatchedFillResults memory matchedFillResults)
     {
         // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
index 1b77cfbcb..ff1cb6995 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol
@@ -19,14 +19,17 @@
 pragma solidity 0.4.24;
 pragma experimental ABIEncoderV2;
 
+import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
 import "./libs/LibMath.sol";
 import "./libs/LibOrder.sol";
 import "./libs/LibFillResults.sol";
 import "./libs/LibAbiEncoder.sol";
 import "./mixins/MExchangeCore.sol";
+import "./mixins/MWrapperFunctions.sol";
 
 
 contract MixinWrapperFunctions is
+    ReentrancyGuard,
     LibMath,
     LibFillResults,
     LibAbiEncoder,
@@ -43,17 +46,14 @@ contract MixinWrapperFunctions is
         bytes memory signature
     )
         public
+        nonReentrant
         returns (FillResults memory fillResults)
     {
-        fillResults = fillOrder(
+        fillResults = fillOrKillOrderInternal(
             order,
             takerAssetFillAmount,
             signature
         );
-        require(
-            fillResults.takerAssetFilledAmount == takerAssetFillAmount,
-            "COMPLETE_FILL_FAILED"
-        );
         return fillResults;
     }
 
@@ -117,11 +117,12 @@ contract MixinWrapperFunctions is
         bytes[] memory signatures
     )
         public
+        nonReentrant
         returns (FillResults memory totalFillResults)
     {
         uint256 ordersLength = orders.length;
         for (uint256 i = 0; i != ordersLength; i++) {
-            FillResults memory singleFillResults = fillOrder(
+            FillResults memory singleFillResults = fillOrderInternal(
                 orders[i],
                 takerAssetFillAmounts[i],
                 signatures[i]
@@ -143,11 +144,12 @@ contract MixinWrapperFunctions is
         bytes[] memory signatures
     )
         public
+        nonReentrant
         returns (FillResults memory totalFillResults)
     {
         uint256 ordersLength = orders.length;
         for (uint256 i = 0; i != ordersLength; i++) {
-            FillResults memory singleFillResults = fillOrKillOrder(
+            FillResults memory singleFillResults = fillOrKillOrderInternal(
                 orders[i],
                 takerAssetFillAmounts[i],
                 signatures[i]
@@ -195,6 +197,7 @@ contract MixinWrapperFunctions is
         bytes[] memory signatures
     )
         public
+        nonReentrant
         returns (FillResults memory totalFillResults)
     {
         bytes memory takerAssetData = orders[0].takerAssetData;
@@ -210,7 +213,7 @@ contract MixinWrapperFunctions is
             uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
 
             // Attempt to sell the remaining amount of takerAsset
-            FillResults memory singleFillResults = fillOrder(
+            FillResults memory singleFillResults = fillOrderInternal(
                 orders[i],
                 remainingTakerAssetFillAmount,
                 signatures[i]
@@ -282,6 +285,7 @@ contract MixinWrapperFunctions is
         bytes[] memory signatures
     )
         public
+        nonReentrant
         returns (FillResults memory totalFillResults)
     {
         bytes memory makerAssetData = orders[0].makerAssetData;
@@ -305,7 +309,7 @@ contract MixinWrapperFunctions is
             );
 
             // Attempt to sell the remaining amount of takerAsset
-            FillResults memory singleFillResults = fillOrder(
+            FillResults memory singleFillResults = fillOrderInternal(
                 orders[i],
                 remainingTakerAssetFillAmount,
                 signatures[i]
@@ -400,4 +404,28 @@ contract MixinWrapperFunctions is
         }
         return ordersInfo;
     }
+
+    /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
+    /// @param order Order struct containing order specifications.
+    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
+    /// @param signature Proof that order has been created by maker.
+    function fillOrKillOrderInternal(
+        LibOrder.Order memory order,
+        uint256 takerAssetFillAmount,
+        bytes memory signature
+    )
+        internal
+        returns (FillResults memory fillResults)
+    {
+        fillResults = fillOrderInternal(
+            order,
+            takerAssetFillAmount,
+            signature
+        );
+        require(
+            fillResults.takerAssetFilledAmount == takerAssetFillAmount,
+            "COMPLETE_FILL_FAILED"
+        );
+        return fillResults;
+    }
 }
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
index c165b647c..41832fe4b 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol
@@ -59,6 +59,19 @@ contract MExchangeCore is
         uint256 orderEpoch                    // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled.
     );
 
+    /// @dev Fills the input order.
+    /// @param order Order struct containing order specifications.
+    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
+    /// @param signature Proof that order has been created by maker.
+    /// @return Amounts filled and fees paid by maker and taker.
+    function fillOrderInternal(
+        LibOrder.Order memory order,
+        uint256 takerAssetFillAmount,
+        bytes memory signature
+    )
+        internal
+        returns (LibFillResults.FillResults memory fillResults);
+
     /// @dev Updates state with results of a fill order.
     /// @param order that was filled.
     /// @param takerAddress Address of taker who filled the order.
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol
new file mode 100644
index 000000000..e04d4a429
--- /dev/null
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol
@@ -0,0 +1,40 @@
+/*
+
+  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 "../libs/LibOrder.sol";
+import "../libs/LibFillResults.sol";
+import "../interfaces/IWrapperFunctions.sol";
+
+
+contract MWrapperFunctions {
+
+    /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
+    /// @param order LibOrder.Order struct containing order specifications.
+    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
+    /// @param signature Proof that order has been created by maker.
+    function fillOrKillOrderInternal(
+        LibOrder.Order memory order,
+        uint256 takerAssetFillAmount,
+        bytes memory signature
+    )
+        internal
+        returns (LibFillResults.FillResults memory fillResults);
+}
diff --git a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol
index 70fc4ca6b..5d6f6970d 100644
--- a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol
+++ b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol
@@ -40,5 +40,4 @@ contract ReentrancyGuard {
         // Unlock mutex after function call
         locked = false;
     }
-
 }
-- 
cgit v1.2.3