CIP-Draft: Penalty Cap Redesign

Penalty Cap Redesign

Simple Summary

This CIP changes the cap on penalties for unsuccessful settlements from a fixed absolute amount to a relative amount of proposed trade volume. The size of these relative caps is chosen to be as small as possible while still retaining a desired settlement success rate.

Motivation

The auction mechanism of CoW Protocol includes a penalty for solvers whose solutions were selected as winners but whose settlements were not successfully executed. The current monetary penalties follow the same second-price logic as rewards, with penalties being capped at a chain-specific absolute value.

One issue with the current penalty is that it serves multiple purposes within the mechanism. On the one hand, the size of penalties implies a trade-off between quality of proposed prices, which improves with small penalties, and speed of execution, which improves with large penalties. On the other hand, penalties provide a form of censorship resistance since it is costly to block the execution of an order by proposing solutions which cannot be executed.

The size of the cap was originally set in CIP-20 and tried to address both purposes. This can lead to large caps with a negative impact on execution quality for small orders, while at the same time not providing sufficient censorship resistance for larger orders. We propose to set the cap from first principles based on the trade-off of execution quality and execution speed.

This change will impact the distribution of rewards and penalties between solvers but not the aggregate total payment to solvers, due to consistency rewards as specified in CIP-85. Censorship resistance will be addressed separately in the future.

Specification

Comparing b5c361d2eaf5ac366a04258ae8128781650f77d7...12547af286d32e8875c672888f710193647140b3 · cowprotocol/docs · GitHub (PR)

Each order will have a penalty cap associated with it in each auction, expressed in the native token of the chain.
The cap for penalties for a given solver in a given auction is the sum of all penalty caps of orders which were not executed in time or not executed at all.
For partially fillable orders, the penalty cap is scaled to the executed fraction.

Example

Suppose a solver wins the right to execute three orders, two of which are not executed. Furthermore, the uncapped penalty for said solver in this auction is 0.02 ETH and the penalty caps associated with the two orders which were not executed are 0.001ETH and 0.005ETH. Then the capped penalty for the solver is 0.006ETH.

Initially, the cap for each order is chosen as a fraction of the quote for an order. The fraction depends on the chain and on whether the traded tokens are correlated.
The concrete values are as follows.

Uncorrelated tokens:

  • Ethereum mainnet: 4 bps
  • Gnosis: 3 bps
  • Arbitrum: 1 bps
  • Base: 2 bps
  • Avalanche: 2 bps
  • Polygon: 3 bps
  • BNB: 1 bps
  • Linea: 2 bps
  • Ink: 1 bps
  • Plasma: 1 bps

Correlated tokens:

  • All chains: 0.1 bps

Additionally, the initial cap will be bounded by the equivalent of $20.

The classification into correlated and uncorrelated token pairs follows the same logic used in determining the protocol volume fee. The quote of an order is the buy amount with all volume fees deducted for sell orders and the sell amount with all volume fees added for buy orders.

Example

For an order selling 9 wstETH for wETH with a quoted amount of 10 wETH, the cap for correlated tokens, 0.1 bps of the quoted amount, corresponds to 0.0001 ETH. The cap for that order would thus be chosen as 0.0001 ETH.

The core team has a mandate to change the penalty cap per order within the interval [0bps, 10bps], if needed, to tune the trade-off between competitive prices and fast execution. Any change to the penalty cap has to be announced in advance to solvers and will be reflected in the documentation on docs.cow.fi.

Rational

The current cap for penalties was originally defined in CIP-20. Its size was based on a symmetry argument which neither addresses strategic implications of caps, nor censorship resistance. Subsequent changes to reward caps, e.g. in CIP-36 or CIP-74, did not change the general logic of the choice of penalty caps. The proposed cap in this CIP, in contrast, is derived from first principles with a focus on encouraging desirable strategic behavior of solvers.

One main driver for unsuccessful settlements is price movements of tokens. If the price moves against them enough, a solver is better off if their solution does not settle and they pay a penalty compared to their solution settling at the new price.

For a successful protocol we want to ensure swift execution of trading intents, giving bounds on settlement success rates p_success. Given such a bound for success rates, the penalty cap for an order is set such that solvers settle with probability p_success, given estimates about price movements during the window of exclusivity, i.e., the time between the /settle notification and the deadline by which solutions to an auction need to be settled. For now, we propose to use separate fixed relative caps for two classes of token pairs, correlated and uncorrelated token pairs. Caps are fitted to achieve around 92% success rate using Binance data for price movements.

