Style changes to atomic order matching
This commit is contained in:
		@@ -53,6 +53,20 @@ contract MixinExchangeCore is
 | 
			
		||||
 | 
			
		||||
    ////// Core exchange functions //////
 | 
			
		||||
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uint256 newMakerEpoch = salt + 1;  // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
 | 
			
		||||
        require(
 | 
			
		||||
            newMakerEpoch > makerEpoch[msg.sender],  // epoch must be monotonically increasing
 | 
			
		||||
            INVALID_NEW_MAKER_EPOCH
 | 
			
		||||
        );
 | 
			
		||||
        makerEpoch[msg.sender] = newMakerEpoch;
 | 
			
		||||
        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets information about an order: status, hash, and amount filled.
 | 
			
		||||
    /// @param order Order to gather information on.
 | 
			
		||||
    /// @return status Status of order. Statuses are defined in the LibStatus.Status struct.
 | 
			
		||||
@@ -64,20 +78,11 @@ contract MixinExchangeCore is
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 orderStatus,
 | 
			
		||||
            bytes32 orderHash,
 | 
			
		||||
            uint256 takerAssetFilledAmount)
 | 
			
		||||
            uint256 takerAssetFilledAmount
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // Compute the order hash and fetch filled amount
 | 
			
		||||
        // Compute the order hash
 | 
			
		||||
        orderHash = getOrderHash(order);
 | 
			
		||||
        takerAssetFilledAmount = filled[orderHash];
 | 
			
		||||
 | 
			
		||||
        // If order.takerAssetAmount is zero, then the order will always
 | 
			
		||||
        // be considered filled because 0 == takerAssetAmount == takerAssetFilledAmount
 | 
			
		||||
        // Instead of distinguishing between unfilled and filled zero taker
 | 
			
		||||
        // amount orders, we choose not to support them.
 | 
			
		||||
        if (order.takerAssetAmount == 0) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT);
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If order.makerAssetAmount is zero, we also reject the order.
 | 
			
		||||
        // While the Exchange contract handles them correctly, they create
 | 
			
		||||
@@ -88,15 +93,18 @@ contract MixinExchangeCore is
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate order expiration
 | 
			
		||||
        if (block.timestamp >= order.expirationTimeSeconds) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_EXPIRED);
 | 
			
		||||
        // If order.takerAssetAmount is zero, then the order will always
 | 
			
		||||
        // be considered filled because 0 == takerAssetAmount == takerAssetFilledAmount
 | 
			
		||||
        // Instead of distinguishing between unfilled and filled zero taker
 | 
			
		||||
        // amount orders, we choose not to support them.
 | 
			
		||||
        if (order.takerAssetAmount == 0) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT);
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate order availability
 | 
			
		||||
        if (takerAssetFilledAmount >= order.takerAssetAmount) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_FULLY_FILLED);
 | 
			
		||||
        // Validate order expiration
 | 
			
		||||
        if (block.timestamp >= order.expirationTimeSeconds) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_EXPIRED);
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -110,6 +118,13 @@ contract MixinExchangeCore is
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fetch filled amount and validate order availability
 | 
			
		||||
        takerAssetFilledAmount = filled[orderHash];
 | 
			
		||||
        if (takerAssetFilledAmount >= order.takerAssetAmount) {
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_FULLY_FILLED);
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // All other statuses are ruled out: order is Fillable
 | 
			
		||||
        orderStatus = uint8(Status.ORDER_FILLABLE);
 | 
			
		||||
        return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
@@ -119,18 +134,18 @@ contract MixinExchangeCore is
 | 
			
		||||
    /// @param order to be filled.
 | 
			
		||||
    /// @param orderStatus Status of order to be filled.
 | 
			
		||||
    /// @param orderHash Hash of order to be filled.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @param signature Proof that the orders was created by its maker.
 | 
			
		||||
    /// @param takerAddress Address of order taker.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of order to fill by taker.
 | 
			
		||||
    function validateFillOrderContextOrRevert(
 | 
			
		||||
    /// @param signature Proof that the orders was created by its maker.
 | 
			
		||||
    function validateFillOrRevert(
 | 
			
		||||
        Order memory order,
 | 
			
		||||
        uint8 orderStatus,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        bytes memory signature,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        uint256 takerAssetFillAmount)
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes memory signature)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Ensure order is valid
 | 
			
		||||
