Atomic Order Matching - Smart Contracts.
This commit is contained in:
		@@ -25,24 +25,28 @@ import "./MixinSettlement.sol";
 | 
			
		||||
import "./MixinWrapperFunctions.sol";
 | 
			
		||||
import "./MixinAssetProxyDispatcher.sol";
 | 
			
		||||
import "./MixinTransactions.sol";
 | 
			
		||||
import "./MixinMatchOrders.sol";
 | 
			
		||||
 | 
			
		||||
contract Exchange is
 | 
			
		||||
    MixinWrapperFunctions,
 | 
			
		||||
    MixinExchangeCore,
 | 
			
		||||
    MixinMatchOrders,
 | 
			
		||||
    MixinSettlement,
 | 
			
		||||
    MixinSignatureValidator,
 | 
			
		||||
    MixinTransactions,
 | 
			
		||||
    MixinAssetProxyDispatcher
 | 
			
		||||
    MixinAssetProxyDispatcher,
 | 
			
		||||
    MixinWrapperFunctions
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    string constant public VERSION = "2.0.1-alpha";
 | 
			
		||||
 | 
			
		||||
    constructor (bytes memory _zrxProxyData)
 | 
			
		||||
        public
 | 
			
		||||
        MixinExchangeCore()
 | 
			
		||||
        MixinSignatureValidator()
 | 
			
		||||
        MixinMatchOrders()
 | 
			
		||||
        MixinSettlement(_zrxProxyData)
 | 
			
		||||
        MixinWrapperFunctions()
 | 
			
		||||
        MixinAssetProxyDispatcher()
 | 
			
		||||
        MixinSignatureValidator()
 | 
			
		||||
        MixinTransactions()
 | 
			
		||||
        MixinAssetProxyDispatcher()
 | 
			
		||||
        MixinWrapperFunctions()
 | 
			
		||||
    {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
 | 
			
		||||
import "./libs/LibFillResults.sol";
 | 
			
		||||
import "./libs/LibOrder.sol";
 | 
			
		||||
import "./libs/LibMath.sol";
 | 
			
		||||
import "./libs/LibStatus.sol";
 | 
			
		||||
import "./libs/LibExchangeErrors.sol";
 | 
			
		||||
import "./mixins/MExchangeCore.sol";
 | 
			
		||||
import "./mixins/MSettlement.sol";
 | 
			
		||||
@@ -29,9 +30,11 @@ import "./mixins/MSignatureValidator.sol";
 | 
			
		||||
import "./mixins/MTransactions.sol";
 | 
			
		||||
 | 
			
		||||
contract MixinExchangeCore is
 | 
			
		||||
    SafeMath,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibStatus,
 | 
			
		||||
    LibOrder,
 | 
			
		||||
    LibFillResults,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibExchangeErrors,
 | 
			
		||||
    MExchangeCore,
 | 
			
		||||
    MSettlement,
 | 
			
		||||
@@ -48,58 +51,102 @@ contract MixinExchangeCore is
 | 
			
		||||
    // Orders with a salt less than their maker's epoch are considered cancelled
 | 
			
		||||
    mapping (address => uint256) public makerEpoch;
 | 
			
		||||
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uint256 newMakerEpoch = salt + 1;  // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
 | 
			
		||||
        require(
 | 
			
		||||
            newMakerEpoch > makerEpoch[msg.sender],  // epoch must be monotonically increasing
 | 
			
		||||
            INVALID_NEW_MAKER_EPOCH
 | 
			
		||||
        );
 | 
			
		||||
        makerEpoch[msg.sender] = newMakerEpoch;
 | 
			
		||||
        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
			
		||||
    }
 | 
			
		||||
    ////// Core exchange functions //////
 | 
			
		||||
 | 
			
		||||
    /// @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)
 | 
			
		||||
    /// @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
 | 
			
		||||
        returns (FillResults memory fillResults)
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            uint8 orderStatus,
 | 
			
		||||
            bytes32 orderHash,
 | 
			
		||||
            uint256 takerAssetFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Compute the order hash
 | 
			
		||||
        bytes32 orderHash = getOrderHash(order);
 | 
			
		||||
        // Compute the order hash and fetch filled amount
 | 
			
		||||
        orderHash = getOrderHash(order);
 | 
			
		||||
        takerAssetFilledAmount = filled[orderHash];
 | 
			
		||||
 | 
			
		||||
        // Check if order has been cancelled by salt value
 | 
			
		||||
        if (order.salt < makerEpoch[order.makerAddress]) {
 | 
			
		||||
            emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash);
 | 
			
		||||
            return fillResults;
 | 
			
		||||
        // 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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if order has been cancelled by orderHash
 | 
			
		||||
        // 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]) {
 | 
			
		||||
            emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash);
 | 
			
		||||
            return fillResults;
 | 
			
		||||
            orderStatus = uint8(Status.ORDER_CANCELLED);
 | 
			
		||||
            return (orderStatus, orderHash, takerAssetFilledAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate order and maker only if first time seen
 | 
			
		||||
        // TODO: Read filled and cancelled only once
 | 
			
		||||
        if (filled[orderHash] == 0) {
 | 
			
		||||
        // 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(
 | 
			
		||||
                order.makerAssetAmount > 0,
 | 
			
		||||
                GT_ZERO_AMOUNT_REQUIRED
 | 
			
		||||
            orderStatus != uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT),
 | 
			
		||||
            INVALID_ORDER_MAKER_ASSET_AMOUNT
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
                order.takerAssetAmount > 0,
 | 
			
		||||
                GT_ZERO_AMOUNT_REQUIRED
 | 
			
		||||
            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
 | 
			
		||||
@@ -115,7 +162,6 @@ contract MixinExchangeCore is
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate taker is allowed to fill this order
 | 
			
		||||
        address takerAddress = getCurrentContextAddress();
 | 
			
		||||
        if (order.takerAddress != address(0)) {
 | 
			
		||||
            require(
 | 
			
		||||
                order.takerAddress == takerAddress,
 | 
			
		||||
@@ -126,40 +172,205 @@ contract MixinExchangeCore is
 | 
			
		||||
            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;
 | 
			
		||||
    /// @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
 | 
			
		||||
        fillResults.takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetFillAmount);
 | 
			
		||||
        if (isRoundingError(fillResults.takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount)) {
 | 
			
		||||
            emit ExchangeError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), orderHash);
 | 
			
		||||
        if (isRoundingError(
 | 
			
		||||
            fillResults.takerAssetFilledAmount,
 | 
			
		||||
            order.takerAssetAmount,
 | 
			
		||||
            order.makerAssetAmount))
 | 
			
		||||
        {
 | 
			
		||||
            status = uint8(Status.ROUNDING_ERROR_TOO_LARGE);
 | 
			
		||||
            fillResults.takerAssetFilledAmount = 0;
 | 
			
		||||
            return fillResults;
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
        // Log order
 | 
			
		||||
        emitFillEvent(order, takerAddress, orderHash, fillResults);
 | 
			
		||||
        // 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.
 | 
			
		||||
@@ -168,54 +379,31 @@ contract MixinExchangeCore is
 | 
			
		||||
        public
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        // Compute the order hash
 | 
			
		||||
        bytes32 orderHash = getOrderHash(order);
 | 
			
		||||
        // Fetch current order status
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
        uint8 orderStatus;
 | 
			
		||||
        uint256 takerAssetFilledAmount;
 | 
			
		||||
        (orderStatus, orderHash, takerAssetFilledAmount) = getOrderInfo(order);
 | 
			
		||||
 | 
			
		||||
        // Validate the order
 | 
			
		||||
        require(
 | 
			
		||||
            order.makerAssetAmount > 0,
 | 
			
		||||
            GT_ZERO_AMOUNT_REQUIRED
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
            order.takerAssetAmount > 0,
 | 
			
		||||
            GT_ZERO_AMOUNT_REQUIRED
 | 
			
		||||
        );
 | 
			
		||||
        // Validate context
 | 
			
		||||
        validateCancelOrderContextOrRevert(order, orderStatus, orderHash);
 | 
			
		||||
 | 
			
		||||
        // Validate sender is allowed to cancel this order
 | 
			
		||||
        if (order.senderAddress != address(0)) {
 | 
			
		||||
            require(
 | 
			
		||||
                order.senderAddress == msg.sender,
 | 
			
		||||
                INVALID_SENDER
 | 
			
		||||
            );
 | 
			
		||||
        // Perform cancel
 | 
			
		||||
        return updateCancelledState(order, orderStatus, orderHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Validate transaction signed by maker
 | 
			
		||||
        address makerAddress = getCurrentContextAddress();
 | 
			
		||||
    /// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
 | 
			
		||||
    /// @param salt Orders created with a salt less or equal to this value will be cancelled.
 | 
			
		||||
    function cancelOrdersUpTo(uint256 salt)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uint256 newMakerEpoch = salt + 1;  // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
 | 
			
		||||
        require(
 | 
			
		||||
            order.makerAddress == makerAddress,
 | 
			
		||||
            INVALID_CONTEXT
 | 
			
		||||
            newMakerEpoch > makerEpoch[msg.sender],  // epoch must be monotonically increasing
 | 
			
		||||
            INVALID_NEW_MAKER_EPOCH
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        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;
 | 
			
		||||
        makerEpoch[msg.sender] = newMakerEpoch;
 | 
			
		||||
        emit CancelUpTo(msg.sender, newMakerEpoch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Logs a Fill event with the given arguments.
 | 
			
		||||
 
 | 
			
		||||
@@ -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 "./libs/LibOrder.sol";
 | 
			
		||||
import "./libs/LibMath.sol";
 | 
			
		||||
import "./mixins/MMatchOrders.sol";
 | 
			
		||||
 | 
			
		||||
contract MixinSettlement is
 | 
			
		||||
    LibMath,
 | 
			
		||||
    MMatchOrders,
 | 
			
		||||
    MSettlement,
 | 
			
		||||
    MAssetProxyDispatcher
 | 
			
		||||
{
 | 
			
		||||
@@ -96,4 +98,87 @@ contract MixinSettlement is
 | 
			
		||||
        );
 | 
			
		||||
        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";
 | 
			
		||||
 | 
			
		||||
contract MixinWrapperFunctions is
 | 
			
		||||
    SafeMath,
 | 
			
		||||
    LibBytes,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibOrder,
 | 
			
		||||
    LibFillResults,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibBytes,
 | 
			
		||||
    LibExchangeErrors,
 | 
			
		||||
    MExchangeCore
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,10 @@ import "./libs/LibOrder.sol";
 | 
			
		||||
import "./libs/LibFillResults.sol";
 | 
			
		||||
 | 
			
		||||
contract IWrapperFunctions is
 | 
			
		||||
    LibBytes,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibOrder,
 | 
			
		||||
    LibFillResults,
 | 
			
		||||
    LibMath,
 | 
			
		||||
    LibBytes,
 | 
			
		||||
    LibExchangeErrors,
 | 
			
		||||
    MExchangeCore
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -20,17 +20,6 @@ pragma solidity ^0.4.23;
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
    string constant GT_ZERO_AMOUNT_REQUIRED = "Amount must be greater than 0.";
 | 
			
		||||
    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_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
 | 
			
		||||
    string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
 | 
			
		||||
    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 experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/IAssetProxyDispatcher.sol";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.4.23;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../libs/LibOrder.sol";
 | 
			
		||||
import "../libs/LibFillResults.sol";
 | 
			
		||||
@@ -63,4 +64,122 @@ contract MExchangeCore is
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        LibFillResults.FillResults memory fillResults)
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
import "../libs/LibOrder.sol";
 | 
			
		||||
import "./MMatchOrders.sol";
 | 
			
		||||
 | 
			
		||||
contract MSettlement {
 | 
			
		||||
 | 
			
		||||
@@ -37,5 +38,16 @@ contract MSettlement {
 | 
			
		||||
            uint256 makerFeePaid,
 | 
			
		||||
            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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user