CoW AMM Liquidity for Solvers
I'm a solver. How do I use CoW AMM liquidity?โ
CoW AMM orders already appear in the CoW Protocol orderbook, so you're already using its liquidity. However, CoW AMMs allow solvers to specify custom buy and sell amounts, as long as the order preserves or increase the constant product invariant of the token reserves.
CoW AMMs can be treated as a liquidity source akin to Uniswap or Balancer weighted pools with uniform weights. Each CoW AMM is a pair that trades two tokens.
Importantly, surplus for a CoW AMM order is measured differently when computing the solver reward payout.
Indexing Balancer CoW AMMsโ
CoW AMM pairs can be detected by listening to the COWAMMPoolCreated
events emitted by the BCowFactory
instance for the current chain (see the official contract repository for the current deployment addresses).
All addresses of Balancer CoW AMMs are sent as part of the auction instance as surplusCapturingJitOrderOwners
.
The AMM reserves are the balance of the two tokens traded by the AMM.
Creating CoW AMM orders with the helper contractโ
Integrating CoW AMM orders requires adding a JitOrder with the CoW AMM. This order should be described from the CoW AMM pool's perspective. So if a user wants to sell token A to buy token B and you would like to settle (part of) this order with a CoW AMM, then you would need to add a JitOrder from the CoW AMM's perspective to match (part of) this order. In other words, you would be adding a JitOrder for the CoW AMM to sell token B to buy token A. You can do this by calling the orderFromBuyAmount
because the userโs amount is exactly how much you would want the pool to receive, asking for the amount of tokens in exchange.
The source code for the helper contract can be found here. The orderFromBuyAmount
and 'orderFromSellAmount' methods return the order, preInteractions, postInteractions, and signature. This can be used to generate the order (JitOrder) with the CoW AMM and check the prices that the CoW AMM would provide for the order you would like to settle.
This order generated by the BCoWHelper contract will contain the limit prices for which the CoW AMM is willing to trade. Trading at exactly these limit prices will not generate surplus for the CoW AMM, any price improvement from these limit prices will be surplus captured by the CoW AMM.
One thing to keep in mind when using the helper contract to generate these JitOrders is that both the orderFromSellAmount
and orderFromBuyAmount
methods return an order where the partiallyFillable
field is marked as true. However, since the driver does not support partially fillable JitOrders, it replaces the partiallyFillable field with false. This means that the partiallyFillable
field must be set to false before passing the solution to the driver and the signature of both the JitOrder and the commit hash in the pre-interaction should be updated accordingly.
Doing this will generate additional surplus in the solver competition (assuming you trade at a better price than the provided limit price). For example, if a solver would like to settle a user using outside liquidity that trades a pair for which there is a CoW AMM, then that solver can compare those prices with that of the CoW AMM. This (or part of this) interaction can then be replaced with the CoW AMM to generate additional surplus. This way the solver can integrate CoW AMMs by solving as if these CoW AMM's do not exist, and then check whether some of the outside interactions can be replaced by CoW AMMs (note: UPC and EBBO apply to CoW AMMs as well).
Another way that a solver can use CoW AMM's is by using outside liquidity from the competition/auction to trade with the CoW AMM, thereby re-balancing the AMM and receiving an additional surplus for doing so if the prices of the CoW AMM is off relative to the outside world.
The helper contracts are deployed here:
Settling a custom orderโ
You need to choose a valid CoW Swap order with the following restrictions:
sellToken
: any token in the pair.buyToken
: the other token in the pair.receiver
: must beRECEIVER_SAME_AS_OWNER
(zero address).sellAmount
: any value.buyAmount
: any value such that, after trading these exact amounts, the product of the token reserves is no smaller than before trading.validTo
: at most 5 minutes after the block timestamp at execution time.appData
: must be the value specified instaticInput
.feeAmount
: must be zero.kind
: any value.partiallyFillable
: any value.sellTokenBalance
: must beBALANCE_ERC20
.buyTokenBalance
: must beBALANCE_ERC20
.
The sell and buy amount specified are the limit amounts of the order. The actual executed amounts are determined using prices from the auction. In that regard, CoW AMM orders behave exactly like normal trader orders.
You also need to compute:
- the order hash
hash
as defined in the libraryGPv2Order
, and - the order signature
Example code that generates an order can be found in the order
function of the BCoWHelper contract.
This order can be included in a batch as any other CoW Protocol orders with two extra conditions:
- One of the pre-interactions must set the commitment by calling
BCoWPool.commit(hash)
. - Must contain at most one order from the AMM in the same batch.
Solvers using the non co-located driver should add a JitTrade
and a preInteraction
to their solution.
::
Surplusโ
The surplus for a CoW AMM order is measured the same way as other orders, by comparing the traded amounts to limit amounts.
When creating a CoW AMM order it is therefore encouraged to use the smallest possible limit amount which does not violate the invariant of the pool.
If we call X
(resp. Y
) the reserves of sell (resp. buy) token, and x
(resp. y
) the executed sell (resp. buy) amount, then the minimal buy amount is x Y / (X - x)
and the order surplus with that choice for the limit amount is:
x Y
surplus = y - ----- .
X - x
Maximizing this quantity will lead to the largest score in the solver competition.