@@ -190,23 +205,24 @@ contract MixinExchangeCore is
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 status,
 | 
			
		||||
            FillResults memory fillResults)
 | 
			
		||||
            FillResults memory fillResults
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // Fill Amount must be greater than 0
 | 
			
		||||
        if (takerAssetFillAmount <= 0) {
 | 
			
		||||
        // Fill amount must be greater than 0
 | 
			
		||||
        if (takerAssetFillAmount == 0) {
 | 
			
		||||
            status = uint8(Status.TAKER_ASSET_FILL_AMOUNT_TOO_LOW);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Ensure the order is fillable
 | 
			
		||||
        if (orderStatus != uint8(Status.ORDER_FILLABLE)) {
 | 
			
		||||
            status = uint8(orderStatus);
 | 
			
		||||
            status = orderStatus;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Compute takerAssetFilledAmount
 | 
			
		||||
        uint256 remainingtakerAssetAmount = safeSub(order.takerAssetAmount, takerAssetFilledAmount);
 | 
			
		||||
        fillResults.takerAssetFilledAmount = min256(takerAssetFillAmount, remainingtakerAssetAmount);
 | 
			
		||||
        uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, takerAssetFilledAmount);
 | 
			
		||||
        fillResults.takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
 | 
			
		||||
 | 
			
		||||
        // Validate fill order rounding
 | 
			
		||||
        if (isRoundingError(
 | 
			
		||||
@@ -242,19 +258,32 @@ contract MixinExchangeCore is
 | 
			
		||||
    /// @dev Updates state with results of a fill order.
 | 
			
		||||
    /// @param order that was filled.
 | 
			
		||||
    /// @param takerAddress Address of taker who filled the order.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
			
		||||
    function updateFilledState(
 | 
			
		||||
        Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        FillResults memory fillResults)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Update state
 | 
			
		||||
        filled[orderHash] = safeAdd(filled[orderHash], fillResults.takerAssetFilledAmount);
 | 
			
		||||
        filled[orderHash] = safeAdd(takerAssetFilledAmount, fillResults.takerAssetFilledAmount);
 | 
			
		||||
 | 
			
		||||
        // Log order
 | 
			
		||||
        emitFillEvent(order, takerAddress, orderHash, fillResults);
 | 
			
		||||
        emit Fill(
 | 
			
		||||
            order.makerAddress,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            order.feeRecipientAddress,
 | 
			
		||||
            fillResults.makerAssetFilledAmount,
 | 
			
		||||
            fillResults.takerAssetFilledAmount,
 | 
			
		||||
            fillResults.makerFeePaid,
 | 
			
		||||
            fillResults.takerFeePaid,
 | 
			
		||||
            orderHash,
 | 
			
		||||
            order.makerAssetData,
 | 
			
		||||
            order.takerAssetData
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fills the input order.
 | 
			
		||||
@@ -279,7 +308,15 @@ contract MixinExchangeCore is
 | 
			
		||||
        address takerAddress = getCurrentContextAddress();
 | 
			
		||||
 | 
			
		||||
        // Either our context is valid or we revert
 | 
			
		||||
        validateFillOrderContextOrRevert(order, orderStatus, orderHash, takerAssetFilledAmount, signature, takerAddress, takerAssetFillAmount);
 | 
			
		||||
        validateFillOrRevert(
 | 
			
		||||
            order,
 | 
			
		||||
            orderStatus,
 | 
			
		||||
            orderHash,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            takerAssetFilledAmount,
 | 
			
		||||
            takerAssetFillAmount,
 | 
			
		||||
            signature
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Compute proportional fill amounts
 | 
			
		||||
        uint8 status;
 | 
			
		||||
@@ -290,11 +327,16 @@ contract MixinExchangeCore is
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Settle order
 | 
			
		||||
        (fillResults.makerAssetFilledAmount, fillResults.makerFeePaid, fillResults.takerFeePaid) =
 | 
			
		||||
            settleOrder(order, takerAddress, fillResults.takerAssetFilledAmount);
 | 
			
		||||
        settleOrder(order, takerAddress, fillResults);
 | 
			
		||||
 | 
			
		||||
        // Update exchange internal state
 | 
			
		||||
        updateFilledState(order, takerAddress, orderHash, fillResults);
 | 
			
		||||
        updateFilledState(
 | 
			
		||||
            order,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            orderHash,
 | 
			
		||||
            takerAssetFilledAmount,
 | 
			
		||||
            fillResults
 | 
			
		||||
        );
 | 
			
		||||
        return fillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -302,7 +344,7 @@ contract MixinExchangeCore is
 | 
			
		||||
    /// @param order that was cancelled.
 | 
			
		||||
    /// @param orderStatus Status of order that was cancelled.
 | 
			
		||||
    /// @param orderHash Hash of order that was cancelled.
 | 
			
		||||
    function validateCancelOrderContextOrRevert(
 | 
			
		||||
    function validateCancelOrRevert(
 | 
			
		||||
        Order memory order,
 | 
			
		||||
        uint8 orderStatus,
 | 
			
		||||
        bytes32 orderHash)
 | 
			
		||||
@@ -386,50 +428,12 @@ contract MixinExchangeCore is
 | 
			
		||||
        // Fetch current order status
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
        uint8 orderStatus;
 | 
			
		||||
        uint256 takerAssetFilledAmount;
 | 
			
		||||
        (orderStatus, orderHash, takerAssetFilledAmount) = getOrderInfo(order);
 | 
			
		||||
        (orderStatus, orderHash, ) = getOrderInfo(order);
 | 
			
		||||
 | 
			
		||||
        // Validate context
 | 
			
		||||
        validateCancelOrderContextOrRevert(order, orderStatus, orderHash);
 | 
			
		||||
        validateCancelOrRevert(order, orderStatus, orderHash);
 | 
			
		||||
 | 
			
		||||
        // Perform cancel
 | 
			
		||||
        return updateCancelledState(order, orderStatus, orderHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uint256 newMakerEpoch = salt + 1;  // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
 | 
			
		||||
        require(
 | 
			
		||||
            newMakerEpoch > makerEpoch[msg.sender],  // epoch must be monotonically increasing
 | 
			
		||||
            INVALID_NEW_MAKER_EPOCH
 | 
			
		||||
        );
 | 
			
		||||
        makerEpoch[msg.sender] = newMakerEpoch;
 | 
			
		||||
        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Logs a Fill event with the given arguments.
 | 
			
		||||
    ///      The sole purpose of this function is to get around the stack variable limit.
 | 
			
		||||
    function emitFillEvent(
 | 
			
		||||
        Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        FillResults memory fillResults)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        emit Fill(
 | 
			
		||||
            order.makerAddress,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            order.feeRecipientAddress,
 | 
			
		||||
            fillResults.makerAssetFilledAmount,
 | 
			
		||||
            fillResults.takerAssetFilledAmount,
 | 
			
		||||
            fillResults.makerFeePaid,
 | 
			
		||||
            fillResults.takerFeePaid,
 | 
			
		||||
            orderHash,
 | 
			
		||||
            order.makerAssetData,
 | 
			
		||||
            order.takerAssetData
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,175 +36,7 @@ contract MixinMatchOrders is
 | 
			
		||||
    MMatchOrders,
 | 
			
		||||
    MSettlement,
 | 
			
		||||
    MTransactions
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates context for matchOrders. Succeeds or throws.
 | 
			
		||||
    /// @param leftOrder First order to match.
 | 
			
		||||
    /// @param rightOrder Second order to match.
 | 
			
		||||
    function validateMatchOrdersContextOrRevert(
 | 
			
		||||
        Order memory leftOrder,
 | 
			
		||||
        Order memory rightOrder)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // The leftOrder maker asset must be the same as the rightOrder taker asset.
 | 
			
		||||
        require(
 | 
			
		||||
            areBytesEqual(leftOrder.makerAssetData, rightOrder.takerAssetData),
 | 
			
		||||
            ASSET_MISMATCH_MAKER_TAKER
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // The leftOrder taker asset must be the same as the rightOrder maker asset.
 | 
			
		||||
        require(
 | 
			
		||||
            areBytesEqual(leftOrder.takerAssetData, rightOrder.makerAssetData),
 | 
			
		||||
            ASSET_MISMATCH_TAKER_MAKER
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Make sure there is a positive spread.
 | 
			
		||||
        // There is a positive spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
 | 
			
		||||
        // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
 | 
			
		||||
        // This is satisfied by the equations below:
 | 
			
		||||
        // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> = <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
 | 
			
		||||
        // AND
 | 
			
		||||
        // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
 | 
			
		||||
        // These equations can be combined to get the following:
 | 
			
		||||
        require(
 | 
			
		||||
            safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
 | 
			
		||||
            safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
 | 
			
		||||
            NEGATIVE_SPREAD
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates matched fill results. Succeeds or throws.
 | 
			
		||||
    /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
 | 
			
		||||
    function validateMatchedOrderFillResultsOrThrow(MatchedFillResults memory matchedFillResults)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // The right order must spend at least as much as we're transferring to the left order.
 | 
			
		||||
        require(
 | 
			
		||||
            matchedFillResults.right.makerAssetFilledAmount >=
 | 
			
		||||
            matchedFillResults.left.takerAssetFilledAmount,
 | 
			
		||||
            MISCALCULATED_TRANSFER_AMOUNTS
 | 
			
		||||
        );
 | 
			
		||||
        // If the amount transferred from the right order is different than what is transferred, it is a rounding error amount.
 | 
			
		||||
        // Ensure this difference is negligible by dividing the values with each other. The result should equal to ~1.
 | 
			
		||||
        require(
 | 
			
		||||
            !isRoundingError(
 | 
			
		||||
                matchedFillResults.right.makerAssetFilledAmount,
 | 
			
		||||
                matchedFillResults.left.takerAssetFilledAmount,
 | 
			
		||||
                1),
 | 
			
		||||
            ROUNDING_ERROR_TRANSFER_AMOUNTS
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates partial value given a numerator and denominator.
 | 
			
		||||
    ///      Throws if there is a rounding error.
 | 
			
		||||
    /// @param numerator Numerator.
 | 
			
		||||
    /// @param denominator Denominator.
 | 
			
		||||
    /// @param target Value to calculate partial of.
 | 
			
		||||
    /// @return Partial value of target.
 | 
			
		||||
    function safeGetPartialAmount(
 | 
			
		||||
        uint256 numerator,
 | 
			
		||||
        uint256 denominator,
 | 
			
		||||
        uint256 target)
 | 
			
		||||
        internal pure
 | 
			
		||||
        returns (uint256 partialAmount)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            !isRoundingError(numerator, denominator, target),
 | 
			
		||||
            ROUNDING_ERROR_ON_PARTIAL_AMOUNT
 | 
			
		||||
            );
 | 
			
		||||
        return getPartialAmount(numerator, denominator, target);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates fill amounts for the matched orders.
 | 
			
		||||
    ///      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 leftOrder order goes to the taker (who matched the two orders).
 | 
			
		||||
    /// @param leftOrder First order to match.
 | 
			
		||||
    /// @param rightOrder Second order to match.
 | 
			
		||||
    /// @param leftOrderStatus Order status of left order.
 | 
			
		||||
    /// @param rightOrderStatus Order status of right order.
 | 
			
		||||
    /// @param leftOrderFilledAmount Amount of left order already filled.
 | 
			
		||||
    /// @param rightOrderFilledAmount Amount of right order already filled.
 | 
			
		||||
    /// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
 | 
			
		||||
    /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
 | 
			
		||||
    function calculateMatchedFillResults(
 | 
			
		||||
        Order memory leftOrder,
 | 
			
		||||
        Order memory rightOrder,
 | 
			
		||||
        uint8 leftOrderStatus,
 | 
			
		||||
        uint8 rightOrderStatus,
 | 
			
		||||
        uint256 leftOrderFilledAmount,
 | 
			
		||||
        uint256 rightOrderFilledAmount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 status,
 | 
			
		||||
            MatchedFillResults memory matchedFillResults)
 | 
			
		||||
    {
 | 
			
		||||
        // We settle orders at the price point defined by the right order (profit goes to the order taker)
 | 
			
		||||
        // The constraint can be either on the left or on the right.
 | 
			
		||||
        // The constraint is on the left iff the amount required to fill the left order
 | 
			
		||||
        // is less than or equal to the amount we can spend from the right order:
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
 | 
			
		||||
        uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderFilledAmount);
 | 
			
		||||
        uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderFilledAmount);
 | 
			
		||||
        uint256 leftOrderAmountToFill = 0;
 | 
			
		||||
        uint256 rightOrderAmountToFill = 0;
 | 
			
		||||
        if (
 | 
			
		||||
            safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
 | 
			
		||||
            safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
 | 
			
		||||
        ) {
 | 
			
		||||
            // Left order is the constraint: maximally fill left
 | 
			
		||||
            leftOrderAmountToFill = leftTakerAssetAmountRemaining;
 | 
			
		||||
 | 
			
		||||
            // The right order receives an amount proportional to how much was spent.
 | 
			
		||||
            // TODO: Can we ensure rounding error is in the correct direction?
 | 
			
		||||
            rightOrderAmountToFill = safeGetPartialAmount(
 | 
			
		||||
                rightOrder.takerAssetAmount,
 | 
			
		||||
                rightOrder.makerAssetAmount,
 | 
			
		||||
                leftOrderAmountToFill);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Right order is the constraint: maximally fill right
 | 
			
		||||
            rightOrderAmountToFill = rightTakerAssetAmountRemaining;
 | 
			
		||||
 | 
			
		||||
            // The left order receives an amount proportional to how much was spent.
 | 
			
		||||
            // TODO: Can we ensure rounding error is in the correct direction?
 | 
			
		||||
            leftOrderAmountToFill = safeGetPartialAmount(
 | 
			
		||||
                rightOrder.makerAssetAmount,
 | 
			
		||||
                rightOrder.takerAssetAmount,
 | 
			
		||||
                rightOrderAmountToFill);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate fill results for left order
 | 
			
		||||
        (   status,
 | 
			
		||||
            matchedFillResults.left
 | 
			
		||||
        ) = calculateFillResults(
 | 
			
		||||
            leftOrder,
 | 
			
		||||
            leftOrderStatus,
 | 
			
		||||
            leftOrderFilledAmount,
 | 
			
		||||
            leftOrderAmountToFill);
 | 
			
		||||
        if (status != uint8(Status.SUCCESS)) {
 | 
			
		||||
            return (status, matchedFillResults);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate fill results for right order
 | 
			
		||||
        (   status,
 | 
			
		||||
            matchedFillResults.right
 | 
			
		||||
        ) = calculateFillResults(
 | 
			
		||||
            rightOrder,
 | 
			
		||||
            rightOrderStatus,
 | 
			
		||||
            rightOrderFilledAmount,
 | 
			
		||||
            rightOrderAmountToFill);
 | 
			
		||||
        if (status != uint8(Status.SUCCESS)) {
 | 
			
		||||
            return (status, matchedFillResults);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate the fill results
 | 
			
		||||
        validateMatchedOrderFillResultsOrThrow(matchedFillResults);
 | 
			
		||||
 | 
			
		||||
        // Return status & fill results
 | 
			
		||||
        return (status, matchedFillResults);
 | 
			
		||||
    }
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Match two complementary orders that have a positive spread.
 | 
			
		||||
    ///      Each order is filled at their respective price point. However, the calculations are
 | 
			
		||||
@@ -249,7 +81,7 @@ contract MixinMatchOrders is
 | 
			
		||||
        address takerAddress = getCurrentContextAddress();
 | 
			
		||||
 | 
			
		||||
        // Either our context is valid or we revert
 | 
			
		||||
        validateMatchOrdersContextOrRevert(leftOrder, rightOrder);
 | 
			
		||||
        validateMatchOrThrow(leftOrder, rightOrder);
 | 
			
		||||
 | 
			
		||||
        // Compute proportional fill amounts
 | 
			
		||||
        uint8 matchedFillAmountsStatus;
 | 
			
		||||
@@ -267,22 +99,24 @@ contract MixinMatchOrders is
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate fill contexts
 | 
			
		||||
        validateFillOrderContextOrRevert(
 | 
			
		||||
        validateFillOrRevert(
 | 
			
		||||
            leftOrder,
 | 
			
		||||
            leftOrderInfo.orderStatus,
 | 
			
		||||
            leftOrderInfo.orderHash,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            leftOrderInfo.orderFilledAmount,
 | 
			
		||||
            leftSignature,
 | 
			
		||||
            rightOrder.makerAddress,
 | 
			
		||||
            matchedFillResults.left.takerAssetFilledAmount);
 | 
			
		||||
        validateFillOrderContextOrRevert(
 | 
			
		||||
            matchedFillResults.left.takerAssetFilledAmount,
 | 
			
		||||
            leftSignature
 | 
			
		||||
        );
 | 
			
		||||
        validateFillOrRevert(
 | 
			
		||||
            rightOrder,
 | 
			
		||||
            rightOrderInfo.orderStatus,
 | 
			
		||||
            rightOrderInfo.orderHash,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            rightOrderInfo.orderFilledAmount,
 | 
			
		||||
            rightSignature,
 | 
			
		||||
            leftOrder.makerAddress,
 | 
			
		||||
            matchedFillResults.right.takerAssetFilledAmount);
 | 
			
		||||
            matchedFillResults.right.takerAssetFilledAmount,
 | 
			
		||||
            rightSignature
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Settle matched orders. Succeeds or throws.
 | 
			
		||||
        settleMatchedOrders(leftOrder, rightOrder, matchedFillResults, takerAddress);
 | 
			
		||||
@@ -290,18 +124,169 @@ contract MixinMatchOrders is
 | 
			
		||||
        // Update exchange state
 | 
			
		||||
        updateFilledState(
 | 
			
		||||
            leftOrder,
 | 
			
		||||
            rightOrder.makerAddress,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            leftOrderInfo.orderHash,
 | 
			
		||||
            leftOrderInfo.orderFilledAmount,
 | 
			
		||||
            matchedFillResults.left
 | 
			
		||||
        );
 | 
			
		||||
        updateFilledState(
 | 
			
		||||
            rightOrder,
 | 
			
		||||
            leftOrder.makerAddress,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            rightOrderInfo.orderHash,
 | 
			
		||||
            rightOrderInfo.orderFilledAmount,
 | 
			
		||||
            matchedFillResults.right
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Return results
 | 
			
		||||
        return matchedFillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates context for matchOrders. Succeeds or throws.
 | 
			
		||||
    /// @param leftOrder First order to match.
 | 
			
		||||
    /// @param rightOrder Second order to match.
 | 
			
		||||
    function validateMatchOrThrow(
 | 
			
		||||
        Order memory leftOrder,
 | 
			
		||||
        Order memory rightOrder)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // The leftOrder maker asset must be the same as the rightOrder taker asset.
 | 
			
		||||
        require(
 | 
			
		||||
            areBytesEqual(leftOrder.makerAssetData, rightOrder.takerAssetData),
 | 
			
		||||
            ASSET_MISMATCH_MAKER_TAKER
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // The leftOrder taker asset must be the same as the rightOrder maker asset.
 | 
			
		||||
        require(
 | 
			
		||||
            areBytesEqual(leftOrder.takerAssetData, rightOrder.makerAssetData),
 | 
			
		||||
            ASSET_MISMATCH_TAKER_MAKER
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Make sure there is a positive spread.
 | 
			
		||||
        // There is a positive spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
 | 
			
		||||
        // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
 | 
			
		||||
        // This is satisfied by the equations below:
 | 
			
		||||
        // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
 | 
			
		||||
        // AND
 | 
			
		||||
        // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
 | 
			
		||||
        // These equations can be combined to get the following:
 | 
			
		||||
        require(
 | 
			
		||||
            safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
 | 
			
		||||
            safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
 | 
			
		||||
            NEGATIVE_SPREAD
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates matched fill results. Succeeds or throws.
 | 
			
		||||
    /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
 | 
			
		||||
    function validateMatchOrThrow(MatchedFillResults memory matchedFillResults)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // The right order must spend at least as much as we're transferring to the left order.
 | 
			
		||||
        require(
 | 
			
		||||
            matchedFillResults.right.makerAssetFilledAmount >=
 | 
			
		||||
            matchedFillResults.left.takerAssetFilledAmount,
 | 
			
		||||
            MISCALCULATED_TRANSFER_AMOUNTS
 | 
			
		||||
        );
 | 
			
		||||
        // If the amount transferred from the right order is different than what is transferred, it is a rounding error amount.
 | 
			
		||||
        // Ensure this difference is negligible by dividing the values with each other. The result should equal to ~1.
 | 
			
		||||
        require(
 | 
			
		||||
            !isRoundingError(
 | 
			
		||||
                matchedFillResults.right.makerAssetFilledAmount,
 | 
			
		||||
                matchedFillResults.left.takerAssetFilledAmount,
 | 
			
		||||
                1),
 | 
			
		||||
            ROUNDING_ERROR_TRANSFER_AMOUNTS
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates fill amounts for the matched orders.
 | 
			
		||||
    ///      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 leftOrder order goes to the taker (who matched the two orders).
 | 
			
		||||
    /// @param leftOrder First order to match.
 | 
			
		||||
    /// @param rightOrder Second order to match.
 | 
			
		||||
    /// @param leftOrderStatus Order status of left order.
 | 
			
		||||
    /// @param rightOrderStatus Order status of right order.
 | 
			
		||||
    /// @param leftOrderFilledAmount Amount of left order already filled.
 | 
			
		||||
    /// @param rightOrderFilledAmount Amount of right order already filled.
 | 
			
		||||
    /// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
 | 
			
		||||
    /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
 | 
			
		||||
    function calculateMatchedFillResults(
 | 
			
		||||
        Order memory leftOrder,
 | 
			
		||||
        Order memory rightOrder,
 | 
			
		||||
        uint8 leftOrderStatus,
 | 
			
		||||
        uint8 rightOrderStatus,
 | 
			
		||||
        uint256 leftOrderFilledAmount,
 | 
			
		||||
        uint256 rightOrderFilledAmount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 status,
 | 
			
		||||
            MatchedFillResults memory matchedFillResults
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // We settle orders at the price point defined by the right order (profit goes to the order taker)
 | 
			
		||||
        // The constraint can be either on the left or on the right.
 | 
			
		||||
        // The constraint is on the left iff the amount required to fill the left order
 | 
			
		||||
        // is less than or equal to the amount we can spend from the right order:
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
 | 
			
		||||
        //    <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
 | 
			
		||||
        uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderFilledAmount);
 | 
			
		||||
        uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderFilledAmount);
 | 
			
		||||
        uint256 leftOrderAmountToFill;
 | 
			
		||||
        uint256 rightOrderAmountToFill;
 | 
			
		||||
        if (
 | 
			
		||||
            safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
 | 
			
		||||
            safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
 | 
			
		||||
        ) {
 | 
			
		||||
            // Left order is the constraint: maximally fill left
 | 
			
		||||
            leftOrderAmountToFill = leftTakerAssetAmountRemaining;
 | 
			
		||||
 | 
			
		||||
            // The right order receives an amount proportional to how much was spent.
 | 
			
		||||
            // TODO: Can we ensure rounding error is in the correct direction?
 | 
			
		||||
            rightOrderAmountToFill = safeGetPartialAmount(
 | 
			
		||||
                rightOrder.takerAssetAmount,
 | 
			
		||||
                rightOrder.makerAssetAmount,
 | 
			
		||||
                leftOrderAmountToFill
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Right order is the constraint: maximally fill right
 | 
			
		||||
            rightOrderAmountToFill = rightTakerAssetAmountRemaining;
 | 
			
		||||
 | 
			
		||||
            // The left order receives an amount proportional to how much was spent.
 | 
			
		||||
            // TODO: Can we ensure rounding error is in the correct direction?
 | 
			
		||||
            leftOrderAmountToFill = safeGetPartialAmount(
 | 
			
		||||
                rightOrder.makerAssetAmount,
 | 
			
		||||
                rightOrder.takerAssetAmount,
 | 
			
		||||
                rightOrderAmountToFill
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate fill results for left order
 | 
			
		||||
        (status, matchedFillResults.left) = calculateFillResults(
 | 
			
		||||
            leftOrder,
 | 
			
		||||
            leftOrderStatus,
 | 
			
		||||
            leftOrderFilledAmount,
 | 
			
		||||
            leftOrderAmountToFill
 | 
			
		||||
        );
 | 
			
		||||
        if (status != uint8(Status.SUCCESS)) {
 | 
			
		||||
            return (status, matchedFillResults);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate fill results for right order
 | 
			
		||||
        (status, matchedFillResults.right) = calculateFillResults(
 | 
			
		||||
            rightOrder,
 | 
			
		||||
            rightOrderStatus,
 | 
			
		||||
            rightOrderFilledAmount,
 | 
			
		||||
            rightOrderAmountToFill
 | 
			
		||||
        );
 | 
			
		||||
        if (status != uint8(Status.SUCCESS)) {
 | 
			
		||||
            return (status, matchedFillResults);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate the fill results
 | 
			
		||||
        validateMatchOrThrow(matchedFillResults);
 | 
			
		||||
 | 
			
		||||
        // Return status & fill results
 | 
			
		||||
        return (status, matchedFillResults);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,13 @@ import "./mixins/MSettlement.sol";
 | 
			
		||||
import "./mixins/MAssetProxyDispatcher.sol";
 | 
			
		||||
import "./libs/LibOrder.sol";
 | 
			
		||||
import "./libs/LibMath.sol";
 | 
			
		||||
import "./libs/LibExchangeErrors.sol";
 | 
			
		||||
import "./libs/LibFillResults.sol";
 | 
			
		||||
import "./mixins/MMatchOrders.sol";
 | 
			
		||||
import "./mixins/LibExchangeErrors.sol";
 | 
			
		||||
 | 
			
		||||
contract MixinSettlement is
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibFillResults,
 | 
			
		||||
    LibExchangeErrors,
 | 
			
		||||
    MMatchOrders,
 | 
			
		||||
    MSettlement,
 | 
			
		||||
@@ -58,47 +60,37 @@ contract MixinSettlement is
 | 
			
		||||
    /// @dev Settles an order by transferring assets between counterparties.
 | 
			
		||||
    /// @param order Order struct containing order specifications.
 | 
			
		||||
    /// @param takerAddress Address selling takerAsset and buying makerAsset.
 | 
			
		||||
    /// @param takerAssetFilledAmount The amount of takerAsset that will be transferred to the order's maker.
 | 
			
		||||
    /// @return Amount filled by maker and fees paid by maker/taker.
 | 
			
		||||
    /// @param fillResults Amounts to be filled and fees paid by maker and taker.
 | 
			
		||||
    function settleOrder(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        uint256 takerAssetFilledAmount)
 | 
			
		||||
        FillResults memory fillResults)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (
 | 
			
		||||
            uint256 makerAssetFilledAmount,
 | 
			
		||||
            uint256 makerFeePaid,
 | 
			
		||||
            uint256 takerFeePaid
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        makerAssetFilledAmount = getPartialAmount(takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount);
 | 
			
		||||
        dispatchTransferFrom(
 | 
			
		||||
            order.makerAssetData,
 | 
			
		||||
            order.makerAddress,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            makerAssetFilledAmount
 | 
			
		||||
            fillResults.makerAssetFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
        dispatchTransferFrom(
 | 
			
		||||
            order.takerAssetData,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            order.makerAddress,
 | 
			
		||||
            takerAssetFilledAmount
 | 
			
		||||
            fillResults.takerAssetFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
        makerFeePaid = getPartialAmount(takerAssetFilledAmount, order.takerAssetAmount, order.makerFee);
 | 
			
		||||
        dispatchTransferFrom(
 | 
			
		||||
            ZRX_PROXY_DATA,
 | 
			
		||||
            order.makerAddress,
 | 
			
		||||
            order.feeRecipientAddress,
 | 
			
		||||
            makerFeePaid
 | 
			
		||||
            fillResults.makerFeePaid
 | 
			
		||||
        );
 | 
			
		||||
        takerFeePaid = getPartialAmount(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee);
 | 
			
		||||
        dispatchTransferFrom(
 | 
			
		||||
            ZRX_PROXY_DATA,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            order.feeRecipientAddress,
 | 
			
		||||
            takerFeePaid
 | 
			
		||||
            fillResults.takerFeePaid
 | 
			
		||||
        );
 | 
			
		||||
        return (makerAssetFilledAmount, makerFeePaid, takerFeePaid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
 | 
			
		||||
 
 | 
			
		||||
@@ -55,5 +55,4 @@ contract LibExchangeErrors {
 | 
			
		||||
    string constant NEGATIVE_SPREAD = "Matched orders must have a positive spread.";
 | 
			
		||||
    string constant MISCALCULATED_TRANSFER_AMOUNTS = "A miscalculation occurred: the left maker would receive more than the right maker would spend.";
 | 
			
		||||
    string constant ROUNDING_ERROR_TRANSFER_AMOUNTS = "A rounding error occurred when calculating transfer amounts for matched orders.";
 | 
			
		||||
    string constant ROUNDING_ERROR_ON_PARTIAL_AMOUNT = "A rounding error occurred when calculating partial transfer amounts.";
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import "../../../utils/SafeMath/SafeMath.sol";
 | 
			
		||||
contract LibMath is
 | 
			
		||||
    SafeMath
 | 
			
		||||
{
 | 
			
		||||
    string constant ROUNDING_ERROR_ON_PARTIAL_AMOUNT = "A rounding error occurred when calculating partial transfer amounts.";
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates partial value given a numerator and denominator.
 | 
			
		||||
    /// @param numerator Numerator.
 | 
			
		||||
@@ -44,6 +45,26 @@ contract LibMath is
 | 
			
		||||
        return partialAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates partial value given a numerator and denominator.
 | 
			
		||||
    ///      Throws if there is a rounding error.
 | 
			
		||||
    /// @param numerator Numerator.
 | 
			
		||||
    /// @param denominator Denominator.
 | 
			
		||||
    /// @param target Value to calculate partial of.
 | 
			
		||||
    /// @return Partial value of target.
 | 
			
		||||
    function safeGetPartialAmount(
 | 
			
		||||
        uint256 numerator,
 | 
			
		||||
        uint256 denominator,
 | 
			
		||||
        uint256 target)
 | 
			
		||||
        internal pure
 | 
			
		||||
        returns (uint256 partialAmount)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            !isRoundingError(numerator, denominator, target),
 | 
			
		||||
            ROUNDING_ERROR_ON_PARTIAL_AMOUNT
 | 
			
		||||
            );
 | 
			
		||||
        return getPartialAmount(numerator, denominator, target);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Checks if rounding error > 0.1%.
 | 
			
		||||
    /// @param numerator Numerator.
 | 
			
		||||
    /// @param denominator Denominator.
 | 
			
		||||
 
 | 
			
		||||
@@ -56,14 +56,10 @@ contract MExchangeCore is
 | 
			
		||||
        uint256 makerEpoch
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Logs a Fill event with the given arguments.
 | 
			
		||||
    ///      The sole purpose of this function is to get around the stack variable limit.
 | 
			
		||||
    function emitFillEvent(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        LibFillResults.FillResults memory fillResults)
 | 
			
		||||
        internal;
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets information about an order: status, hash, and amount filled.
 | 
			
		||||
    /// @param order Order to gather information on.
 | 
			
		||||
@@ -76,24 +72,25 @@ contract MExchangeCore is
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 orderStatus,
 | 
			
		||||
            bytes32 orderHash,
 | 
			
		||||
            uint256 takerAssetFilledAmount);
 | 
			
		||||
            uint256 takerAssetFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates context for fillOrder. Succeeds or throws.
 | 
			
		||||
    /// @param order to be filled.
 | 
			
		||||
    /// @param orderStatus Status of order to be filled.
 | 
			
		||||
    /// @param orderHash Hash of order to be filled.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @param signature Proof that the orders was created by its maker.
 | 
			
		||||
    /// @param takerAddress Address of order taker.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of order to fill by taker.
 | 
			
		||||
    function validateFillOrderContextOrRevert(
 | 
			
		||||
    /// @param signature Proof that the orders was created by its maker.
 | 
			
		||||
    function validateFillOrRevert(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        uint8 orderStatus,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        bytes memory signature,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        uint256 takerAssetFillAmount)
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes memory signature)
 | 
			
		||||
        internal;
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates amounts filled and fees paid by maker and taker.
 | 
			
		||||
@@ -112,16 +109,19 @@ contract MExchangeCore is
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 status,
 | 
			
		||||
            LibFillResults.FillResults memory fillResults);
 | 
			
		||||
            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.
 | 
			
		||||
    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
			
		||||
    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
			
		||||
    function updateFilledState(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        uint256 takerAssetFilledAmount,
 | 
			
		||||
        LibFillResults.FillResults memory fillResults)
 | 
			
		||||
        internal;
 | 
			
		||||
 | 
			
		||||
@@ -141,7 +141,7 @@ contract MExchangeCore is
 | 
			
		||||
    /// @param order that was cancelled.
 | 
			
		||||
    /// @param orderStatus Status of order that was cancelled.
 | 
			
		||||
    /// @param orderHash Hash of order that was cancelled.
 | 
			
		||||
    function validateCancelOrderContextOrRevert(
 | 
			
		||||
    function validateCancelOrRevert(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        uint8 orderStatus,
 | 
			
		||||
        bytes32 orderHash)
 | 
			
		||||
@@ -162,15 +162,12 @@ contract MExchangeCore is
 | 
			
		||||
        returns (bool stateUpdated);
 | 
			
		||||
 | 
			
		||||
    /// @dev After calling, the order can not be filled anymore.
 | 
			
		||||
    /// @param order Order struct containing order specifications.
 | 
			
		||||
    ///      Throws if order is invalid or sender does not have permission to cancel.
 | 
			
		||||
    /// @param order Order to cancel. Order must be Status.FILLABLE.
 | 
			
		||||
    /// @return True if the order state changed to cancelled.
 | 
			
		||||
    ///         False if the transaction was already cancelled or expired.
 | 
			
		||||
    ///         False if the order was order was in a valid, but
 | 
			
		||||
    ///               unfillable state (see LibStatus.STATUS for order states)
 | 
			
		||||
    function cancelOrder(LibOrder.Order memory order)
 | 
			
		||||
        public
 | 
			
		||||
        returns (bool);
 | 
			
		||||
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,32 +37,36 @@ contract MMatchOrders {
 | 
			
		||||
        uint256 orderFilledAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Match two complementary orders that have a positive 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 goes to the taker (who matched the two orders).
 | 
			
		||||
    /// @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.
 | 
			
		||||
    /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
 | 
			
		||||
    function matchOrders(
 | 
			
		||||
        LibOrder.Order memory leftOrder,
 | 
			
		||||
        LibOrder.Order memory rightOrder,
 | 
			
		||||
        bytes leftSignature,
 | 
			
		||||
        bytes rightSignature)
 | 
			
		||||
        public
 | 
			
		||||
        returns (MatchedFillResults memory matchedFillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates context for matchOrders. Succeeds or throws.
 | 
			
		||||
    /// @param leftOrder First order to match.
 | 
			
		||||
    /// @param rightOrder Second order to match.
 | 
			
		||||
    function validateMatchOrdersContextOrRevert(
 | 
			
		||||
    function validateMatchOrThrow(
 | 
			
		||||
        LibOrder.Order memory leftOrder,
 | 
			
		||||
        LibOrder.Order memory rightOrder)
 | 
			
		||||
        internal;
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates matched fill results. Succeeds or throws.
 | 
			
		||||
    /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
 | 
			
		||||
    function validateMatchedOrderFillResultsOrThrow(MatchedFillResults memory matchedFillResults)
 | 
			
		||||
    function validateMatchOrThrow(MatchedFillResults memory matchedFillResults)
 | 
			
		||||
        internal;
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates partial value given a numerator and denominator.
 | 
			
		||||
    ///      Throws if there is a rounding error.
 | 
			
		||||
    /// @param numerator Numerator.
 | 
			
		||||
    /// @param denominator Denominator.
 | 
			
		||||
    /// @param target Value to calculate partial of.
 | 
			
		||||
    /// @return Partial value of target.
 | 
			
		||||
    function safeGetPartialAmount(
 | 
			
		||||
        uint256 numerator,
 | 
			
		||||
        uint256 denominator,
 | 
			
		||||
        uint256 target)
 | 
			
		||||
        internal pure
 | 
			
		||||
        returns (uint256 partialAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates fill amounts for the matched orders.
 | 
			
		||||
    ///      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.
 | 
			
		||||
@@ -85,22 +89,6 @@ contract MMatchOrders {
 | 
			
		||||
        internal
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 status,
 | 
			
		||||
            MatchedFillResults memory matchedFillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Match two complementary orders that have a positive 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 goes to the taker (who matched the two orders).
 | 
			
		||||
    /// @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.
 | 
			
		||||
    /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
 | 
			
		||||
    function matchOrders(
 | 
			
		||||
        LibOrder.Order memory leftOrder,
 | 
			
		||||
        LibOrder.Order memory rightOrder,
 | 
			
		||||
        bytes leftSignature,
 | 
			
		||||
        bytes rightSignature)
 | 
			
		||||
        public
 | 
			
		||||
        returns (MatchedFillResults memory matchedFillResults);
 | 
			
		||||
            MatchedFillResults memory matchedFillResults
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,24 +20,19 @@ pragma solidity ^0.4.23;
 | 
			
		||||
 | 
			
		||||
import "../libs/LibOrder.sol";
 | 
			
		||||
import "./MMatchOrders.sol";
 | 
			
		||||
import "../libs/LibFillResults.sol";
 | 
			
		||||
 | 
			
		||||
contract MSettlement {
 | 
			
		||||
 | 
			
		||||
    /// @dev Settles an order by transfering assets between counterparties.
 | 
			
		||||
    /// @dev Settles an order by transferring assets between counterparties.
 | 
			
		||||
    /// @param order Order struct containing order specifications.
 | 
			
		||||
    /// @param takerAddress Address selling takerAsset and buying makerAsset.
 | 
			
		||||
    /// @param takerAssetFilledAmount The amount of takerAsset that will be transfered to the order's maker.
 | 
			
		||||
    /// @return Amount filled by maker and fees paid by maker/taker.
 | 
			
		||||
    /// @param fillResults Amounts to be filled and fees paid by maker and taker.
 | 
			
		||||
    function settleOrder(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        address takerAddress,
 | 
			
		||||
        uint256 takerAssetFilledAmount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (
 | 
			
		||||
            uint256 makerAssetFilledAmount,
 | 
			
		||||
            uint256 makerFeePaid,
 | 
			
		||||
            uint256 takerFeePaid
 | 
			
		||||
        );
 | 
			
		||||
        LibFillResults.FillResults memory fillResults)
 | 
			
		||||
        internal;
 | 
			
		||||
 | 
			
		||||
    /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
 | 
			
		||||
    /// @param leftOrder First matched order.
 | 
			
		||||
 
 | 
			
		||||
@@ -225,12 +225,6 @@ export class ExchangeWrapper {
 | 
			
		||||
        const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex));
 | 
			
		||||
        return filledAmount;
 | 
			
		||||
    }
 | 
			
		||||
    private async _getTxWithDecodedExchangeLogsAsync(txHash: string) {
 | 
			
		||||
        const tx = await this._zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
        tx.logs = _.filter(tx.logs, log => log.address === this._exchange.address);
 | 
			
		||||
        tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async getOrderInfoAsync(
 | 
			
		||||
        signedOrder: SignedOrder,
 | 
			
		||||
    ): Promise<[number /* orderStatus */, string /* orderHash */, BigNumber /* orderTakerAssetAmountFilled */]> {
 | 
			
		||||
@@ -251,6 +245,14 @@ export class ExchangeWrapper {
 | 
			
		||||
            { from },
 | 
			
		||||
        );
 | 
			
		||||
        const tx = await this._getTxWithDecodedExchangeLogsAsync(txHash);
 | 
			
		||||
        tx.logs = _.filter(tx.logs, log => log.address === this._exchange.address);
 | 
			
		||||
        tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    private async _getTxWithDecodedExchangeLogsAsync(txHash: string) {
 | 
			
		||||
        const tx = await this._zeroEx.awaitTransactionMinedAsync(txHash);
 | 
			
		||||
        tx.logs = _.filter(tx.logs, log => log.address === this._exchange.address);
 | 
			
		||||
        tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('matchOrdersAndVerifyBalancesAsync', () => {
 | 
			
		||||
describe('matchOrders', () => {
 | 
			
		||||
    let makerAddressLeft: string;
 | 
			
		||||
    let makerAddressRight: string;
 | 
			
		||||
    let owner: string;
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,6 @@ import {
 | 
			
		||||
    TransferAmountsByMatchOrders as TransferAmounts,
 | 
			
		||||
} from '../../src/utils/types';
 | 
			
		||||
import { chaiSetup } from '../utils/chai_setup';
 | 
			
		||||
import { deployer } from '../utils/deployer';
 | 
			
		||||
import { provider, web3Wrapper } from '../utils/web3_wrapper';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user