The window of exclusivity used for different chains are as follows. The value for main net is based on statistical data. All other chains follow the formula floor((submission_deadline - 0.5) * block_time) with values as configured in the autopilot.

  • Ethereum mainnet: 26s
  • Gnosis: 12s
  • Arbitrum: 2s
  • Base: 7s
  • Avalanche: 7s
  • Polygon: 11s
  • BNB: 2s
  • Linea: 7s
  • Ink: 4s
  • Plasma: 4s

Looking at the 10 most traded correlated and uncorrelated tokens, these exclusivity times result in the caps proposed above. A notebook containing this the computation can be found on GitHub.

While we start with a fixed cap per class of token pair, an approach more tailored to the specific token pair could be used in the future. We have tested different approaches, e.g. based on price movements in the last 24h hours which result in a more stable success rate at the cost of additional complexity in computing penalty caps.

For caps in the proposed interval [0bps, 10bps], the expected impact on bidding is similar to the current mechanism. Solvers need to take the cap into account for optimal bidding, see this forum post.

Future initiatives of reducing settlement deadlines will reduce penalty caps, as expected price variations decrease given a shorter exclusivity window.

Note that the change to penalties is not intended to change the total payment to solvers. The aggregate of rewards and penalties is fixed to a fraction of protocol revenue, see CIP-85. This does not change with this proposal. What changes is implied solver behavior and distribution of rewards between solvers.

A notebook comparing current and proposed rewards can be found on GitHub.

Update 2026-08-09:

  • Values for caps and exclusivity times were updated.
  • A global absolute cap for penalties was added. It reduces penalty caps for large orders.

Update 2026-08-18:

  • A link to a docs PR was added.

Taking the example from the CIP: a solver wins three orders, successfully settles one, and fails to settle the other two. The uncapped penalty from the failed orders is 0.02 ETH, while their combined order-level penalty cap is 0.006 ETH.

Now assume the successfully settled order generated a 0.01 ETH performance reward, with an order-level reward cap of 0.02 ETH.

If everything is netted and capped at the solver-auction level, the result is:

0.01 − 0.02 = −0.01 ETH, capped to −0.006 ETH.

This means the two failed orders cost the solver not only the capped 0.006 ETH penalty, but also the entire 0.01 ETH reward earned from the successfully settled order, even though that reward is below its 0.02 ETH cap.

It seems more logical to apply the reward and penalty caps at the order level first, and only then aggregate the results at the auction level:

min(0.01, 0.02) − 0.006 = +0.004 ETH.

The solver would still be penalized for the two failed orders, but those orders would not erase the reward earned from an order that was successfully executed.

Since both the reward cap and the penalty cap can now be derived from individual orders, shouldn’t the capping logic also move from the solver-auction level to the order-auction level?

At the moment, performance rewards (and penalties) are on the solver-auction level. That is, there is generally no concept of a reward per order or penalty per order. Adapting these concepts to a order-auction level is a more fundamental change. We are currently trying that out with consistency rewards. But it does not in all cases work with batching. This could change a bit once all solvers use multiple submission accounts and submit lots of separate solutions for combination of orders.

In the example from the CIP, the uncapped penalty of 0.02 already contains contributions from the successful order. Otherwise the penalty (specifically, the uncapped penalty as well as the penalty cap) would have been larger.

A full example could have been as follows. Orders 1 and 2 contribute a score of 0.02 ETH each, order 3 contributes 0.1 ETH. Penalty caps for these orders are 0.001 ETH, 0.005 ETH, and 0.01 ETH, respectively. Suppose there is only one winning solver and the reference score is 0.12 ETH.
In the case of the solver only settling order 3, the uncapped payment is 0.1 ETH - 0.12 ETH = -0.2 ETH. The penalty cap is 0.001 ETH + 0.005 ETH = 0.006 ETH. The resulting payment is thus a penalty of 0.006 ETH.
Had the solver not settled any order, the uncapped payment would have been 0 ETH - 0.12 ETH = -0.12 ETH. The penalty cap would then be 0.001 ETH + 0.006 ETH + 0.01 ETH = 0.016 ETH and the resulting penalty 0.016 ETH. So given this setup, there is value in having executed the third order. (This argument becomes weaker when talking about whether the solver had an incentive to win the second order.)

