Understanding CoW AMM: A Zero-Swap-Fee, MEV-Mitigating Liquidity Source for CowSwap
Surplus replaces fees, turning MEV into LP returns.
Outline
0. TL;DR
1. Intro
2. CowSwap Recap
3. CoW AMM Design
- Batching
- Curve Shift
4. Implementation Shallow Dive
- Walking Through a Trade
5. Observations
- Batching
- Zero swap fee!
- Curve Shift = Surplus
- Seamless Integration
- AMM-as-Liquidity-Source
6. Performance
7. Conclusion
0. TL;DR
- CoW AMM mitigates MEV by leveraging CowSwap’s trade batching and surplus mechanism.
- Trading on CoW AMM has zero swap fee; instead, surplus serves as LP returns.
- The integration of CoW AMM with Balancer’s existing AMM, or any post-swap fee-added AMMs, is minimal.
- CoW AMM is essentially an additional liquidity source to CowSwap, providing MEV-mitigating price offers for traders.
- 🐮 🧀 🚧 🐭 🟰 🤖
1. Intro
CowSwap is widely known in the DeFi space for its mesmerising Mooooo sound after successful transactions. 🎶🐮🎶
Now, in this era of intent-based trading, CowSwap is dominating the intent aggregation market with its early mover advantage.
CoW AMM, however, hasn’t got as much attention as I thought it would, even though I see it as a unique attempt to leverage AMMs to solve MEV — Maximum Extractable Value.
This article aims to briefly walk through CoW AMM’s features, the implementation, and its current status to see what it brings to the table! 🥩
Before we start officially, let’s play some moooosic 🐄 🤣
2. CowSwap Recap
Let’s start with a quick recap of CowSwap to ease into CoW AMM.
CowSwap is a DEX where you can trade tokens. But don’t be fooled by its Uniswap-like and cute appearance — it’s not an AMM like Uniswap, where trades are matched against AMM pools’ liquidity.
Instead, CowSwap is a liquidity aggregator, matching users’ tokens with liquidity sources from everywhere: CoWs, on-chain AMMs, off-chain centralised exchanges, and more.
The name “CowSwap” actually comes from Coincidence of Wants — various users’ trade requests can be settled with each other simply by transferring tokens between them. This avoids extra on-chain costs, like AMM calculations.
Since liquidity isn’t limited to on-chain AMMs (where trades must happen on-chain), liquidity aggregators like CowSwap usually batch multiple trades from various liquidity sources into a single transaction*. This reduces the gas cost per trade.
But CowSwap’s biggest edge is its network of “solvers.” These are bots that listen for trade requests on CowSwap and compete to figure out the best batch of requests to yield the most milk —i.e. surplus! 🥛
Surplus is the extra value achieved compared to the minimum execution price. For example, if Alice wants to sell 1 ETH for 2,700 USDC but ends up getting 2,705 USDC, the surplus is 5 USDC. CowSwap always chooses batch solutions with the maximum surplus.
Now that we’ve covered the basics, let’s dive into CoW AMM!
*Thanks to Andrea, he pointed out that batching mechanisms can vary between liquidity aggregators. “CowSwap runs a single auction for multiple trades in the batch, whereas 1inch fusion or UniswapX runs separate auctions for each trade received.”
3. CoW AMM Design
The innovation behind CoW AMM comes from a research paper titled Arbitrageurs’ profits, LVR, and sandwich attacks: batch trading as an AMM design response.
As the title suggests, LVR (Loss-versus-Rebalancing) — a type of MEV — is what this new design aims to fix.
In short, LVR happens due to the inherent design of AMM curves, which always incur slippage during trades. When AMM prices fall behind more informed, price-sensitive venues like centralised exchanges (CEXs), arbitrageurs can step in and profit from the price mismatch.
While LVR and other types of MEV are big topics worthy of separate discussion, this article focuses on the solution. The research paper outlines two key conditions for creating an MEV-mitigating* AMM (or FM-AMM):
- Multiple trades must be batched and settled together on the AMM curve.
- The AMM curve must move upward/rightward after each batch trade.
If you’re curious about the maths behind these assumptions, I’ve already fallen down that rabbit hole for you. Check out the first episode of this cow series: ELI5: What Is FM-AMM, The Theory Behind CoW AMM, and How Is It MEV-Resistant?
*or MEV-resistant, though “resistance” might imply completely solving MEV, which isn’t necessarily true for CoW AMM’s current implementation.
- Batching
Batching has always been CowSwap’s second biggest feature (🎶 🐮 🎶🥇). So, who is better than CowSwap to implement an AMM that requires batching? What a C(oincidence) o(f) W(ants)! 😎
Tacky joke and apology aside, many of you may already be familiar with some of the benefits of CowSwap’s batching technique:
- Reduced gas costs for trades, as highlighted earlier.
- Reduced MEV risk: MEV bots are less likely to front-run trades if they’re settled together as CoWs.
- Uniform clearing prices for all trades in a batch.
But the additional benefit of further mitigating MEV might seem too good to be true!
Here’s the TL;DR: In an FM-AMM, the product of the reserves — i.e., the constant — changes after each trade. However, this change isn’t proportional to trade size — the larger the trade, the more non-linearly the curve shifts. This non-linearity creates the necessity for batching.
- Curve Shift
The paper explains curve shifting in two ways:
- A pricing function, whose post-trade constant is:
(Y * ((X - x’) / (X − 2 * x’))) * (X − x’)
, withX
andY
the pre-trade reserves andx’
the size of a trade. This method can completely eliminate MEV, leaving arbitrageurs with zero profits. - A maximisation problem. The goal is to maximise the pool’s liquidity, i.e. the product of the reserves. While this approach cannot eliminate MEV completely, it minimises it, leaving arbitrageurs with only limited profits.
CoW AMM adopts the maximisation approach, and we’ll explore the rationale behind this decision soon!
If you’re still hungry for details about these two conditions, you have two options: the paper or my article 😁.
4. Implementation Shallow Dive
Now that we’ve uncovered the two requirements for making AMMs MEV-mitigating, let’s explore the implementation!
Although CoW AMM is launched on Balancer, its implementation was actually crafted by Wonderland, a mysterious group of crypto developers. Rumour has it they just attended Devcon 😍 🤫.
There’s also another implementation by CoW Dao. According to a member, it is an experimental version that didn’t make it to production. The CoW team has since shifted its focus to supporting the Balancer implementation.
- Walking Through a Trade
There’re two contracts involved in this section:
- BCoWPool.sol: the contract of CoW AMM. The prefix B stands for Balancer, so other contracts such as BMath.sol are also from Balancer and meant for CoW AMM’s logic.
- GPv2Settlement.sol: the settlement contract of CowSwap and any CoW AMMs.
The main contract we’ll examine is BCoWPool.sol. If you’re unfamiliar with CowSwap, this contract might seem puzzling: it has only three main functions — commit()
, verify()
, and isValidSignature()
. How can a trade even possibly be made?
Here’s how a trade works, focusing on CoW AMM-specific logic:
- Solvers get trades info from CowSwap’s APIs and propose their solutions. The winning bid is the one that maximises total surplus for all trades in the batch.
- The winning solver calls the settlement function of CowSwap
GPv2Settlement.settle()
with the batch trade details. - Settlement begins with
BCoWPool.commit()
, which locks in the order hash for the proposed trade. This ensures only one trade is executed on the CoW AMM per block. - Next,
BCoWPool.isValidSignature()
(an ERC-1271 function) andBCoWPool.verify()
are called to validate the trade against its requirements. - In
BCoWPool.verify()
,BMath.calcOutGivenIn()
calculates the swap output amounttokenAmountOut
based on the AMM curve withswapFee = 0
. This result is compared with the order’s designated amountorder.sellAmount
to ensure the AMM offers at least the expected output. - Finally, both the CoW AMM and the user transfer tokens to the
GPv2Settlement
contract, which then redistributes the exchanged tokens to the respective parties.
Why don’t we solidify this understanding with a real transaction on a CoW AMM on Gnosis Chain? 0xbbcb88fac67954e381443608e46fc5182abf5ef55ac2bcf12fa2007588aeb607
As shown, in GPv2Settlement.executeInteractions()
*, commit()
is followed by _setLock()
.
isValidSignature() verification.
Source: https://www.tdly.co/tx/gnosis-chain/0xbbcb88fac67954e381443608e46fc5182abf5ef55ac2bcf12fa2007588aeb607We can also observe that verify()
and isValidSignature()
perform all the complicated calculations within BCoWPool
to validate the trade.
*Note: Sometimes input data aren’t displayed correctly on Tenderly due to a bug. You can view the complete details on blockchain explorers.
5. Observations
There are several key observations we can make from the implementation details above:
- Batching
The “one trade per block” limitation effectively introduces the batching requirement that makes CoW AMM MEV-mitigating.
Since time on blockchains is typically defined in blocks, limiting trades to one per block is a rather intuitive choice.
- Zero swap fee!
As I specifically mentioned when calculating tokenAmountOut
, the swap fee is 0. Yes, there’s no swap fee on CoW AMM!
While this is great news for traders, it raises the question: how does CoW AMM incentivise liquidity providers? Clearly, this is where the surplus mechanism comes in.
- Curve Shift = Surplus
Instead of fixing a swapFee
, CoW AMM leverages CowSwap’s existing surplus mechanism, which is to accept the max possible surplus proposed by solvers. Thus, surplus becomes LP’s returns, which replaces the need for a traditional swap fee!
Some might notice an uncommon pattern previously: the final step of the trade transfers tokens directly between users, liquidity sources, and GPv2Settlement
. Why aren’t these transfers handled by a swap function within the AMM contract?
This is due to CowSwap’s original design: tokens, including surplus, are always transferred to GPv2Settlement
, which then redistributes them. In CoW AMM, the exchanged tokens, along with surplus — i.e. LP earnings — are transferred directly from GPv2Settlement
to the CoW AMM.
In many DeFi AMMs, swap fees are added to the AMM pool post-swap, which causes the AMM curve to shift upward/rightward. By sending the surplus directly to CoW AMMs, we achieve a similar curve shift, as long as the surplus is positive.
Since CowSwap always selects batches with the maximum surplus, it’s clear that the second requirement for FM-AMMs (curve shift, in its maximised form) can be achieved by simply attaching CoW AMM to CowSwap’s batch selection criteria. Maximising surplus equals minimising MEV!
In other words: 🐮 🧀 🚧 🐭 🟰 🤖
- Seamless Integration
You may have noticed that I didn’t dive into GPv2Settlement
or other Balancer’s contracts, which is why I refer to the previous section as a “shallow dive.”
This isn’t just because our focus here is on CoW AMM, but also because CoW AMM’s core logic is simply to integrate CowSwap with an existing AMM design — in this case, Balancer.
BPool
; there’s nothing about AMM design. Source: https://github.com/balancer/cow-amm?tab=readme-ov-fileLooking at the changes to Balancer’s pool contract BPool
, the biggest adjustment is using ERC20.balanceOf(address(this))
to track token balances, instead of maintaining an internal record. That’s it.
When you think about it, this integration is udderly simple: by implementing CowSwap-related functions in an existing AMM contract, batching AMM trades, and tracking token balances with ERC20.balanceOf()
, we’ve created an MEV-mitigating AMM!
This approach works for CFAMMs like Uniswap V1 and V2. However, it’s not applicable to Uniswap V3-like AMMs, because V3’s range fragmentation prevents adding fees back to the pool, meaning it cannot fulfil the curve-shifting requirement of FM-AMM.
- AMM-as-Liquidity-Source
Both requirements for making CoW AMM MEV-mitigating have always been part of CowSwap’s original design. Creating a CoW AMM is essentially just aligning the trading process with CowSwap’s GPv2Settlement
contract.
So, what benefits does CoW AMM bring? CoW AMM is effectively AMM-as-liquidity-source for CowSwap!
Beyond the obvious fact that CoW AMM mitigates MEV, the more CoW AMMs there are, the more liquidity sources CowSwap can integrate with, ultimately offering better prices for traders on CowSwap!
The last observation is: CoW AMM is an (almost) effortless additional liquidity source to the grand CowSwap moo🐮oniverse!
6. Performance
If you’re still with me, you must be thinking: everything about this brand-new, cool stuff sounds great so far — tell us the hard truth!
Well, here it is: LP returns on CoW AMM are slightly underperforming compared to Uni V2 at the moment. 🙊
There are many potential reasons for this: trading volume, liquidity depth, CowSwap’s solver integration with CoW AMMs, and so on.
However, uncovering the true cause requires some professional SQL skills, and I’ll humbly leave this task to the Dune masters out there. If you happen to be one, feel free to share your elaborately crafted Dune boards below!
For now, we’ll continue observing and let time and devs do justice for CoW AMM. 🤞
7. Conclusion
In this exploration of CoW AMM, we’ve discussed its innovative approach to mitigating MEV through batching and curve shifting. By leveraging CowSwap’s existing infrastructure, CoW AMM offers reduced gas costs, zero swap fees, minimised MEV risks, and bovine… performance? 🤣 😉
The integration is seamless, with CoW AMMs tapping into CowSwap as additional liquidity sources, enabling better MEV-mitigating prices for users.
This is all for my second dive into CoW AMM. I sincerely hope it becomes a true 💰 🐄 for CowSwap and that CowSwap can someday compete with the 🦄 !
As always, feel free to leave comments, share your thoughts, or point out any errors you spot. Until next time!
Thanks to Ping Chen and Anton Cheng for reviewing!