← All docs

Wallet → cluster revenue attribution

Wallet → Cluster Revenue Attribution Spec

How to map 30-day incoming USDC transfers on endpoint pay_to wallets to endpoint clusters when one wallet serves many endpoints — often at different prices.

This spec defines max potential attribution: an optimistic per-cluster upper bound that avoids pretending we know more than the chain data allows.

In x402DiscoveryAnalysis: endpoints, cluster assignments, and wallet transfers are read from Postgres. Wallet sync (wallet-sync worker / x402-wallet-sync) incrementally ingests chain transfers into global wallet_transfers (deduped by (wallet, tx_hash)), with per-wallet block cursors in wallet_sync_state. Attribution projection (analytics worker) runs bounds → certainty → revenue over a rolling time window (WALLET_VOLUME_WINDOW_DAYS), triggered debounced on cluster.run_completed and wallet.volume_completed — it never calls Alchemy. Results persist in cluster_revenue_bounds, wallet_plausibility, endpoint_certainty, and cluster_descriptions. Legacy one-shot seed: x402-wallet-fetch. CSV export via scripts/export_flat.py remains an optional escape hatch.


Problem

We have three data sources:

Source Key fields Role
Postgres (endpoints, endpoint_text, price_snapshots, cluster assignments) pay_to, cluster_label, effective price, … Which endpoints exist and what they cost
Postgres (wallet_transfers via wallet_volume_runs) wallet, value_usdc, tx_hash, … Individual incoming USDC transfers
Aggregated wallet stats (derived from wallet_transfers) wallet, incoming_usdc, incoming_tx_count Per-wallet aggregates for proportional attribution

A wallet is the on-chain recipient (pay_to). Many endpoints can share one wallet. Incoming transfers do not say which endpoint was paid.

Proportional approach (x402-revenue / attribute_revenue): split each wallet's volume proportionally by endpoint count per cluster. Simple, but wrong when endpoints on the same wallet have different prices — a $1.00 payment is attributed partly to $0.001 endpoints that could never have received it.

Price-matched approach (x402-bounds): narrow attribution using tx value vs endpoint price, then split within the matching price bucket. Better, but still ambiguous when many endpoints share the same (pay_to, price) across multiple clusters (common for CDP-style catalogs).

Max potential (this spec): don't pick a single split when we can't. Report how much volume could have landed in each cluster, given price plausibility.


Does max potential make sense?

Yes. It matches what we actually know:

  • A tx of $0.05 to wallet W cannot have paid a $1.00 endpoint on W.
  • It could have paid any endpoint on W listed at $0.05 (exact scheme, Base USDC).
  • If 50 clusters each have at least one $0.05 endpoint on W, we cannot say which cluster earned it — but we can say each of those 50 clusters is plausible, and each could have received the full $0.05.

Max potential is a per-cluster upper bound, not a partition of revenue. Summing max potential across all clusters will exceed total chain volume whenever ambiguity exists. That is expected and useful.

Use it to answer: "Could this cluster plausibly explain this much money?" not "This cluster definitely earned exactly $X."


Definitions

Endpoint price

For each endpoint row:

  1. Use price_usd_effective, else price_usd (see analytics/pricing.py).
  2. Normalize to 6 decimal places (USDC on Base).
  3. Optionally restrict to exact-scheme accepts only (see Price index).

Skip endpoints with no usable price (~11 rows today).

Price index

Build once from endpoint rows (load_endpoint_rowsbuild_price_index):

pay_to → price → [EndpointRef…]
pay_to → price → set(cluster_label)

Precompute for each (pay_to, price):

  • endpoint_count
  • cluster_set — distinct clusters with ≥1 endpoint at that price
  • single_cluster — true when len(cluster_set) == 1

Plausible clusters for a transaction

For incoming tx (wallet, value):

  1. Exact match: value equals a listed price for wallet.
  2. Near match (optional): nearest listed price within --price-tolerance (default 0.000001 USDC).
  3. No match: fall back to wallet-wide plausibility.

Plausible cluster set = all clusters that have ≥1 endpoint on wallet at the matched price.

If near match ties (two prices equally close), treat as no price match → fallback.


Attribution modes

We report several stats side by side. They answer different questions.