I want to point out that this proposal will have an adverse impact on pricing of large orders.

If the main intention is to improve “execution quality for small orders”, we should avoid negative side-effects and keep the hard cap of .01ETH in addition to the proposed bps caps i.e. min(.01, bps_cap).

As orders get large, the difficulty of settling them increases exponentially. The design assumes that there is no difference between executing a small and large order and the only factors at play are slippage/price movements.

Difficulty increases with size because:

  1. Routes get very complex - lots of steps that are a mix of dexs, rfqs, prop amms, where a single failure may lead to a revert.
  2. RFQs fail more often because of small changes in available liquidity once pushed to the limit.
  3. Greater reliance on builder-level PropAmms - if there is no pamm-supported builder block within the 3-block window tx fails.
  4. Transit token liquidity risk. For example, if a route is A->B->C, if A->B has slippage that a settlement contract can’t cover, the whole route reverts (its not always possible to adjust subsequent route’s inputs on the smart-contract level)
  5. All of the above are compounded by “GPv2: order filled” issue which still hasn’t been addressed (Solver A fails to settle in time, but still executes, Solver B of this and submits a solution in subsequent auction and gets penalized)

The model is fitted to a 92% success rate. I would argue that for $1M+ orders this will not hold and may be closer to a 66%.

As a result, a solver wishing to offset the penalty losses, would have to markup large non-stable orders by roughly 2bps on mainnet, effectively doubling the Cowswap fee (not to mention a significant overhaul of pricing/risk models which will lead to near-term instability).

I’m assuming there are no current issues with execution quality of large orders - if its not broken, don’t fix it!

If we are considering this change, it might make sense to consult users that make these kinds of trades often if they would prefer faster execution speed in exchange for doubling of fees.

It might also make sense to examine competitors and see how much volume Cowswap would sacrifice as a result.

If the intention of the proposal is to improve “execution quality for small orders” and not impact large orders adversely, the cap should be the min of the current .01ETH cap and bps_cap.

With the current penalty scheme, most small orders are heavily penalized since the solver has an asymmetric penalty / reward and their p_success should be higher than the 92% target of the backtesting. The issue for those orders is that another component suffers: the executed price. The higher the penalty/reward ratio leads to more underbidding which covers most of the times an adverse price movement and we have a big p_success.

On a large order, we have many times the opposite. Since penalty / reward is small, a solver often might overbid or tightly bid in general with the risk of not transmitting when price movement is adverse or not positive, lowering p_success. This approach though leads to much better executed prices.

Definitely increasing the potential penalty on a larger side order would increase the p_success. But I think that this increase would be much smaller than the 92% estimate which might not take into account a lot of factors other than adverse price movement and at a very big tradeoff, a much worse execution price. As flash well described above there are many more intricacies in larger orders that result in them having naturally a lower success rate, with only one component of it being the tight bidding. The biggest issue though is that the cost of that p_success improvement would be disproportionate for the end user in terms of execution price since the p_success on large orders depends at a much smaller fraction on the bidding aggressiveness than it does on small ones. A single ( and simple ) liquidity source route is much more controllable and this is very rarely the case with big orders.

I think there is a big asymmetry between applying the same bps penalty cap on a $100 order and on a $1M order and this change suggests a change on a $1M order from 0.19bps to a 6bps penalty for ethereum mainet. I don’t have any concrete suggestion other than to examine the data more closely and to not do huge jumps. A quick thought is to adjust the max bps according to the dollar value of the order.

We run kaisersolver (Arbitrum and Base, mostly small orders). This proposal cuts both ways for us, and some of what we found argues against our own interest, so we’ll just put everything on the table.

We spent some time trying to answer the success rate question empirically. Part of it turned out to be measurable from public data and part of it genuinely isn’t, and that split ended up being the most useful thing we learned.

Reverts are rare, and you can check that from public data

We pulled every settle() call sent directly to the settlement contract and checked success vs revert. Mainnet, Jul 31 to Aug 8: 10,977 settlements, one revert. Base, Jul 29 to Aug 8: 241 reverts out of 15,975, about 1.5 percent. All 241 reverting senders are active solvers that also land successful settlements, so this isn’t noise, it’s a real solver revert rate. Anyone can reproduce it with a Blockscout crawl, no keys needed. Two caveats: this misses settlements routed through solver-owned wrappers, so it’s a big sample rather than a census. And the mainnet number is partly an artifact of private submission, a reverting mainnet settlement usually just never lands. Those failures don’t disappear though, they turn into declines or timeouts, which matters below.

Our own numbers look the same. Over the last 28 days, counting from the moment our driver starts submitting a winning solution: 1,272 of 1,283 landed on Arbitrum, 580 of 585 on Base, both 99.1 percent. Important caveat: that’s success after we decided to submit, it says nothing about wins we declined. And we’re a small order solver that bids conservatively, so this mostly confirms what solver said above, small orders already settle well above the 92 percent target under the current cap.

The 92 vs 66 disagreement is about three different things

“Success rate” here bundles three failure modes that behave very differently:

  1. Declines: the solver wins but never submits, usually because the price moved. No transaction exists, so it’s invisible on chain.
  2. Reverts: submitted and failed. Measurable, and per the above it’s about 1.5 percent on Base and near zero on mainnet.
  3. Late settlements: landed past the deadline, including the “GPv2: order filled” race flash mentioned.

So the 92 percent fit and flash’s 66 percent worry can both be right at the same time, because the large order risk lives mostly in declines and late settlements, not in reverts.

Late settlements we could actually check, at least for transactions that landed. We took 250 settled transactions per chain and compared each settlement’s block to the auction’s deadline block from the competition API. Base: 0 of 250 late. Mainnet: 1 of 250, by one block. The auction id is in the settle calldata, so a late landing can’t masquerade as an on-time one.

Declines we could not crack, and not for lack of trying. There’s no transaction to observe. We also probed the public v2 competition endpoint across 50 consecutive recent Base auction ids, and the only ids with stored data were the ones with a settlement transaction. No record anywhere of a winner without one. So two of the three failure modes are publicly measurable and both are small. The one that isn’t measurable, declines, is exactly the one the 92 percent assumption depends on, and right now only the core team has that data.

Where the new caps bite

The proposed cap crosses the current one at 0.01 ETH divided by the cap in bps (using the documented c_l of 0.010 ETH for mainnet, Arbitrum and Base). That’s 100 ETH on Arbitrum, about 33 ETH on Base, about 17 ETH on mainnet, 1,000 ETH for correlated pairs. In dollars, very roughly 190k, 63k, 32k and 1.9M, which lines up with the 0.19 bps figure solver quoted for a 1M mainnet order.

Above those sizes penalties go up, which is where flash’s concern is real. Below them they collapse. And on Base essentially everything is below the line: in an 800 auction window we measured this week (about 11 hours, 838 executed trades), 85 percent of trades were under 100 dollars and over 99 percent were below the crossover. For a typical sub-100-dollar Base order the cap goes from about 19 dollars to under 3 cents.

We’re honestly not sure whether that’s good or bad, but it should probably be said out loud: on Base this doesn’t recalibrate the penalty, it effectively removes it for nearly all current flow. What’s left as a deterrent against winning without settling is the success rate multiplier in the CIP-85 consistency metric. The interaction between those two mechanisms might be worth an explicit paragraph in the proposal.

One smaller observation. The caps are fitted to price movement over the full exclusivity window (2.75s Arbitrum, 8s Base, 26s mainnet). From our driver telemetry, median time from starting submission to landing is 0.94s on Arbitrum and 1.76s on Base. A solver that commits quickly is exposed for a fraction of the modeled window, the full window is really the exposure of someone who waits until the deadline to decide. Might be worth reflecting in the fit.

Two suggestions:

  1. Could the proposal include the historical decline rate by order size from the internal chosen-vs-settled data? As far as we can tell nobody outside the team can produce it, and it’s the single number the 92 vs 66 dispute stands or falls on. Or make the dataset queryable and several of us will happily do the analysis.
  2. For the tail above the crossover sizes, flash’s min(0.01 ETH, bps cap) seems like a cheap bridge until the size question is settled with data. Or calibrate per failure mode, declines vs reverts, so the cap targets the behavior it’s actually meant to shape.

I updated the main text.

  • Numbers for exclusivity times and caps were adapted. Notebooks are referenced to reproduce these computations.
  • A global cap for caps of $20 is introduced across all order and chains. It represents roughly the old cap of 0.01 ETH on mainnet. A notebook with numbers on a counterfactual is referenced.