CIP: 65
title: Updating score definition for buy orders
author: Haris Angelidakis, Andrea Canidio, Felix Henneke
status: Draft
created: 2025-03-27
Simple summary
The score associated with a proposed solution is currently equal to the sum of scores over all orders the solutions proposes to execute, where the score of a proposed execution of an order is the sum of surplus and protocol/partner fees collected by that order execution, converted in the native currency of the chain by using the native prices provided in the auction by the protocol. The definition of the surplus associated with a buy order allows for the surplus of such an order to potentially become very large, and in fact much larger than the actual volume being traded, in cases where the limit sell amount of the order is very large. Posting such an order is possible, and is actually the way to express that the user wants to trade at market price, without any “limit price protection”.
A recent incident on the Base network revealed that the current definition of score and surplus can lead to an excessive allocation of solver rewards. This can happen when a user, either intentionally or unintentionally, decides to place a buy order with a very loose limit price as a partially fillable order where the balance of the sell token of the user is consistently very low, and whenever a partial execution takes place, it is topped up again (or alternatively, the user could place a lot of fill-or-kill buy orders with tiny buy amounts and very loose limit sell amounts).
This CIP proposes that the definition of the score for buy orders is modified in order to prevent cases such as the one described above. Moreover, it proposes that the rewards originally allocated to solvers, via the current mechanism, for all auctions generated by this query, as well as any future auctions (i.e., auctions that took place after March 4, 2025 00:00 UTC) that might be affected by this issue, are recomputed and distributed by using the updated definition (and set to zero, if that leads to negative rewards).
Motivation
The score of a solution within a batch auction is equal to the sum of scores (i.e., user surplus plus protocol and partner fees collected) over all orders the solutions proposes to execute. This objective function has proved very effective in pushing solvers towards maximizing surplus for all orders they propose to execute, so as to make their solutions more competitive.
However, the definition of surplus of an order, although natural, is slightly asymmetric between sell and buy orders. For sell orders, surplus is defined as
executed_buy_amount - limit_buy_amount,
while for buy orders, surplus is defined as
limit_sell_amount - executed_sell_amount.
By observing the above, it is clear that surplus for a sell order is at most equal to the executed_buy_amount
, while for buy orders, the surplus is potentially “unbounded”, as one can set the limit_sell_amount
to be equal to the largest integer the system allows.
The above asymmetry can affect scores, and thus, rewards, for auctions where a buy order with a very loose limit price might be picked for execution. And specifically, this is what happened during the week of March 4-11, 2025, where the following 2 partially fillable orders were placed:
The above orders were executed in thousands of auctions, thus resulting in significantly inflated rewards (in the order of 50+ ETH), while the actual traded volumes were less than 0.1 ETH in total.
The core team took the initiative, after communicating with solvers, to stall the payment for these auctions, as they would lead to excessive and unnecessary spending for the DAO for trivial orders; such orders could be labeled as intentional inflation of rewards, which is prohibited by social consensus rules. Nevertheless, to properly resolve the situation, it is up to the DAO to decide, with this CIP, whether rewards for all these auctions should be paid according to the current mechanism, or whether they should be recomputed based on a new definition of score for buy orders.
Specification
We propose to keep the current definition of surplus and protocol fee calculations for buy orders, but redefine how the score of a buy order is computed. Suppose we have the following buy order:
-
Limit sell amount X
-
Limit buy amount Y
-
Executed sell amount = x, where x <= y * X / Y
-
Executed buy amount = y
-
Protocol + partner fees collected = fees (denominated in the sell token)
To simplify notation, let p_limit = Y / X
. Here, we assume that f <= x, as has always been the case so far.
The definition of the user surplus is
user_surplus = y / p_limit - x
.
Currently, the score of the above order is the following:
Current_score = (user_surplus + fees) * native_price_sell_token
We propose to keep the definition of surplus and the calculation of protocol and partner fees exactly as they are now, and modify the score associated with the above trade as follows:
New_score = p_limit * (user_surplus + fees) * native_price_buy_token
.
Intuitively, instead of evaluating the score of a buy order in the sell token and converting it to the native currency by using the native price of the sell token, we instead use the limit price of the order in order to “express the surplus in the buy token” and convert that amount to the native currency by using the native price of the buy token. This is effectively a linear scaling of what we currently call score of the order. Specifically, one can easily see that
New_score = Current_score * p_limit * native_price_buy_token / native_price_sell_token.
With the above modification, we can ensure that the score of a buy order is always bounded by the volume of the trade. To see that this is the case, consider a fill-or-kill order, in which case (by using the notation we defined above) we have
New_score = (X - x + fees) * p_limit * native_price_buy_token <= X * p_limit * native_price_buy_token <= Y * native_price_buy_token = y * native_price_buy_token.
Note that when p_limit
is close to market price (which is the case for standard swaps placed via the CoW Swap UI), the above redefinition is very close to the current definition, as we would have p_limit ~= native_price_of_sell_token / native_price_of_buy_token
.
We also note that in extreme cases where the limit price p_limit
is very far from market price, the above redefinition might lead to slight bid shading from solvers, as there will no longer be 1:1 (or close to 1:1) mapping between additional surplus generated by the winning solution (compared to the second best solution) and rewards. We believe this is unavoidable, one way or another, but assuming robust competition, we do not think this will have any negative practical implications for users (especially since there is already a cap for rewards on an auction level, which has proved to not have a significant negative impact on users).
Besides the above modification in the definition, we also propose that the auctions on Base that resulted in an execution of the following two orders:
are adapted based on this new definition of score for buy orders. Concretely, we propose that the scores of all bids in all of the affected auctions are recomputed based on the new definition, and rewards are recomputed based on these updated scores; in case where a winning solver becomes a non-winner, we propose to set the reward for that auction to zero.
Finally, we propose that all similar instances that might appear until this proposal gets activated (in the case that it passes) are adapted, as described in the previous paragraph.
We also stress that in case this proposal is not successful, the core team commits to executing the pending payouts on Base according to the current rewards mechanism.
Execution
We propose that the above definition is enabled as soon as the core team and all solver teams are ready to apply the change. Further details about the concrete timeline could be posted when the proposal moves to the voting phase.