Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

New Order Matching Strategy #1913

Conversation

jalextowle
Copy link
Contributor

@jalextowle jalextowle commented Jul 1, 2019

Description

These changes implements the functionality of ZEIP 40 and the remaining functionality from ZEIP 41.

image

New Order Matching Strategy

The bulk of the changes in this pull request are related to the new order matching strategy that ZEIP 40 introduces.

The new order matching strategy comes with a new function that is used to expose the functionality of the new order matching strategy:

    function matchOrdersWithMaximalFill(
        LibOrder.Order memory leftOrder,
        LibOrder.Order memory rightOrder,
        bytes memory leftSignature,
        bytes memory rightSignature
    )
        public
        nonReentrant
        returns (LibFillResults.MatchedFillResults memory matchedFillResults);

The new order matching strategy allows profit to be paid out of the left maker asset, the right maker asset, or both. There are three cases in the order matching strategy:

  • leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining, which indicates that the right order can be fully filled but the left order cannot. In this case, the profit will be paid out in the left maker asset, and the profit will be calculated as the spread in the left maker asset.
  • rightTakerAssetAmountRemaining > rightMakerAssetAmountRemaining, which indicates that the right order can be fully filled but the left order cannot. In this case, the profit will be paid out in the right maker asset, and the profit will be calculated as the spread in the right maker asset.
  • leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining && rightTakerAssetAmountRemaining <= rightMakerAssetAmountRemaining, which indicates that both orders can be fully filled. In this case, the profit will be paid out in both maker assets, and the profit will be calculated as the spread in the left maker asset and the spread in the right maker asset.

Batch Orders with Maximal Fill

A reentrant version of the function is available through the internal function _matchOrders if its argument withMaximalFill is true, which allowed a batchMatchOrdersWithMaximalFill function to be created using almost identical logic to batchMatchOrders.

Split up TestExchangeInternals

We have now reached the point where TestExchangeInternals will not deploy with all of the internal functions defined. To facilitate the process of breaking of the tests, I created a TestExchangeMath contract that only inherits the math functions of the exchange. Over time, the creation of Test contracts that only inherit from one or several mixins may become necessary if deployment costs continue to increase.

Testing instructions

yarn build:contracts && yarn test:contracts

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

  • Prefix PR title with [WIP] if necessary.
  • Add tests to cover changes as needed.
  • Update documentation as needed.
  • Add new entries to the relevant CHANGELOG.jsons.

@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 5 times, most recently from a000574 to 56127e0 Compare July 1, 2019 23:58
@jalextowle jalextowle changed the title [WIP] New Order Matching Strategy New Order Matching Strategy Jul 1, 2019
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch from 56127e0 to f373aae Compare July 2, 2019 00:13
@jalextowle

This comment has been minimized.

@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 2 times, most recently from b302ab9 to 6931c7b Compare July 2, 2019 04:47
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 4 times, most recently from aa71e59 to f639564 Compare July 2, 2019 21:50
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 4 times, most recently from 18510a7 to 83b2f96 Compare July 3, 2019 09:38
Copy link
Contributor

@dorothy-zbornak dorothy-zbornak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid work, man!

contracts/test-utils/src/types.ts Outdated Show resolved Hide resolved
contracts/exchange/test/match_orders.ts Show resolved Hide resolved
Copy link
Contributor

@hysz hysz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very clean code, nice work!

There are a few edge cases I think we should explore. I believe there are ~25 cases for the original matching strategy but only a handful for the new strategy. It might be worthwhile to copy over the original tests and update the expected output.

contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
Copy link
Member

@abandeali1 abandeali1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only done a partial review so far (haven't reviewed batch matching or tests). I'll get the rest reviewed over the next few days!

contracts/exchange-libs/contracts/src/LibFillResults.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
contracts/exchange/contracts/src/MixinMatchOrders.sol Outdated Show resolved Hide resolved
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 2 times, most recently from fa18f78 to 7d2c464 Compare July 7, 2019 06:58
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch from 857488e to e8f4219 Compare July 17, 2019 15:08
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch 4 times, most recently from 62ed45a to d469606 Compare July 17, 2019 19:18
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch from d469606 to fb9e402 Compare July 17, 2019 19:43
@jalextowle jalextowle force-pushed the feature/contracts/3.0/new-order-matching-strategy branch from 46779fb to 9b653d5 Compare July 17, 2019 22:45
// Otherwise, update the current right order.
if (leftIdx == leftOrders.length) {
// Update the right batched fill results
batchMatchedFillResults.right[rightIdx] = rightFillResults;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to add a note to the definition of BatchMatchedFillResults that there will be no fill result for orders that were not matched. Right now we label the fields as "Fill results for left/right orders", which is sort of ambiguous. A client may expect to receive fill results for all orders they pass in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amir and I talked about this earlier. I don’t know that we came to a conclusion on it. I’ll talk to him in the morning and see what he thinks. I’m happy to add a comment for now, and depending on what he says I’ll either create an asana task or update the PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. For this PR, we should at least ensure there is consistent behavior across match scenarios. So we should either (i) return empty fill results for all unmatched orders, or (ii) return no empty fill results for any unmatched orders. I personally think it's okay to only return a fill result for orders that are matched.

Ex of current inconsistent behavior:

-- Scenario 1 --
leftOrders = [order_a, order_b]
rightOrders = [order_c]
* order_a and order_c are fully matched*
leftResult = [a_fill_result, (empty)]
rightResult = [c_fill_result]

-- Scenario 2 --
leftOrders = [order_a]
rightOrders = [order_c, order_d]
* order_a and order_c are fully matched*
leftResult = [a_fill_result]
rightResult = [c_fill_result]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note:
Chatted with Alex offline. The array initialization was updated earlier in the PR, so this is just an issue with redundant writes. We may want to refactor this section so that we only write the left/right result once, but in terms of correct output this looks good to me 👍 .

// Otherwise, update the current right order.
if (rightIdx == rightOrders.length) {
// Update the left batched fill results
batchMatchedFillResults.left[leftIdx] = leftFillResults;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary if the left order was also filled during this iteration? I believe this would write an empty fill result for the next iteration's left order. If this is the case, then we should ensure there is a test case for this scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I actually don’t know if this is a problem though since in this case the next left order wouldn’t have been filled anyways. It’s redundant, but it doesn’t seem to change any behavior since we process the orders in order and the last order will never be filled in this case. I actually think it may be cleaner to keep it the same, but I’m interested to hear your thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see comment above 🙏

Copy link
Contributor

@hysz hysz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work !! Very cleanly implemented with very thorough coverage. Let's get this merged 🥂

@jalextowle jalextowle merged commit 31324eb into 0xProject:3.0 Jul 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants