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.

The solver rewards pipeline draws on two primary data sources: Dune Analytics for on-chain block interval resolution and PostgreSQL analytics databases for pre-computed solver performance metrics. A third source, CoinPaprika, supplies the token exchange rates needed to convert native-token reward caps into COW amounts.

Dune Analytics

The DuneFetcher class (src/fetch/dune.py) wraps the dune-client library and is the sole interface to Dune queries. It holds a DuneClient instance, the target blockchain string, and an AccountingPeriod, and resolves block numbers for that period at construction time.
src/fetch/dune.py
class DuneFetcher:  # pylint: disable=too-few-public-methods
    """
    Class Contains DuneAPI Instance and Accounting Period along with several get methods
    for various Dune Queries.
    """

    dune: DuneClient
    period: AccountingPeriod
    blockchain: str

    def __init__(
        self,
        dune: DuneClient,
        blockchain: str,
        period: AccountingPeriod,
    ):
        self.dune = dune
        self.blockchain = blockchain
        self.period = period
        self.start_block, self.end_block = self.get_block_interval()

Block interval resolution

get_block_interval() is called during __init__ and maps the accounting period’s start and end dates to on-chain block numbers. It executes the PERIOD_BLOCK_INTERVAL Dune query (query ID 3333356) with both the network’s blockchain name and the period date parameters, and asserts that exactly one row is returned.
src/fetch/dune.py
def get_block_interval(self) -> tuple[str, str]:
    """Returns block numbers corresponding to date interval"""
    results = self._get_query_results(
        self._parameterized_query(
            QUERIES["PERIOD_BLOCK_INTERVAL"], self._network_and_period_params()
        )
    )
    assert len(results) == 1, "Block Interval Query should return only 1 result!"
    return str(results[0]["start_block"]), str(results[0]["end_block"])

Query execution

All Dune queries are routed through _get_query_results(). When no cached execution ID (job_id) is supplied, the method calls dune.refresh(query, ping_frequency=15), which submits the query and polls every 15 seconds until results are available. The execution ID is logged for auditing.
src/fetch/dune.py
def _get_query_results(
    self, query: QueryBase, job_id: Optional[str] = None
) -> list[dict[str, str]]:
    """Internally every dune query execution is routed through here."""
    log.info(f"Fetching {query.name} from query: {query}")
    if not job_id:
        exec_result = self.dune.refresh(query, ping_frequency=15)
    else:
        exec_result = self.dune.get_result(job_id)

    log.info(f"Fetch completed for execution {exec_result.execution_id}")
    log_saver.print(
        f"{query.name} execution ID: {exec_result.execution_id}", Category.EXECUTION
    )
    return exec_result.get_rows()

Query parameters

Two helpers build the parameter lists passed to each query:
  • _period_params() — returns the accounting period’s start and end dates as QueryParameter objects.
  • _network_and_period_params() — appends a blockchain text parameter (e.g. "ethereum", "gnosis") to the period params.

Registered queries

All queries are defined in src/queries.py in the QUERIES dict:
KeyNameDune query ID
PERIOD_BLOCK_INTERVALBlock Interval for Accounting Period3333356
DASHBOARD_SLIPPAGEPeriod Solver Rewards2510345
Set DUNE_API_KEY in your environment before running any pipeline step. The key is read from the environment by DuneConfig.from_network().

Data flow

The following describes how data flows through the pipeline from raw sources to payout transfers:
  1. Block resolutionDuneFetcher runs the PERIOD_BLOCK_INTERVAL query on Dune to map accounting period dates to block numbers for the target network.
  2. Solver metricsMultiInstanceDBFetcher queries fct_data_per_solver_and_accounting_period across prod and staging databases, returning per-solver reward data pre-filtered to the accounting period.
  3. Fee dataMultiInstanceDBFetcher queries fct_partner_and_protocol_fees for partner and protocol fee breakdowns.
  4. Price conversionexchange_rate_atoms() fetches COW and native token USD prices from CoinPaprika to apply quote reward caps.
  5. Payout computationconstruct_payouts() combines the above inputs to produce Transfer objects split into COW and native token buckets.