Mode Per-tx rule Sums across clusters Interpretation
Proportional (existing) Split by endpoint share across all wallet endpoints ≈ total volume Neutral guess; smears across wrong prices
Max potential If cluster ∈ plausible set, add full value ≥ total volume Optimistic upper bound per cluster
Min potential (guaranteed) Add value only if plausible set has exactly one cluster ≤ total volume Pessimistic lower bound; only certain cases
Expected (price bucket) Split value evenly among endpoints at matched price, then by cluster ≈ total volume Best point estimate when implementing splits

Max potential is the headline stat for exploratory cluster ranking under ambiguity.


Max potential algorithm

Stream wallet transfers from Postgres (wallet_transfers, ordered by wallet).

For each tx with wallet, value (USDC):

plausible = clusters_plausible(wallet, value)

if plausible is empty:
    # Fallback: any cluster with any endpoint on this wallet
    plausible = all_clusters(wallet)
    match_type = "fallback"

for cluster in plausible:
    cluster_max_potential_usdc[cluster] += value
    cluster_max_potential_txs[cluster] += 1   # full tx counted per plausible cluster

track match_type counts (exact / near / fallback)

Important: do not divide value among plausible clusters. Each plausible cluster gets the full amount. Double-counting across clusters is intentional.

Derived cluster fields

max_potential_usdc_30d
max_potential_tx_count_30d
max_avg_tx_usdc_30d = max_potential_usdc / max_potential_tx_count

certain_usdc_30d          # min potential alias
certain_tx_count_30d
ambiguous_usdc_30d        # max - certain (per cluster, see note below)
plausible_cluster_count   # avg |plausible set| for txs touching this cluster

Note on ambiguous_usdc at cluster level: ambiguity is a property of a transaction, not cleanly decomposable per cluster. Prefer wallet-level ambiguity stats; at cluster level, report certain_usdc vs max_potential_usdc as bounds.

Wallet-level max potential

Same logic keyed by wallet instead of cluster:

  • wallet_max_potential_usdc = sum of tx values (always equals actual wallet volume).
  • Useful for sanity checks, not cluster ranking.

Fallback: no price match

When tx value matches no listed price for that wallet:

  • Max potential: every cluster with any endpoint on that wallet is plausible (widest bound).
  • Min potential: $0 added (we cannot prove any specific cluster).
  • Expected: revert to proportional split across all wallet endpoints (same as proportional revenue).

Log these txs; they dominate error when prices are stale or non-exact schemes are excluded.


Worked examples

Example A — Two prices, two clusters (clean case)

Wallet W has:

  • Cluster 1: one endpoint at $0.01
  • Cluster 2: one endpoint at $1.00
Tx value Plausible clusters Max potential added
$0.01 {1} C1 += $0.01
$1.00 {2} C2 += $1.00

Min potential = max potential. No ambiguity.

Example B — Same price, multiple clusters (catalog case)

Wallet W has 100 endpoints at $0.05 spanning clusters {A, B, C, …, Z}.

Tx: $0.05

  • Plausible clusters: all clusters with a $0.05 endpoint (say 20 clusters).
  • Max potential: each of the 20 clusters += $0.05 (20 × $0.05 = $1.00 total upper-bound mass).
  • Min potential: each cluster += $0 (cannot prove which one).
  • Expected: each cluster += $0.05 / (100 endpoints) × (endpoints that cluster has at $0.05).

Max potential tells you: "Any of these 20 themes could be driving $0.05 payments at this price point."

Example C — Proportional vs max (why this matters)

Wallet W: 999 endpoints at $0.001 (cluster Noise), 1 endpoint at $1.00 (cluster Premium).

One tx: $1.00

Mode Noise Premium
Proportional ~$0.999 ~$0.001
Max potential $0 $1.00
Min potential $0 $1.00

Proportional ranks Noise as the revenue driver. Max potential (and min, here) correctly identifies Premium as the only plausible recipient.


Data landscape (current export)

From endpoint export (approximate):

Metric Count
Wallets with 2+ endpoints 372
Wallets with 2+ distinct prices 273
(pay_to, price) pairs with 2+ endpoints 715
(pay_to, price) pairs spanning 2+ clusters 525

