TLDR;
- CIP-74 changed solver reward cap per order from 0.01 eth ($40) to the protocol fee (2 basis points)
- to remain profitable post CIP-74, solvers must introduce fees to break even
- these fees will get reflected in prices for users and a loss of competitivy for cowswap
- the current rewards are heavily concentrated towards solvers settling few large orders vs many small orders.
Disclaimer / context: I run the Fractal solver which has in the last few months been settling about 20% of cowswap trades and 5% of volume. I have seen my rewards reduced by 80% recently which is what has lead me to look into the problem I will explain here.
To remain profitable, a solver must have a positive reward expectancy. To place a bid on an order, a solver must ensure that if he wins,
E(total_reward) > 0,
which can be rewritten as
E(base_reward) + E(penalty) + E(slippage) + network_fee - gas_fees > 0
Solvers are free to set the network_fee as they see fit, but higher fees lower the order surplus and therefore the base_reward and their likelihood to win.
base_reward
The base_reward is the second price reward paid to solvers for winning a batch in the auction. It is defined in CIP-67 as
base_reward = max(min(score - reference_score, reward_cap), 0) where the reference score is the score (sum of order surpluses) that the auction would have without the solverâs bids.
CIP-74 changed the reward_cap from 0.012 eth to the protocol fee collected for that settlement, which generally 2bps (more if limit order or the prive improves from quote).
This means that the max reward for a $2000 trade went from $35 to $0.4 if we value eth at $3000.
penalty
I separated the negative base_rewards as âpenaltiesâ, so penalty = max(min(score - reference_score, 0), -0.01)
If a user wins a trade and doesnât settle it within the time limit (because it reverts or doesnât get included in time), the solver incurs a penalty as defined above.
slippage
slippage is the difference between the solverâs expected output for the trade and the actual output.
as this query shows, https://dune.com/queries/6371954/10133071 slippage tends to be negative for small orders, and positive for large orders. This is due to lower value order being settled more onchain and larger orders more through private liquidity.
reward expectation vs batch value
Combinding data from the previous dune queries, and fetching the /competition endpoint, I looked at 10810 Fractal won auctions with a single batch from 2nd of december to the 16th of december. I bucketed these batches by value and looked at the base_reward, penalty, capped reward, old reward (with a 0.01 cap) and expressed them in basis points. I joined each row with the slippage stats accross all solvers from the query above. Here are the results:
| uncapped_reward_bips | reward_cap_bips | old_reward_bips | capped_reward_bips | penalty_bips | slippage_bips | Capped_reward+penalty+slippage | Num batches | |
|---|---|---|---|---|---|---|---|---|
| price_bucket USD | ||||||||
| 0â1k | 22,09 | 13,13 | 22,04 | 7,84 | -4,35 | -5,62 | -2,13 | 5311 |
| 1kâ10k | 8,04 | 5,32 | 7,37 | 3,49 | -2,49 | -2,74 | -1,74 | 4266 |
| 10kâ25k | 5,29 | 3,79 | 3,42 | 2,10 | -0,97 | -0,71 | 0,43 | 584 |
| 25kâ100k | 5,81 | 3,27 | 2,14 | 1,65 | -0,49 | -0,15 | 1,01 | 495 |
| 100kâ250k | 5,01 | 2,82 | 0,78 | 1,43 | -0,25 | 0,10 | 1,28 | 110 |
| 250kâ1M | 10,87 | 3,84 | 0,48 | 1,68 | -0,07 | 0,12 | 1,72 | 43 |
This shows, for instance, that for orders betwek $1k and $10k, Fractal had on average 8bps of improvement over the 2nd best bid, Cow protocol earned 5.3 bps of protocol fees (after removing partner fees), the protocol paid Fractal 3.49-2.49= 1 bps in base_reward which after slippage resulted in - 1.74 bps profit without network fees. Pre CIP-74 with the old rewards capped at 0.01 eth, Fractal would have earned 7.37-2,49-1,74 = 3,14 bps . Fractal now needs to set a network fee of 4bps if it wants to generate an average of 2bps of profit, which will be reflected in prices for cowswap users. This is not a second price auction anymore, itâs a first price auction.
Without introducing a network fee, solvers expected profits are now NEGATIVE for trades below $10k. In practice, solvers have to set fees even higher to generate profit and be able to cover their costs. These fees will be reflected in prices offered to users which affects cowswap competitiveness.
In addition, when given sufficient rewards solvers can bid truthfully (at the amount they think they can obtain) to maximize the trade surplus for users. This is now no longer the case, solvers have to come up with fee models to profitably place bids on orders < $10k. (which represented 74% of cowswap batches between december 2nd to december 16th)
Centralizing effect on rewards in the solver competition
I aggregated at the uncapped_reward (surplus delivered to users vs 2nd best solver bid), the protocol_fees and the base rewards at a per-solver level in this query
If we look at the rewards from the 2nd until the 16th of december, cowswap earned 276 eth of fees and paid 93 eth to solvers, 72 of which to the top solver (even though it earned only 45% of the uncapped rewards, which is a measure of value provided to users).
We can see that the current reward incentives for solvers favor solvers settling few large orders vs solvers settling many small orders resulting in extreme concentration of rewards.
Suggested solutions
multiple things can be done to reduce this issue:
1 - add min reward cap
I suggest we introduce a min reward cap (at least on mainnet) per batch:
instead of
reward_cap = protocol_fee,
use
reward_cap = max(protocol_fee, min_reward_cap)
Which could be set around 0.005 eth (to be tuned properly by core team)
2 - reduce penalties (bring them back in line with the rewards)
instead of
max_penalty = 0.01
use
max_penalty = min(reward_cap, 0.01)
3 - cap solver rewards on a weekly level instead of per order
This is a bigger change that would need to be considered more carefully but would significantly improve solver rewards distribution:
instead of using
base_reward_per_auction = max(min(score - reference_score, protocol_fees), -0.01)
remove the per auction cap and add a weekly reward cap
base_reward_per_auction = max(score - reference_score -0.01)
weekly_solver_reward = min(sum(base_rewards_per_auction), weekly_solver_protocol_fees * factor)
where the factor is a tunable parameter.
The biggest risk of this approach is that it does introduce a previously present risk (pre CIP-74) of wash trading by solvers: they could create their own orders, settle it themselves at high surplus value, lose the protocol fees but gain more than what they lose at the expense of the protocol. I believe this risk is limited as there are two mitigating factors:
- wash trading profits it would be limited in value to the difference between solver rewards and protocol fees * factor.
- So a solver who doesnât generate protocol fees couldnât benefit from it.
- solvers have significant bonds that would be slashed if they behave in a dishonest way.
Therefore I doubt it would be an issue in practice.