Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Order Matching Strategy #40

hysz opened this issue May 4, 2019 · 2 comments


Copy link

commented May 4, 2019


We propose an additional order matching function that maximally fills both orders (referred to as the left and right order). The matcher would receive profit denominated in either the left maker asset, the right maker asset, or a combination of both. This proposal allows matching relayers to execute trades without upfront capital, and does not modify the current matchOrders interface or implementation.


The current implementation of matchOrders maximally fills the left order, returning a profit to the matcher that is taken from the left maker. The proposed implementation maximally fills both orders, returning a profit to the matcher that is taken from the left or right maker (or both). The former implementation is beneficial for arbitrage and the latter for matching relayers.

Note that the proposed functionality can also be achieved by calling matchOrders and subsequently fillOrder on the right order. This strategy has been implemented in the Order Matcher extension contract.


Comparison of Matching Strategies

The figure below compares how profit is generated by the current and proposed matching strategies, along with the respective formulas for computing the flow of value between makers and the matcher.

Comparison of Matching Strategies

A Note on Rounding

In the formulas above, we round up or down to ensure that a maker's exchange rate does not exceed the price specified by their order. We favor the maker (opposed to the taker / matcher) when the exchange rate is rounded.


/// @dev Match two complementary orders that have a profitable spread.
///      Each order is maximally filled at their respective price point, and
///      the matcher receives a profit denominated in either the left maker asset,
///      right maker asset, or a combination of both. 
/// @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 by maker and taker of matched orders.
function matchOrdersWithMaximalFill(
    LibOrder.Order memory leftOrder,
    LibOrder.Order memory rightOrder,
    bytes memory leftSignature,
    bytes memory rightSignature
returns (LibFillResults.MatchedFillResults memory matchedFillResults);

@dekz dekz added the 3.0 label May 6, 2019

@dekz dekz changed the title [3.0] New Order Matching Strategy New Order Matching Strategy May 6, 2019

@dorothy-zbornak dorothy-zbornak referenced this issue May 18, 2019


Arbitrary Fee Tokens #1819

0 of 4 tasks complete

@jalextowle jalextowle referenced this issue Jun 27, 2019


Batch Order Matching #1900

1 of 4 tasks complete

This comment has been minimized.

Copy link

commented Jul 1, 2019

I ran three scenarios against the case 3 math and quickly realized that these formulas are missing support for partial fills as well as right/left swapping and negative differences. Here are the notes:

  • “matcher receives” part should be ABS() to make left/right swap not matter (you can’t do negative) and also should be proportionate to the actual amount possible to send (see MAX below) - eg: support partial fills
  • “Maker right -> maker asset amount right” should be “Maker right -> MAX(maker asset amount right, taker asset amount left)” and proportionate to the amount actually fillable
  • “Maker left -> maker asset amount left” should be “Maker left -> MAX(maker asset amount left, taker asset amount right)” and proportionate to the amount actually fillable

One other note: It would be optimal if the matcher could specify where the arb goes so it's a cheaper transaction with fewer transfers.

The scenarios I tried:

Scenario 1 (no price diff)

Left Order “Buy 10@1”
MTA = 10
TTA = 10
Price = MTA/TTA = 1

Right Order “Sell 9@1”
MTA = 9
TTA = 9
Price = TTA/MTA = 1

Expect: exchange of 9 at 1 dollar, no arb

Scenario 2 (price diff, full fillable)

Left Order “Buy 10@1.1”
MTA = 11
TTA = 10
Price = MTA/TTA = 1.1

Right Order “Sell 10@.9”
MTA = 10
TTA = 9
Price = TTA/MTA = .9

Expect: exchange of 10 at .9, 2 tokens remain -> Matcher, matcher determines PTP adjustment

Scenario 3 (price diff and not both full fillable)

Left Order “Buy 10@1.1”
MTA = 11
TTA = 10
Price = MTA/TTA = 1.1

Right Order “Sell 8@.9”
MTA = 8
TTA = 7.2
Price = TTA/MTA = .9

Should be exchange of 8 at .9, 8.8/7.2 = 1.6 tokens remain -> Matcher, Matcher determines PTP adjustment

@jalextowle jalextowle referenced this issue Jul 1, 2019


New Order Matching Strategy #1913

1 of 4 tasks complete

This comment has been minimized.

Copy link

commented Jul 2, 2019

@robdoesstuff Thank you for digging into this! Appreciate the feedback.

For reference, this is how the scenarios you described map to our equations to produce your results.

  • Scenario 1 → Case 1
  • Scenario 2 → Case 3
  • Scenario 3 → Case 1

Re negative differences. In the original implementation we constrained input such that the Left Order always has the higher price. This made the outcome more predictable: “Profits are always denominated in the maker asset of the left order.” That said, does enforcing this strict ordering complicate things on your end? The increase in gas should be negligible, so I'm open to supporting it if this makes the feature easier to use.

Re partial fills. Any amount filled is subtracted from makerAssetAmount and takerAssetAmount. So a partially filled order is effectively treated as a new, smaller order. I’ll amend the ZEIP to include this.

Re specifying where to send the arb. I like this idea +1.

Let me bring @jalextowle into this discussion, who is currently implementing this ZEIP.

Edit: I've updated the ZEIP for clarity. Please see "Order Constraints" and "Partial Fills" sections.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
3 participants
You can’t perform that action at this time.