Max potential helps most for multi-price wallets (Example C). For same-price / multi-cluster wallets (Example B), max potential stays wide — pair it with certain_usdc and cluster endpoint counts to interpret.


Outputs

cluster_revenue_bounds (Postgres)

Column Description
cluster_label Cluster id (-1 = noise)
max_potential_usdc Upper-bound USDC
max_potential_tx_count Upper-bound tx count
certain_usdc Min potential (unique plausible cluster only)
certain_tx_count Tx count for certain cases
expected_usdc Price-bucket proportional estimate
proportional_usdc Existing split (for comparison)
endpoint_count Endpoints in cluster

analytics_runs.params_json (bounds job)

Run-level summary stored on the analytics run:

  • Total txs / USDC processed
  • Match rates: exact / near / fallback (% of USDC)
  • Unmatched wallet tx counts

wallet_plausibility (Postgres)

Per wallet:

  • incoming_usdc
  • distinct_prices
  • certain_tx_count / pct_certain
  • top_ambiguous_prices — prices that map to many clusters

CLI

x402-wallet-fetch --local
x402-bounds --local `
  --price-tolerance 0.000001 `
  --exact-scheme-only `
  --no-near-match
x402-certainty --local --min-certain 0.01
x402-revenue --local --describe-top 50

Flags (x402-bounds):

Flag Purpose
--exact-scheme-only Only index exact-scheme USDC accepts
--price-tolerance Near-match epsilon
--no-near-match Exact price only
--cluster-run-id Pin cluster run (default: latest)
--wallet-volume-run-id Pin wallet fetch run (default: latest completed)

Requires wallet transfers in Postgres (x402-wallet-fetch first).


Implementation

Code lives in src/x402_discovery/analytics/:

  1. wallet_attribution.py — price index, max/min/expected/proportional attribution.
  2. bounds.py — stream transfers from DB, persist bounds + plausibility.
  3. certainty.py — endpoint-level certainty rankings.
  4. revenue.py + gemini.py — proportional revenue + cluster descriptions.

Unit tests: tests/test_wallet_bounds.py (Examples A–C).


Interpretation guide

Question Stat to use
Could this cluster be a major revenue driver? max_potential_usdc
Do we know this cluster earned this? certain_usdc
Best single-number estimate expected_usdc (price bucket split)
Compare to old analysis proportional_usdc
How ambiguous is a cluster? max_potential / certain (when certain > 0); or high max with certain ≈ 0

When presenting externally:

  • Report ranges (certainmax) for high-value clusters.
  • Do not sum max_potential across clusters and call it "total revenue."
  • Rank clusters by max_potential for discovery; confirm with certain or manual sampling.

Edge cases

Case Max potential behavior
Unknown wallet (tx but no endpoints) Skip; log as unmatched
Endpoint missing price Excluded from price index; may force fallback
Non-exact scheme (batch-settlement) Exclude from index unless flag off; likely fallback
Stale price vs actual payment Near match or fallback; flag in stats
Duplicate endpoints same price same cluster Collapse in index (set semantics)
Multiple txs same second Each evaluated independently

Relationship to other commands

x402-wallet-fetch     → wallet_transfers (Postgres)
x402-revenue          → proportional + Gemini descriptions
x402-bounds           → max / min / expected (this spec)
x402-certainty        → endpoint-level certainty rankings

Max potential does not replace proportional attribution; it complements it with honest uncertainty bounds.


Open questions

  1. Near-match tolerance: Is 1e-6 USDC enough, or do we see systematic drift (e.g. fees)?
  2. Exact-scheme-only default: On or off for v1?
  3. Gemini copy: Descriptions say "up to $X" when certain << max (implemented in gemini.py).
  4. Fetch completeness: Bounds job warns when wallet coverage is incomplete.

Glossary

Term Meaning
pay_to / wallet On-chain USDC recipient for x402 payments
Price bucket All endpoints on a wallet sharing one listed price
Plausible cluster Cluster with ≥1 endpoint whose price matches the tx
Max potential Full tx value credited to every plausible cluster
Min potential / certain Full tx value credited only when exactly one plausible cluster
Expected Proportional split within the price bucket, then by cluster
Fallback No price match; use all wallet clusters (max) or proportional (expected)