Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cowprotocol/solver-rewards/llms.txt

Use this file to discover all available pages before exploring further.

Slippage accounting measures the net token imbalance a solver introduces when settling a batch. Positive slippage means the solver gained tokens (a surplus), and negative slippage means the solver lost tokens (a deficit). Because solvers interact with external liquidity venues whose prices move between trade signing and settlement, this imbalance is unavoidable — the pipeline simply measures and accounts for it.

What is slippage in this context?

In the CoW Protocol settlement context, a solver’s slippage is the difference between the tokens a solver was expected to exchange and the tokens that were actually transferred in its settlement transaction. It is computed entirely from on-chain token transfer events, not from any off-chain price model. The canonical reference is the period_slippage.sql Dune query (also browsable at Dune Analytics query #3427730).

Batch-wise token imbalance

Slippage is computed per settlement transaction by constructing a token balance sheet for the CoW Protocol settlement contract. Every transfer in or out of the settlement contract is classified into one of four categories:
CategoryDirectionMeaning
USER_INInboundTokens sent by a user into the settlement contract (adjusted for fees)
USER_OUTOutboundTokens sent from the settlement contract back to a user
AMM_INInboundAll other inbound transfers (from AMMs, WETH wraps, sDAI wraps, etc.)
AMM_OUTOutboundAll other outbound transfers (to AMMs, WETH unwraps, sDAI unwraps, etc.)
In all cases, IN means the settlement contract is the recipient of the transfer, and OUT means the settlement contract is the sender.

Transfer type classification rules

- USER_IN / USER_OUT: transfers emitted by the Settlement contract's Trade Event
  (USER_IN is adjusted for user fees)
- AMM_IN / AMM_OUT:  all on-chain transfers that are NOT user transfers
AMM_IN/AMM_OUT is a broad catch-all. It captures not only genuine AMM liquidity interactions but also WETH wraps and unwraps and sDAI wraps and unwraps.
The token imbalance for each token in a given settlement is:
imbalance = (USER_IN + AMM_IN) - (USER_OUT + AMM_OUT)
A non-zero imbalance after accounting for all user trades represents a residual surplus or deficit that the solver is responsible for.

Price evaluation in ETH

Token imbalances are denominated in their native units (e.g., USDC atoms, WBTC satoshis). To aggregate across all tokens, each imbalance is converted to ETH using two price sources:
  1. prices.usd hourly mean — Dune’s prices.usd table provides hourly USD prices for most tokens. The pipeline takes the mean price over the settlement’s hour.
  2. Intrinsic token prices — For tokens not covered by prices.usd, the pipeline falls back to the “intrinsic” prices embedded in the settlement calldata itself.
The SQL code for the price table is in the period_slippage.sql query (lines 354–436).
Wait for price data to finalize. Dune’s prices.usd table is populated from off-chain price feeds with a lag. Running the pipeline immediately after a period ends will produce incorrect (often zero) slippage values for recent settlements. The README explicitly warns: “we must wait some time after the period has ended for some data to finalize (e.g. prices.usd, ethereum.transactions, our event data, etc.).”

How slippage_eth is combined with network_fee_eth

The Dune query returns two separate fields per solver: slippage_eth (the net token imbalance in ETH) and network_fee_eth (the gas cost the solver paid for settlements). These are merged into a single slippage_eth value in RewardAndPenaltyDatum.from_series():
# src/fetch/payouts.py
@classmethod
def from_series(cls, frame: Series) -> RewardAndPenaltyDatum:
    """Constructor from row in Dataframe"""
    slippage = int(frame["slippage_eth"]) + int(frame["network_fee_eth"])
    ...
    return cls(
        ...
        slippage_eth=slippage,
        ...
    )
After this merge, self.slippage_eth in RewardAndPenaltyDatum represents the total buffer impact: both the raw token imbalance and the gas cost the solver paid.

Impact on total payout

Slippage feeds directly into the total outgoing native-token amount:
# src/fetch/payouts.py
def total_outgoing_eth(self) -> int:
    """Total outgoing amount (including slippage) for the payout."""
    return self.total_eth_reward() + self.slippage_eth
This is the fundamental equation of the payout:
total_outgoing_eth = total_eth_reward + slippage_eth
Where:
  • total_eth_reward is the batch reward scaled by (1 - service_fee), or the raw value if it’s negative
  • slippage_eth is the combined token imbalance + network fee (can be negative)
When slippage_eth is positive, the settlement contract owes the solver more (it gained tokens on their behalf). When it is negative, the solver owes the settlement contract (it lost tokens). A large enough negative slippage_eth can make total_outgoing_eth() negative, triggering an overdraft.
The solver created a surplus — e.g., got better prices than expected from AMMs.
primary_reward_eth = +0.01 ETH
slippage_eth       = +0.005 ETH   (surplus from AMM interactions)
──────────────────────────────────
total_outgoing_eth = +0.015 ETH   → ETH transfer to solver
If a solver’s slippage is so large that it exceeds their ETH payout, the README advises: “please do not proceed with the payout, until the root cause is known.” Investigate the anomaly with the project maintainers before posting any transaction.

Slippage in the payout flow

The slippage_eth column from SOLVER_PAYOUTS_COLUMNS enters the pipeline in compute_solver_payouts():
# src/fetch/payouts.py
solver_payouts["slippage_eth"] = (
    data_per_solver["sum_slippage_native"].fillna(0).astype(object)
)
And the per-period summary log reports the aggregate:
f"Slippage: {slippage / 10**18:.4f}\n"
f"Network Fees: {network_fee / 10**18:.4f}\n"
This makes it easy to spot unusually large slippage totals before executing any on-chain transactions.