Atomic Order Matching - Smart Contracts.
This commit is contained in:
		@@ -25,24 +25,28 @@ import "./MixinSettlement.sol";
 | 
				
			|||||||
import "./MixinWrapperFunctions.sol";
 | 
					import "./MixinWrapperFunctions.sol";
 | 
				
			||||||
import "./MixinAssetProxyDispatcher.sol";
 | 
					import "./MixinAssetProxyDispatcher.sol";
 | 
				
			||||||
import "./MixinTransactions.sol";
 | 
					import "./MixinTransactions.sol";
 | 
				
			||||||
 | 
					import "./MixinMatchOrders.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract Exchange is
 | 
					contract Exchange is
 | 
				
			||||||
    MixinWrapperFunctions,
 | 
					 | 
				
			||||||
    MixinExchangeCore,
 | 
					    MixinExchangeCore,
 | 
				
			||||||
 | 
					    MixinMatchOrders,
 | 
				
			||||||
    MixinSettlement,
 | 
					    MixinSettlement,
 | 
				
			||||||
    MixinSignatureValidator,
 | 
					    MixinSignatureValidator,
 | 
				
			||||||
    MixinTransactions,
 | 
					    MixinTransactions,
 | 
				
			||||||
    MixinAssetProxyDispatcher
 | 
					    MixinAssetProxyDispatcher,
 | 
				
			||||||
 | 
					    MixinWrapperFunctions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    string constant public VERSION = "2.0.1-alpha";
 | 
					    string constant public VERSION = "2.0.1-alpha";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor (bytes memory _zrxProxyData)
 | 
					    constructor (bytes memory _zrxProxyData)
 | 
				
			||||||
        public
 | 
					        public
 | 
				
			||||||
        MixinExchangeCore()
 | 
					        MixinExchangeCore()
 | 
				
			||||||
        MixinSignatureValidator()
 | 
					        MixinMatchOrders()
 | 
				
			||||||
        MixinSettlement(_zrxProxyData)
 | 
					        MixinSettlement(_zrxProxyData)
 | 
				
			||||||
        MixinWrapperFunctions()
 | 
					        MixinSignatureValidator()
 | 
				
			||||||
        MixinAssetProxyDispatcher()
 | 
					 | 
				
			||||||
        MixinTransactions()
 | 
					        MixinTransactions()
 | 
				
			||||||
 | 
					        MixinAssetProxyDispatcher()
 | 
				
			||||||
 | 
					        MixinWrapperFunctions()
 | 
				
			||||||
    {}
 | 
					    {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
 | 
				
			|||||||
import "./libs/LibFillResults.sol";
 | 
					import "./libs/LibFillResults.sol";
 | 
				
			||||||
import "./libs/LibOrder.sol";
 | 
					import "./libs/LibOrder.sol";
 | 
				
			||||||
import "./libs/LibMath.sol";
 | 
					import "./libs/LibMath.sol";
 | 
				
			||||||
 | 
					import "./libs/LibStatus.sol";
 | 
				
			||||||
import "./libs/LibExchangeErrors.sol";
 | 
					import "./libs/LibExchangeErrors.sol";
 | 
				
			||||||
import "./mixins/MExchangeCore.sol";
 | 
					import "./mixins/MExchangeCore.sol";
 | 
				
			||||||
import "./mixins/MSettlement.sol";
 | 
					import "./mixins/MSettlement.sol";
 | 
				
			||||||
@@ -29,9 +30,11 @@ import "./mixins/MSignatureValidator.sol";
 | 
				
			|||||||
import "./mixins/MTransactions.sol";
 | 
					import "./mixins/MTransactions.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MixinExchangeCore is
 | 
					contract MixinExchangeCore is
 | 
				
			||||||
 | 
					    SafeMath,
 | 
				
			||||||
 | 
					    LibMath,
 | 
				
			||||||
 | 
					    LibStatus,
 | 
				
			||||||
    LibOrder,
 | 
					    LibOrder,
 | 
				
			||||||
    LibFillResults,
 | 
					    LibFillResults,
 | 
				
			||||||
    LibMath,
 | 
					 | 
				
			||||||
    LibExchangeErrors,
 | 
					    LibExchangeErrors,
 | 
				
			||||||
    MExchangeCore,
 | 
					    MExchangeCore,
 | 
				
			||||||
    MSettlement,
 | 
					    MSettlement,
 | 
				
			||||||
@@ -48,6 +51,347 @@ contract MixinExchangeCore is
 | 
				
			|||||||
    // Orders with a salt less than their maker's epoch are considered cancelled
 | 
					    // Orders with a salt less than their maker's epoch are considered cancelled
 | 
				
			||||||
    mapping (address => uint256) public makerEpoch;
 | 
					    mapping (address => uint256) public makerEpoch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ////// Core exchange functions //////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Gets information about an order.
 | 
				
			||||||
 | 
					    /// @param order Order to gather information on.
 | 
				
			||||||
 | 
					    /// @return status Status of order. Statuses are defined in the LibStatus.Status struct.
 | 
				
			||||||
 | 
					    /// @return orderHash Keccak-256 EIP712 hash of the order.
 | 
				
			||||||
 | 
					    /// @return takerAssetFilledAmount Amount of order that has been filled.
 | 
				
			||||||
 | 
					    function getOrderInfo(Order memory order)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (
 | 
				
			||||||
 | 
					            uint8 orderStatus,
 | 
				
			||||||
 | 
					            bytes32 orderHash,
 | 
				
			||||||
 | 
					            uint256 takerAssetFilledAmount)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Compute the order hash and fetch filled amount
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					        // edge cases in the supporting infrastructure because they have
 | 
				
			||||||
 | 
					        // an 'infinite' price when computed by a simple division.
 | 
				
			||||||
 | 
					        if (order.makerAssetAmount == 0) {
 | 
				
			||||||
 | 
					            orderStatus = uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT);
 | 
				
			||||||
 | 
					            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate order expiration
 | 
				
			||||||
 | 
					        if (block.timestamp >= order.expirationTimeSeconds) {
 | 
				
			||||||
 | 
					            orderStatus = uint8(Status.ORDER_EXPIRED);
 | 
				
			||||||
 | 
					            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate order availability
 | 
				
			||||||
 | 
					        if (takerAssetFilledAmount >= order.takerAssetAmount) {
 | 
				
			||||||
 | 
					            orderStatus = uint8(Status.ORDER_FULLY_FILLED);
 | 
				
			||||||
 | 
					            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check if order has been cancelled
 | 
				
			||||||
 | 
					        if (cancelled[orderHash]) {
 | 
				
			||||||
 | 
					            orderStatus = uint8(Status.ORDER_CANCELLED);
 | 
				
			||||||
 | 
					            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate order is not cancelled
 | 
				
			||||||
 | 
					        if (makerEpoch[order.makerAddress] > order.salt) {
 | 
				
			||||||
 | 
					            orderStatus = uint8(Status.ORDER_CANCELLED);
 | 
				
			||||||
 | 
					            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Order is Fillable
 | 
				
			||||||
 | 
					        orderStatus = uint8(Status.ORDER_FILLABLE);
 | 
				
			||||||
 | 
					        return (orderStatus, orderHash, 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 takerAssetFillAmount Desired amount of order to fill by taker.
 | 
				
			||||||
 | 
					    function validateFillOrderContextOrRevert(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash,
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount,
 | 
				
			||||||
 | 
					        bytes memory signature,
 | 
				
			||||||
 | 
					        address takerAddress,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Ensure order is valid
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            orderStatus != uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT),
 | 
				
			||||||
 | 
					            INVALID_ORDER_MAKER_ASSET_AMOUNT
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            orderStatus != uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT),
 | 
				
			||||||
 | 
					            INVALID_ORDER_TAKER_ASSET_AMOUNT
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate Maker signature (check only if first time seen)
 | 
				
			||||||
 | 
					        if (takerAssetFilledAmount == 0) {
 | 
				
			||||||
 | 
					            require(
 | 
				
			||||||
 | 
					                isValidSignature(orderHash, order.makerAddress, signature),
 | 
				
			||||||
 | 
					                SIGNATURE_VALIDATION_FAILED
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate sender is allowed to fill this order
 | 
				
			||||||
 | 
					        if (order.senderAddress != address(0)) {
 | 
				
			||||||
 | 
					            require(
 | 
				
			||||||
 | 
					                order.senderAddress == msg.sender,
 | 
				
			||||||
 | 
					                INVALID_SENDER
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate taker is allowed to fill this order
 | 
				
			||||||
 | 
					        if (order.takerAddress != address(0)) {
 | 
				
			||||||
 | 
					            require(
 | 
				
			||||||
 | 
					                order.takerAddress == takerAddress,
 | 
				
			||||||
 | 
					                INVALID_CONTEXT
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            takerAssetFillAmount > 0,
 | 
				
			||||||
 | 
					            GT_ZERO_AMOUNT_REQUIRED
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Calculates amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    /// @param order to be filled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order to be filled.
 | 
				
			||||||
 | 
					    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
				
			||||||
 | 
					    /// @param takerAssetFillAmount Desired amount of order to fill by taker.
 | 
				
			||||||
 | 
					    /// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
 | 
				
			||||||
 | 
					    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function calculateFillResults(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        pure
 | 
				
			||||||
 | 
					        returns (
 | 
				
			||||||
 | 
					            uint8 status,
 | 
				
			||||||
 | 
					            FillResults memory fillResults)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 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);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Compute takerAssetFilledAmount
 | 
				
			||||||
 | 
					        uint256 remainingtakerAssetAmount = safeSub(order.takerAssetAmount, takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        fillResults.takerAssetFilledAmount = min256(takerAssetFillAmount, remainingtakerAssetAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate fill order rounding
 | 
				
			||||||
 | 
					        if (isRoundingError(
 | 
				
			||||||
 | 
					            fillResults.takerAssetFilledAmount,
 | 
				
			||||||
 | 
					            order.takerAssetAmount,
 | 
				
			||||||
 | 
					            order.makerAssetAmount))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            status = uint8(Status.ROUNDING_ERROR_TOO_LARGE);
 | 
				
			||||||
 | 
					            fillResults.takerAssetFilledAmount = 0;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Compute proportional transfer amounts
 | 
				
			||||||
 | 
					        // TODO: All three are multiplied by the same fraction. This can
 | 
				
			||||||
 | 
					        // potentially be optimized.
 | 
				
			||||||
 | 
					        fillResults.makerAssetFilledAmount = getPartialAmount(
 | 
				
			||||||
 | 
					            fillResults.takerAssetFilledAmount,
 | 
				
			||||||
 | 
					            order.takerAssetAmount,
 | 
				
			||||||
 | 
					            order.makerAssetAmount);
 | 
				
			||||||
 | 
					        fillResults.makerFeePaid = getPartialAmount(
 | 
				
			||||||
 | 
					            fillResults.takerAssetFilledAmount,
 | 
				
			||||||
 | 
					            order.takerAssetAmount,
 | 
				
			||||||
 | 
					            order.makerFee);
 | 
				
			||||||
 | 
					        fillResults.takerFeePaid = getPartialAmount(
 | 
				
			||||||
 | 
					            fillResults.takerAssetFilledAmount,
 | 
				
			||||||
 | 
					            order.takerAssetAmount,
 | 
				
			||||||
 | 
					            order.takerFee);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status = uint8(Status.SUCCESS);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Updates state with results of a fill order.
 | 
				
			||||||
 | 
					    /// @param order that was filled.
 | 
				
			||||||
 | 
					    /// @param takerAddress Address of taker who filled the order.
 | 
				
			||||||
 | 
					    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function updateFilledState(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        address takerAddress,
 | 
				
			||||||
 | 
					        bytes32 orderHash,
 | 
				
			||||||
 | 
					        FillResults memory fillResults)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Update state
 | 
				
			||||||
 | 
					        filled[orderHash] = safeAdd(filled[orderHash], fillResults.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Log order
 | 
				
			||||||
 | 
					        emitFillEvent(order, takerAddress, orderHash, fillResults);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Fills the input order.
 | 
				
			||||||
 | 
					    /// @param order Order struct containing order specifications.
 | 
				
			||||||
 | 
					    /// @param takerAssetFillAmount Desired amount of takerToken to sell.
 | 
				
			||||||
 | 
					    /// @param signature Proof that order has been created by maker.
 | 
				
			||||||
 | 
					    /// @return Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function fillOrder(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount,
 | 
				
			||||||
 | 
					        bytes memory signature)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        returns (FillResults memory fillResults)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Fetch current order status
 | 
				
			||||||
 | 
					        bytes32 orderHash;
 | 
				
			||||||
 | 
					        uint8 orderStatus;
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount;
 | 
				
			||||||
 | 
					        (orderStatus, orderHash, takerAssetFilledAmount) = getOrderInfo(order);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Fetch taker address
 | 
				
			||||||
 | 
					        address takerAddress = getCurrentContextAddress();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Either our context is valid or we revert
 | 
				
			||||||
 | 
					        validateFillOrderContextOrRevert(order, orderStatus, orderHash, takerAssetFilledAmount, signature, takerAddress, takerAssetFillAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Compute proportional fill amounts
 | 
				
			||||||
 | 
					        uint8 status;
 | 
				
			||||||
 | 
					        (status, fillResults) = calculateFillResults(order, orderStatus, takerAssetFilledAmount, takerAssetFillAmount);
 | 
				
			||||||
 | 
					        if (status != uint8(Status.SUCCESS)) {
 | 
				
			||||||
 | 
					            emit ExchangeStatus(uint8(status), orderHash);
 | 
				
			||||||
 | 
					            return fillResults;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Settle order
 | 
				
			||||||
 | 
					        (fillResults.makerAssetFilledAmount, fillResults.makerFeePaid, fillResults.takerFeePaid) =
 | 
				
			||||||
 | 
					            settleOrder(order, takerAddress, fillResults.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update exchange internal state
 | 
				
			||||||
 | 
					        updateFilledState(order, takerAddress, orderHash, fillResults);
 | 
				
			||||||
 | 
					        return fillResults;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Validates context for cancelOrder. Succeeds or throws.
 | 
				
			||||||
 | 
					    /// @param order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderHash Hash of order that was cancelled.
 | 
				
			||||||
 | 
					    function validateCancelOrderContextOrRevert(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Ensure order is valid
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            orderStatus != uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT),
 | 
				
			||||||
 | 
					            INVALID_ORDER_MAKER_ASSET_AMOUNT
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            orderStatus != uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT),
 | 
				
			||||||
 | 
					            INVALID_ORDER_TAKER_ASSET_AMOUNT
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate transaction signed by maker
 | 
				
			||||||
 | 
					        address makerAddress = getCurrentContextAddress();
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            order.makerAddress == makerAddress,
 | 
				
			||||||
 | 
					            INVALID_CONTEXT
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate sender is allowed to cancel this order
 | 
				
			||||||
 | 
					        if (order.senderAddress != address(0)) {
 | 
				
			||||||
 | 
					            require(
 | 
				
			||||||
 | 
					                order.senderAddress == msg.sender,
 | 
				
			||||||
 | 
					                INVALID_SENDER
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Updates state with results of cancelling an order.
 | 
				
			||||||
 | 
					    ///      State is only updated if the order is currently fillable.
 | 
				
			||||||
 | 
					    ///      Otherwise, updating state would have no effect.
 | 
				
			||||||
 | 
					    /// @param order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderHash Hash of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @return stateUpdated Returns true only if state was updated.
 | 
				
			||||||
 | 
					    function updateCancelledState(
 | 
				
			||||||
 | 
					        Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        returns (bool stateUpdated)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Ensure order is fillable (otherwise cancelling does nothing)
 | 
				
			||||||
 | 
					        if (orderStatus != uint8(Status.ORDER_FILLABLE)) {
 | 
				
			||||||
 | 
					            emit ExchangeStatus(uint8(orderStatus), orderHash);
 | 
				
			||||||
 | 
					            stateUpdated = false;
 | 
				
			||||||
 | 
					            return stateUpdated;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Perform cancel
 | 
				
			||||||
 | 
					        cancelled[orderHash] = true;
 | 
				
			||||||
 | 
					        stateUpdated = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Log cancel
 | 
				
			||||||
 | 
					        emit Cancel(
 | 
				
			||||||
 | 
					            order.makerAddress,
 | 
				
			||||||
 | 
					            order.feeRecipientAddress,
 | 
				
			||||||
 | 
					            orderHash,
 | 
				
			||||||
 | 
					            order.makerAssetData,
 | 
				
			||||||
 | 
					            order.takerAssetData
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return stateUpdated;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev After calling, the order can not be filled anymore.
 | 
				
			||||||
 | 
					    /// @param order Order struct containing order specifications.
 | 
				
			||||||
 | 
					    /// @return True if the order state changed to cancelled.
 | 
				
			||||||
 | 
					    ///         False if the transaction was already cancelled or expired.
 | 
				
			||||||
 | 
					    function cancelOrder(Order memory order)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        returns (bool)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Fetch current order status
 | 
				
			||||||
 | 
					        bytes32 orderHash;
 | 
				
			||||||
 | 
					        uint8 orderStatus;
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount;
 | 
				
			||||||
 | 
					        (orderStatus, orderHash, takerAssetFilledAmount) = getOrderInfo(order);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate context
 | 
				
			||||||
 | 
					        validateCancelOrderContextOrRevert(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.
 | 
					    /// @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.
 | 
					    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
				
			||||||
    function cancelOrdersUpTo(uint256 salt)
 | 
					    function cancelOrdersUpTo(uint256 salt)
 | 
				
			||||||
@@ -62,162 +406,6 @@ contract MixinExchangeCore is
 | 
				
			|||||||
        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
					        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @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 fillOrder(
 | 
					 | 
				
			||||||
        Order memory order,
 | 
					 | 
				
			||||||
        uint256 takerAssetFillAmount,
 | 
					 | 
				
			||||||
        bytes memory signature)
 | 
					 | 
				
			||||||
        public
 | 
					 | 
				
			||||||
        returns (FillResults memory fillResults)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Compute the order hash
 | 
					 | 
				
			||||||
        bytes32 orderHash = getOrderHash(order);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check if order has been cancelled by salt value
 | 
					 | 
				
			||||||
        if (order.salt < makerEpoch[order.makerAddress]) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash);
 | 
					 | 
				
			||||||
            return fillResults;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check if order has been cancelled by orderHash
 | 
					 | 
				
			||||||
        if (cancelled[orderHash]) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash);
 | 
					 | 
				
			||||||
            return fillResults;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate order and maker only if first time seen
 | 
					 | 
				
			||||||
        // TODO: Read filled and cancelled only once
 | 
					 | 
				
			||||||
        if (filled[orderHash] == 0) {
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                order.makerAssetAmount > 0,
 | 
					 | 
				
			||||||
                GT_ZERO_AMOUNT_REQUIRED
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                order.takerAssetAmount > 0,
 | 
					 | 
				
			||||||
                GT_ZERO_AMOUNT_REQUIRED
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                isValidSignature(orderHash, order.makerAddress, signature),
 | 
					 | 
				
			||||||
                SIGNATURE_VALIDATION_FAILED
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        // Validate sender is allowed to fill this order
 | 
					 | 
				
			||||||
        if (order.senderAddress != address(0)) {
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                order.senderAddress == msg.sender,
 | 
					 | 
				
			||||||
                INVALID_SENDER
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate taker is allowed to fill this order
 | 
					 | 
				
			||||||
        address takerAddress = getCurrentContextAddress();
 | 
					 | 
				
			||||||
        if (order.takerAddress != address(0)) {
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                order.takerAddress == takerAddress,
 | 
					 | 
				
			||||||
                INVALID_CONTEXT
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            takerAssetFillAmount > 0,
 | 
					 | 
				
			||||||
            GT_ZERO_AMOUNT_REQUIRED
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate order expiration
 | 
					 | 
				
			||||||
        if (block.timestamp >= order.expirationTimeSeconds) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_EXPIRED), orderHash);
 | 
					 | 
				
			||||||
            return fillResults;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate order availability
 | 
					 | 
				
			||||||
        uint256 remainingTakerAssetFillAmount = safeSub(order.takerAssetAmount, filled[orderHash]);
 | 
					 | 
				
			||||||
        if (remainingTakerAssetFillAmount == 0) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_FULLY_FILLED), orderHash);
 | 
					 | 
				
			||||||
            return fillResults;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate fill order rounding
 | 
					 | 
				
			||||||
        fillResults.takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetFillAmount);
 | 
					 | 
				
			||||||
        if (isRoundingError(fillResults.takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount)) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), orderHash);
 | 
					 | 
				
			||||||
            fillResults.takerAssetFilledAmount = 0;
 | 
					 | 
				
			||||||
            return fillResults;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Update state
 | 
					 | 
				
			||||||
        filled[orderHash] = safeAdd(filled[orderHash], fillResults.takerAssetFilledAmount);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Settle order
 | 
					 | 
				
			||||||
        (fillResults.makerAssetFilledAmount, fillResults.makerFeePaid, fillResults.takerFeePaid) =
 | 
					 | 
				
			||||||
            settleOrder(order, takerAddress, fillResults.takerAssetFilledAmount);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Log order
 | 
					 | 
				
			||||||
        emitFillEvent(order, takerAddress, orderHash, fillResults);
 | 
					 | 
				
			||||||
        return fillResults;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev After calling, the order can not be filled anymore.
 | 
					 | 
				
			||||||
    /// @param order Order struct containing order specifications.
 | 
					 | 
				
			||||||
    /// @return True if the order state changed to cancelled.
 | 
					 | 
				
			||||||
    ///         False if the transaction was already cancelled or expired.
 | 
					 | 
				
			||||||
    function cancelOrder(Order memory order)
 | 
					 | 
				
			||||||
        public
 | 
					 | 
				
			||||||
        returns (bool)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Compute the order hash
 | 
					 | 
				
			||||||
        bytes32 orderHash = getOrderHash(order);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate the order
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            order.makerAssetAmount > 0,
 | 
					 | 
				
			||||||
            GT_ZERO_AMOUNT_REQUIRED
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            order.takerAssetAmount > 0,
 | 
					 | 
				
			||||||
            GT_ZERO_AMOUNT_REQUIRED
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate sender is allowed to cancel this order
 | 
					 | 
				
			||||||
        if (order.senderAddress != address(0)) {
 | 
					 | 
				
			||||||
            require(
 | 
					 | 
				
			||||||
                order.senderAddress == msg.sender,
 | 
					 | 
				
			||||||
                INVALID_SENDER
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        // Validate transaction signed by maker
 | 
					 | 
				
			||||||
        address makerAddress = getCurrentContextAddress();
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            order.makerAddress == makerAddress,
 | 
					 | 
				
			||||||
            INVALID_CONTEXT
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if (block.timestamp >= order.expirationTimeSeconds) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_EXPIRED), orderHash);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (cancelled[orderHash]) {
 | 
					 | 
				
			||||||
            emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cancelled[orderHash] = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        emit Cancel(
 | 
					 | 
				
			||||||
            order.makerAddress,
 | 
					 | 
				
			||||||
            order.feeRecipientAddress,
 | 
					 | 
				
			||||||
            orderHash,
 | 
					 | 
				
			||||||
            order.makerAssetData,
 | 
					 | 
				
			||||||
            order.takerAssetData
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Logs a Fill event with the given arguments.
 | 
					    /// @dev Logs a Fill event with the given arguments.
 | 
				
			||||||
    ///      The sole purpose of this function is to get around the stack variable limit.
 | 
					    ///      The sole purpose of this function is to get around the stack variable limit.
 | 
				
			||||||
    function emitFillEvent(
 | 
					    function emitFillEvent(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,285 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					  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.21;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "./mixins/MExchangeCore.sol";
 | 
				
			||||||
 | 
					import "./mixins/MMatchOrders.sol";
 | 
				
			||||||
 | 
					import "./mixins/MSettlement.sol";
 | 
				
			||||||
 | 
					import "./mixins/MTransactions.sol";
 | 
				
			||||||
 | 
					import "../../utils/SafeMath/SafeMath.sol";
 | 
				
			||||||
 | 
					import "./libs/LibMath.sol";
 | 
				
			||||||
 | 
					import "./libs/LibOrder.sol";
 | 
				
			||||||
 | 
					import "./libs/LibStatus.sol";
 | 
				
			||||||
 | 
					import "../../utils/LibBytes/LibBytes.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contract MixinMatchOrders is
 | 
				
			||||||
 | 
					    SafeMath,
 | 
				
			||||||
 | 
					    LibBytes,
 | 
				
			||||||
 | 
					    LibMath,
 | 
				
			||||||
 | 
					    LibStatus,
 | 
				
			||||||
 | 
					    LibOrder,
 | 
				
			||||||
 | 
					    MExchangeCore,
 | 
				
			||||||
 | 
					    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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The leftOrder taker asset must be the same as the rightOrder maker asset.
 | 
				
			||||||
 | 
					        require(areBytesEqual(leftOrder.takerAssetData, rightOrder.makerAssetData));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 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)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @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's maker.
 | 
				
			||||||
 | 
					        // If the amount transferred from the right order is greater 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(matchedFillResults.right.makerAssetFilledAmount >= matchedFillResults.left.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        require(!isRoundingError(matchedFillResults.right.makerAssetFilledAmount, matchedFillResults.left.takerAssetFilledAmount, 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @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));
 | 
				
			||||||
 | 
					        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: 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: 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
 | 
				
			||||||
 | 
					    ///      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(
 | 
				
			||||||
 | 
					        Order memory leftOrder,
 | 
				
			||||||
 | 
					        Order memory rightOrder,
 | 
				
			||||||
 | 
					        bytes leftSignature,
 | 
				
			||||||
 | 
					        bytes rightSignature)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        returns (MatchedFillResults memory matchedFillResults)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Get left status
 | 
				
			||||||
 | 
					        OrderInfo memory leftOrderInfo;
 | 
				
			||||||
 | 
					        (   leftOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderFilledAmount
 | 
				
			||||||
 | 
					        ) = getOrderInfo(leftOrder);
 | 
				
			||||||
 | 
					        if (leftOrderInfo.orderStatus != uint8(Status.ORDER_FILLABLE)) {
 | 
				
			||||||
 | 
					            emit ExchangeStatus(uint8(leftOrderInfo.orderStatus), leftOrderInfo.orderHash);
 | 
				
			||||||
 | 
					            return matchedFillResults;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get right status
 | 
				
			||||||
 | 
					        OrderInfo memory rightOrderInfo;
 | 
				
			||||||
 | 
					        (   rightOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderFilledAmount
 | 
				
			||||||
 | 
					        ) = getOrderInfo(rightOrder);
 | 
				
			||||||
 | 
					        if (rightOrderInfo.orderStatus != uint8(Status.ORDER_FILLABLE)) {
 | 
				
			||||||
 | 
					            emit ExchangeStatus(uint8(rightOrderInfo.orderStatus), rightOrderInfo.orderHash);
 | 
				
			||||||
 | 
					            return matchedFillResults;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Fetch taker address
 | 
				
			||||||
 | 
					        address takerAddress = getCurrentContextAddress();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Either our context is valid or we revert
 | 
				
			||||||
 | 
					        validateMatchOrdersContextOrRevert(leftOrder, rightOrder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Compute proportional fill amounts
 | 
				
			||||||
 | 
					        uint8 matchedFillAmountsStatus;
 | 
				
			||||||
 | 
					        (   matchedFillAmountsStatus,
 | 
				
			||||||
 | 
					            matchedFillResults
 | 
				
			||||||
 | 
					        ) = calculateMatchedFillResults(
 | 
				
			||||||
 | 
					            leftOrder,
 | 
				
			||||||
 | 
					            rightOrder,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderFilledAmount,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderFilledAmount);
 | 
				
			||||||
 | 
					        if (matchedFillAmountsStatus != uint8(Status.SUCCESS)) {
 | 
				
			||||||
 | 
					            return matchedFillResults;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate fill contexts
 | 
				
			||||||
 | 
					        validateFillOrderContextOrRevert(
 | 
				
			||||||
 | 
					            leftOrder,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderFilledAmount,
 | 
				
			||||||
 | 
					            leftSignature,
 | 
				
			||||||
 | 
					            rightOrder.makerAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.left.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        validateFillOrderContextOrRevert(
 | 
				
			||||||
 | 
					            rightOrder,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderStatus,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderFilledAmount,
 | 
				
			||||||
 | 
					            rightSignature,
 | 
				
			||||||
 | 
					            leftOrder.makerAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.right.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Settle matched orders. Succeeds or throws.
 | 
				
			||||||
 | 
					        settleMatchedOrders(leftOrder, rightOrder, matchedFillResults, takerAddress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update exchange state
 | 
				
			||||||
 | 
					        updateFilledState(
 | 
				
			||||||
 | 
					            leftOrder,
 | 
				
			||||||
 | 
					            rightOrder.makerAddress,
 | 
				
			||||||
 | 
					            leftOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            matchedFillResults.left
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        updateFilledState(
 | 
				
			||||||
 | 
					            rightOrder,
 | 
				
			||||||
 | 
					            leftOrder.makerAddress,
 | 
				
			||||||
 | 
					            rightOrderInfo.orderHash,
 | 
				
			||||||
 | 
					            matchedFillResults.right
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Return results
 | 
				
			||||||
 | 
					        return matchedFillResults;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -22,9 +22,11 @@ import "./mixins/MSettlement.sol";
 | 
				
			|||||||
import "./mixins/MAssetProxyDispatcher.sol";
 | 
					import "./mixins/MAssetProxyDispatcher.sol";
 | 
				
			||||||
import "./libs/LibOrder.sol";
 | 
					import "./libs/LibOrder.sol";
 | 
				
			||||||
import "./libs/LibMath.sol";
 | 
					import "./libs/LibMath.sol";
 | 
				
			||||||
 | 
					import "./mixins/MMatchOrders.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MixinSettlement is
 | 
					contract MixinSettlement is
 | 
				
			||||||
    LibMath,
 | 
					    LibMath,
 | 
				
			||||||
 | 
					    MMatchOrders,
 | 
				
			||||||
    MSettlement,
 | 
					    MSettlement,
 | 
				
			||||||
    MAssetProxyDispatcher
 | 
					    MAssetProxyDispatcher
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -96,4 +98,87 @@ contract MixinSettlement is
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
        return (makerAssetFilledAmount, makerFeePaid, takerFeePaid);
 | 
					        return (makerAssetFilledAmount, makerFeePaid, takerFeePaid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
 | 
				
			||||||
 | 
					    /// @param leftOrder First matched order.
 | 
				
			||||||
 | 
					    /// @param rightOrder Second matched order.
 | 
				
			||||||
 | 
					    /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
 | 
				
			||||||
 | 
					    /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
 | 
				
			||||||
 | 
					    function settleMatchedOrders(
 | 
				
			||||||
 | 
					        LibOrder.Order memory leftOrder,
 | 
				
			||||||
 | 
					        LibOrder.Order memory rightOrder,
 | 
				
			||||||
 | 
					        MatchedFillResults memory matchedFillResults,
 | 
				
			||||||
 | 
					        address takerAddress)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Optimized for:
 | 
				
			||||||
 | 
					        // * leftOrder.feeRecipient =?= rightOrder.feeRecipient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Not optimized for:
 | 
				
			||||||
 | 
					        // * {left, right}.{MakerAsset, TakerAsset} == ZRX
 | 
				
			||||||
 | 
					        // * {left, right}.maker, takerAddress == {left, right}.feeRecipient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // leftOrder.MakerAsset == rightOrder.TakerAsset
 | 
				
			||||||
 | 
					        // Taker should be left with a positive balance (the spread)
 | 
				
			||||||
 | 
					        dispatchTransferFrom(
 | 
				
			||||||
 | 
					            leftOrder.makerAssetData,
 | 
				
			||||||
 | 
					            leftOrder.makerAddress,
 | 
				
			||||||
 | 
					            takerAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.left.makerAssetFilledAmount);
 | 
				
			||||||
 | 
					        dispatchTransferFrom(
 | 
				
			||||||
 | 
					            leftOrder.makerAssetData,
 | 
				
			||||||
 | 
					            takerAddress,
 | 
				
			||||||
 | 
					            rightOrder.makerAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.right.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // rightOrder.MakerAsset == leftOrder.TakerAsset
 | 
				
			||||||
 | 
					        // leftOrder.takerAssetFilledAmount ~ rightOrder.makerAssetFilledAmount
 | 
				
			||||||
 | 
					        // The change goes to right, not to taker.
 | 
				
			||||||
 | 
					        assert(matchedFillResults.right.makerAssetFilledAmount >= matchedFillResults.left.takerAssetFilledAmount);
 | 
				
			||||||
 | 
					        dispatchTransferFrom(
 | 
				
			||||||
 | 
					            rightOrder.makerAssetData,
 | 
				
			||||||
 | 
					            rightOrder.makerAddress,
 | 
				
			||||||
 | 
					            leftOrder.makerAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.right.makerAssetFilledAmount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Maker fees
 | 
				
			||||||
 | 
					        dispatchTransferFrom(
 | 
				
			||||||
 | 
					            ZRX_PROXY_DATA,
 | 
				
			||||||
 | 
					            leftOrder.makerAddress,
 | 
				
			||||||
 | 
					            leftOrder.feeRecipientAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.left.makerFeePaid);
 | 
				
			||||||
 | 
					        dispatchTransferFrom(
 | 
				
			||||||
 | 
					            ZRX_PROXY_DATA,
 | 
				
			||||||
 | 
					            rightOrder.makerAddress,
 | 
				
			||||||
 | 
					            rightOrder.feeRecipientAddress,
 | 
				
			||||||
 | 
					            matchedFillResults.right.makerFeePaid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Taker fees
 | 
				
			||||||
 | 
					        // If we assume distinct(left, right, takerAddress) and
 | 
				
			||||||
 | 
					        // distinct(MakerAsset, TakerAsset, zrx) then the only remaining
 | 
				
			||||||
 | 
					        // opportunity for optimization is when both feeRecipientAddress' are
 | 
				
			||||||
 | 
					        // the same.
 | 
				
			||||||
 | 
					        if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
 | 
				
			||||||
 | 
					            dispatchTransferFrom(
 | 
				
			||||||
 | 
					                ZRX_PROXY_DATA,
 | 
				
			||||||
 | 
					                takerAddress,
 | 
				
			||||||
 | 
					                leftOrder.feeRecipientAddress,
 | 
				
			||||||
 | 
					                safeAdd(
 | 
				
			||||||
 | 
					                    matchedFillResults.left.takerFeePaid,
 | 
				
			||||||
 | 
					                    matchedFillResults.right.takerFeePaid
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            dispatchTransferFrom(
 | 
				
			||||||
 | 
					                ZRX_PROXY_DATA,
 | 
				
			||||||
 | 
					                takerAddress,
 | 
				
			||||||
 | 
					                leftOrder.feeRecipientAddress,
 | 
				
			||||||
 | 
					                matchedFillResults.left.takerFeePaid);
 | 
				
			||||||
 | 
					            dispatchTransferFrom(
 | 
				
			||||||
 | 
					                ZRX_PROXY_DATA,
 | 
				
			||||||
 | 
					                takerAddress,
 | 
				
			||||||
 | 
					                rightOrder.feeRecipientAddress,
 | 
				
			||||||
 | 
					                matchedFillResults.right.takerFeePaid);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,10 +27,11 @@ import "./libs/LibFillResults.sol";
 | 
				
			|||||||
import "./libs/LibExchangeErrors.sol";
 | 
					import "./libs/LibExchangeErrors.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MixinWrapperFunctions is
 | 
					contract MixinWrapperFunctions is
 | 
				
			||||||
 | 
					    SafeMath,
 | 
				
			||||||
 | 
					    LibBytes,
 | 
				
			||||||
 | 
					    LibMath,
 | 
				
			||||||
    LibOrder,
 | 
					    LibOrder,
 | 
				
			||||||
    LibFillResults,
 | 
					    LibFillResults,
 | 
				
			||||||
    LibMath,
 | 
					 | 
				
			||||||
    LibBytes,
 | 
					 | 
				
			||||||
    LibExchangeErrors,
 | 
					    LibExchangeErrors,
 | 
				
			||||||
    MExchangeCore
 | 
					    MExchangeCore
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,10 @@ import "./libs/LibOrder.sol";
 | 
				
			|||||||
import "./libs/LibFillResults.sol";
 | 
					import "./libs/LibFillResults.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract IWrapperFunctions is
 | 
					contract IWrapperFunctions is
 | 
				
			||||||
 | 
					    LibBytes,
 | 
				
			||||||
 | 
					    LibMath,
 | 
				
			||||||
    LibOrder,
 | 
					    LibOrder,
 | 
				
			||||||
    LibFillResults,
 | 
					    LibFillResults,
 | 
				
			||||||
    LibMath,
 | 
					 | 
				
			||||||
    LibBytes,
 | 
					 | 
				
			||||||
    LibExchangeErrors,
 | 
					    LibExchangeErrors,
 | 
				
			||||||
    MExchangeCore
 | 
					    MExchangeCore
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,17 +20,6 @@ pragma solidity ^0.4.23;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
contract LibExchangeErrors {
 | 
					contract LibExchangeErrors {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Error Codes
 | 
					 | 
				
			||||||
    enum Errors {
 | 
					 | 
				
			||||||
        ORDER_EXPIRED,                     // Order has already expired
 | 
					 | 
				
			||||||
        ORDER_FULLY_FILLED,                // Order has already been fully filled
 | 
					 | 
				
			||||||
        ORDER_CANCELLED,                   // Order has already been cancelled
 | 
					 | 
				
			||||||
        ROUNDING_ERROR_TOO_LARGE,          // Rounding error too large
 | 
					 | 
				
			||||||
        INSUFFICIENT_BALANCE_OR_ALLOWANCE  // Insufficient balance or allowance for token transfer
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    event ExchangeError(uint8 indexed errorId, bytes32 indexed orderHash);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Core revert reasons
 | 
					    // Core revert reasons
 | 
				
			||||||
    string constant GT_ZERO_AMOUNT_REQUIRED = "Amount must be greater than 0.";
 | 
					    string constant GT_ZERO_AMOUNT_REQUIRED = "Amount must be greater than 0.";
 | 
				
			||||||
    string constant SIGNATURE_VALIDATION_FAILED = "Signature validation failed.";
 | 
					    string constant SIGNATURE_VALIDATION_FAILED = "Signature validation failed.";
 | 
				
			||||||
@@ -38,6 +27,10 @@ contract LibExchangeErrors {
 | 
				
			|||||||
    string constant INVALID_CONTEXT = "Function called in an invalid context.";
 | 
					    string constant INVALID_CONTEXT = "Function called in an invalid context.";
 | 
				
			||||||
    string constant INVALID_NEW_MAKER_EPOCH = "Specified salt must be greater than or equal to existing makerEpoch.";
 | 
					    string constant INVALID_NEW_MAKER_EPOCH = "Specified salt must be greater than or equal to existing makerEpoch.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Order revert reasons
 | 
				
			||||||
 | 
					    string constant INVALID_ORDER_TAKER_ASSET_AMOUNT = "Invalid order taker asset amount: expected a non-zero value.";
 | 
				
			||||||
 | 
					    string constant INVALID_ORDER_MAKER_ASSET_AMOUNT = "Invalid order maker asset amount: expected a non-zero value.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Transaction revert reasons
 | 
					    // Transaction revert reasons
 | 
				
			||||||
    string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
 | 
					    string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
 | 
				
			||||||
    string constant TRANSACTION_EXECUTION_FAILED = "Transaction execution failed.";
 | 
					    string constant TRANSACTION_EXECUTION_FAILED = "Transaction execution failed.";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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.21;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contract LibStatus {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Exchange Status Codes
 | 
				
			||||||
 | 
					    enum Status {
 | 
				
			||||||
 | 
					        /// Default Status ///
 | 
				
			||||||
 | 
					        INVALID,                                // General invalid status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// General Exchange Statuses ///
 | 
				
			||||||
 | 
					        SUCCESS,                                // Indicates a successful operation
 | 
				
			||||||
 | 
					        ROUNDING_ERROR_TOO_LARGE,               // Rounding error too large
 | 
				
			||||||
 | 
					        INSUFFICIENT_BALANCE_OR_ALLOWANCE,      // Insufficient balance or allowance for token transfer
 | 
				
			||||||
 | 
					        TAKER_ASSET_FILL_AMOUNT_TOO_LOW,        // takerAssetFillAmount is <= 0
 | 
				
			||||||
 | 
					        INVALID_SIGNATURE,                      // Invalid signature
 | 
				
			||||||
 | 
					        INVALID_SENDER,                         // Invalid sender
 | 
				
			||||||
 | 
					        INVALID_TAKER,                          // Invalid taker
 | 
				
			||||||
 | 
					        INVALID_MAKER,                          // Invalid maker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// Order State Statuses ///
 | 
				
			||||||
 | 
					        ORDER_INVALID_MAKER_ASSET_AMOUNT,       // Order does not have a valid maker asset amount
 | 
				
			||||||
 | 
					        ORDER_INVALID_TAKER_ASSET_AMOUNT,       // Order does not have a valid taker asset amount
 | 
				
			||||||
 | 
					        ORDER_FILLABLE,                         // Order is fillable
 | 
				
			||||||
 | 
					        ORDER_EXPIRED,                          // Order has already expired
 | 
				
			||||||
 | 
					        ORDER_FULLY_FILLED,                     // Order is fully filled
 | 
				
			||||||
 | 
					        ORDER_CANCELLED                         // Order has been cancelled
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    event ExchangeStatus(uint8 indexed statusId, bytes32 indexed orderHash);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pragma solidity ^0.4.23;
 | 
					pragma solidity ^0.4.23;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../interfaces/IAssetProxyDispatcher.sol";
 | 
					import "../interfaces/IAssetProxyDispatcher.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pragma solidity ^0.4.23;
 | 
					pragma solidity ^0.4.23;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../libs/LibOrder.sol";
 | 
					import "../libs/LibOrder.sol";
 | 
				
			||||||
import "../libs/LibFillResults.sol";
 | 
					import "../libs/LibFillResults.sol";
 | 
				
			||||||
@@ -63,4 +64,122 @@ contract MExchangeCore is
 | 
				
			|||||||
        bytes32 orderHash,
 | 
					        bytes32 orderHash,
 | 
				
			||||||
        LibFillResults.FillResults memory fillResults)
 | 
					        LibFillResults.FillResults memory fillResults)
 | 
				
			||||||
        internal;
 | 
					        internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Gets information about an order.
 | 
				
			||||||
 | 
					    /// @param order Order to gather information on.
 | 
				
			||||||
 | 
					    /// @return status Status of order. Statuses are defined in the LibStatus.Status struct.
 | 
				
			||||||
 | 
					    /// @return orderHash Keccak-256 EIP712 hash of the order.
 | 
				
			||||||
 | 
					    /// @return takerAssetFilledAmount Amount of order that has been filled.
 | 
				
			||||||
 | 
					    function getOrderInfo(LibOrder.Order memory order)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (
 | 
				
			||||||
 | 
					            uint8 orderStatus,
 | 
				
			||||||
 | 
					            bytes32 orderHash,
 | 
				
			||||||
 | 
					            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 takerAssetFillAmount Desired amount of order to fill by taker.
 | 
				
			||||||
 | 
					    function validateFillOrderContextOrRevert(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash,
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount,
 | 
				
			||||||
 | 
					        bytes memory signature,
 | 
				
			||||||
 | 
					        address takerAddress,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount)
 | 
				
			||||||
 | 
					        internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Calculates amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    /// @param order to be filled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order to be filled.
 | 
				
			||||||
 | 
					    /// @param takerAssetFilledAmount Amount of order already filled.
 | 
				
			||||||
 | 
					    /// @param takerAssetFillAmount Desired amount of order to fill by taker.
 | 
				
			||||||
 | 
					    /// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
 | 
				
			||||||
 | 
					    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function calculateFillResults(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        uint256 takerAssetFilledAmount,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        pure
 | 
				
			||||||
 | 
					        returns (
 | 
				
			||||||
 | 
					            uint8 status,
 | 
				
			||||||
 | 
					            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.
 | 
				
			||||||
 | 
					    /// @return fillResults Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function updateFilledState(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        address takerAddress,
 | 
				
			||||||
 | 
					        bytes32 orderHash,
 | 
				
			||||||
 | 
					        LibFillResults.FillResults memory fillResults)
 | 
				
			||||||
 | 
					        internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Fills the input order.
 | 
				
			||||||
 | 
					    /// @param order Order struct containing order specifications.
 | 
				
			||||||
 | 
					    /// @param takerAssetFillAmount Desired amount of takerToken to sell.
 | 
				
			||||||
 | 
					    /// @param signature Proof that order has been created by maker.
 | 
				
			||||||
 | 
					    /// @return Amounts filled and fees paid by maker and taker.
 | 
				
			||||||
 | 
					    function fillOrder(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        uint256 takerAssetFillAmount,
 | 
				
			||||||
 | 
					        bytes memory signature)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        returns (LibFillResults.FillResults memory fillResults);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Validates context for cancelOrder. Succeeds or throws.
 | 
				
			||||||
 | 
					    /// @param order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderHash Hash of order that was cancelled.
 | 
				
			||||||
 | 
					    function validateCancelOrderContextOrRevert(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash)
 | 
				
			||||||
 | 
					        internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Updates state with results of cancelling an order.
 | 
				
			||||||
 | 
					    ///      State is only updated if the order is currently fillable.
 | 
				
			||||||
 | 
					    ///      Otherwise, updating state would have no effect.
 | 
				
			||||||
 | 
					    /// @param order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderStatus Status of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @param orderHash Hash of order that was cancelled.
 | 
				
			||||||
 | 
					    /// @return stateUpdated Returns true only if state was updated.
 | 
				
			||||||
 | 
					    function updateCancelledState(
 | 
				
			||||||
 | 
					        LibOrder.Order memory order,
 | 
				
			||||||
 | 
					        uint8 orderStatus,
 | 
				
			||||||
 | 
					        bytes32 orderHash)
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        returns (bool stateUpdated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev After calling, the order can not be filled anymore.
 | 
				
			||||||
 | 
					    /// @param order Order struct containing order specifications.
 | 
				
			||||||
 | 
					    /// @return True if the order state changed to cancelled.
 | 
				
			||||||
 | 
					    ///         False if the transaction was already cancelled or expired.
 | 
				
			||||||
 | 
					    function cancelOrder(LibOrder.Order memory order)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        returns (bool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
				
			||||||
 | 
					    function cancelOrdersUpTo(uint256 salt)
 | 
				
			||||||
 | 
					        external;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    /// @dev Checks if rounding error > 0.1%.
 | 
				
			||||||
 | 
					    /// @param numerator Numerator.
 | 
				
			||||||
 | 
					    /// @param denominator Denominator.
 | 
				
			||||||
 | 
					    /// @param target Value to multiply with numerator/denominator.
 | 
				
			||||||
 | 
					    /// @return Rounding error is present.
 | 
				
			||||||
 | 
					    function isRoundingError(uint256 numerator, uint256 denominator, uint256 target)
 | 
				
			||||||
 | 
					        public pure
 | 
				
			||||||
 | 
					        returns (bool isError); */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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.21;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "../libs/LibOrder.sol";
 | 
				
			||||||
 | 
					import "../libs/LibFillResults.sol";
 | 
				
			||||||
 | 
					import "./MExchangeCore.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contract MMatchOrders {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct MatchedFillResults {
 | 
				
			||||||
 | 
					        LibFillResults.FillResults left;
 | 
				
			||||||
 | 
					        LibFillResults.FillResults right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// This struct exists solely to avoid the stack limit constraint
 | 
				
			||||||
 | 
					    /// in matchOrders
 | 
				
			||||||
 | 
					    struct OrderInfo {
 | 
				
			||||||
 | 
					        uint8 orderStatus;
 | 
				
			||||||
 | 
					        bytes32 orderHash;
 | 
				
			||||||
 | 
					        uint256 orderFilledAmount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Validates context for matchOrders. Succeeds or throws.
 | 
				
			||||||
 | 
					    /// @param leftOrder First order to match.
 | 
				
			||||||
 | 
					    /// @param rightOrder Second order to match.
 | 
				
			||||||
 | 
					    function validateMatchOrdersContextOrRevert(
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					        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.
 | 
				
			||||||
 | 
					    ///      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(
 | 
				
			||||||
 | 
					        LibOrder.Order memory leftOrder,
 | 
				
			||||||
 | 
					        LibOrder.Order memory rightOrder,
 | 
				
			||||||
 | 
					        uint8 leftOrderStatus,
 | 
				
			||||||
 | 
					        uint8 rightOrderStatus,
 | 
				
			||||||
 | 
					        uint256 leftOrderFilledAmount,
 | 
				
			||||||
 | 
					        uint256 rightOrderFilledAmount)
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
pragma solidity ^0.4.23;
 | 
					pragma solidity ^0.4.23;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../libs/LibOrder.sol";
 | 
					import "../libs/LibOrder.sol";
 | 
				
			||||||
 | 
					import "./MMatchOrders.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract MSettlement {
 | 
					contract MSettlement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,5 +38,16 @@ contract MSettlement {
 | 
				
			|||||||
            uint256 makerFeePaid,
 | 
					            uint256 makerFeePaid,
 | 
				
			||||||
            uint256 takerFeePaid
 | 
					            uint256 takerFeePaid
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
 | 
				
			||||||
 | 
					    /// @param leftOrder First matched order.
 | 
				
			||||||
 | 
					    /// @param rightOrder Second matched order.
 | 
				
			||||||
 | 
					    /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
 | 
				
			||||||
 | 
					    /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
 | 
				
			||||||
 | 
					    function settleMatchedOrders(
 | 
				
			||||||
 | 
					        LibOrder.Order memory leftOrder,
 | 
				
			||||||
 | 
					        LibOrder.Order memory rightOrder,
 | 
				
			||||||
 | 
					        MMatchOrders.MatchedFillResults memory matchedFillResults,
 | 
				
			||||||
 | 
					        address takerAddress)
 | 
				
			||||||
 | 
					        internal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,4 +38,4 @@ contract TestSignatureValidator is MixinSignatureValidator {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
        return isValid;
 | 
					        return isValid;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user