Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8c2315c
fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1…
Flotapponnier Aug 7, 2026
4497d88
fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1…
Flotapponnier Aug 7, 2026
0caf2dc
feat: add wave 7 chains to /chains hub (fantom, kusama, hydration, ze…
Flotapponnier Aug 7, 2026
3f162e7
feat: add 15 wave 7 chains to /chains hub (#1790)
Flotapponnier Aug 7, 2026
a0ef237
fix: remove drift and variational from perp venue meta (404 on /perp …
Flotapponnier Aug 7, 2026
c4bcb14
Merge pull request #1791 from ChainBench/feat/wave7-chain-pages
Flotapponnier Aug 7, 2026
a68392d
fix: filter non-provider result links in answers, add bridge to footer
Flotapponnier Aug 7, 2026
37d2d18
Merge pull request #1792 from ChainBench/feat/wave7-chain-pages
Flotapponnier Aug 7, 2026
6af4b14
fix: drop dead RPC providers across 14 chains (DNS failures, 404s, pa…
Flotapponnier Aug 7, 2026
3a18a3c
Merge pull request #1793 from ChainBench/feat/wave7-chain-pages
Flotapponnier Aug 7, 2026
c6d9121
fix: hydration draft+placeholder provider, zetachain/songbird em-dash…
Flotapponnier Aug 7, 2026
c534730
fix: hydration draft+placeholder provider, zetachain/songbird em-dash…
Flotapponnier Aug 7, 2026
05d75d7
Merge remote-tracking branch 'origin/main' into dev
Flotapponnier Aug 8, 2026
8a11c67
feat: add /apps leaderboard foundation — specs, Go harness, Postgres …
Flotapponnier Aug 9, 2026
32833ae
fix: interface ctx type, float-free toMicroUSDC, goroutine error capt…
Flotapponnier Aug 9, 2026
8b37bfe
feat: /apps leaderboard foundation (#1797)
Flotapponnier Aug 9, 2026
adb7335
fix: dydx collector json key megavaultPnl, cumulative-to-delta PnL, D…
Flotapponnier Aug 9, 2026
b9ed117
Merge remote-tracking branch 'origin/dev' into feat/apps-leaderboard
Flotapponnier Aug 9, 2026
fcf4c3f
Merge pull request #1798 from ChainBench/feat/apps-leaderboard
Flotapponnier Aug 9, 2026
b6b869b
feat: add Hyperliquid collector via DeFiLlama (perps/HLP/spot breakdo…
Flotapponnier Aug 9, 2026
f44468d
Merge pull request #1799 from ChainBench/feat/apps-leaderboard
Flotapponnier Aug 9, 2026
9bc9f69
feat: /apps leaderboard page + Go API service (Hyperliquid $45M/30d, …
Flotapponnier Aug 9, 2026
94bf701
Merge pull request #1800 from ChainBench/feat/apps-leaderboard
Flotapponnier Aug 9, 2026
034a9d6
feat(apps): first-party data sources — HL node fills + GMX Subsquid (…
Flotapponnier Aug 9, 2026
58a681b
fix: dYdX collector — volume×fee-rate instead of MegaVault PnL
Flotapponnier Aug 10, 2026
a9d6a26
feat: add Gains.trade collector (The Graph, needs THEGRAPH_API_KEY)
Flotapponnier Aug 10, 2026
243e0ad
feat: Gains.trade collector via DeFiLlama public API (no key needed)
Flotapponnier Aug 10, 2026
f229e52
feat: gains-trade real-time WS collector via gTrade backend + eth_get…
Flotapponnier Aug 10, 2026
67576a8
fix: leaderboard UI polish + map treasury->burn bucket for Gains.trade
Flotapponnier Aug 10, 2026
66c1678
feat: add logos + /perp links to apps leaderboard table
Flotapponnier Aug 10, 2026
1fd444e
chore: remove defillama gains collector, WS handles gains going forward
Flotapponnier Aug 10, 2026
688b4fe
fix: update codex/defined auth to use defined-attestation-token + COD…
Flotapponnier Aug 10, 2026
6329ccc
Merge pull request #1802 from ChainBench/fix/codex-defined-cookie-mig…
Flotapponnier Aug 10, 2026
5d0ef3a
feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLl…
Flotapponnier Aug 10, 2026
4611234
fix: dYdX fee rate 5bps → 3.5bps (blended effective rate) (#1804)
Flotapponnier Aug 10, 2026
06d36c1
fix: dYdX full history — 90d limit → 1000d (Nov 2023 launch) (#1805)
Flotapponnier Aug 10, 2026
1834a1d
perf: use recording rules for lz/bridge histogram queries, drop raw r…
Flotapponnier Aug 10, 2026
a40284e
perf: Prometheus recording rules for lz/bridge histogram queries
Flotapponnier Aug 10, 2026
4d31fde
fix: truncate tron/token-quote methodology strings, telos em-dash in …
Flotapponnier Aug 10, 2026
6e47dd7
fix: tron/token-quote methodology too long, telos em-dash
Flotapponnier Aug 10, 2026
6837c83
perf: recording rules for hyperlane histogram queries
Flotapponnier Aug 10, 2026
da74d21
perf: recording rules for hyperlane histogram queries
Flotapponnier Aug 10, 2026
fea9515
revert: layerzero back to raw queries
Flotapponnier Aug 10, 2026
fcae361
fix: remove em dashes in kaia-rpc and aurora-rpc findings
Flotapponnier Aug 10, 2026
5d66ae7
feat: add solana-exec harness + /apps/exec page (#1811)
Flotapponnier Aug 10, 2026
ee29243
fix: log warning when solana-exec collector hits sig limit (#1812)
Flotapponnier Aug 10, 2026
2afd0b3
feat: paginate getSignaturesForAddress for complete tx coverage (#1813)
Flotapponnier Aug 10, 2026
e848876
fix: remove dead RPC providers, allow optional p90/p99 for gauge benches
Flotapponnier Aug 10, 2026
57d5742
remove: delete indexing-freshness bench
Flotapponnier Aug 10, 2026
23c80a5
remove: delete indexing-freshness bench
Flotapponnier Aug 10, 2026
7b52010
fix(codex): utls scraper + GitHub Actions token push (#1818)
Flotapponnier Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/codex-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Codex token push

on:
schedule:
- cron: '*/5 * * * *'
workflow_dispatch:

jobs:
push-token:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version-file: harnesses/aggregator-head-lag/go.mod
cache-dependency-path: harnesses/aggregator-head-lag/go.sum

- name: Build scraper
working-directory: harnesses/aggregator-head-lag
run: go build -o /tmp/codex-scraper ./cmd/test-utls/

- name: Scrape and push token
run: |
set -euo pipefail
output=$(MODE=default /tmp/codex-scraper 2>&1)
echo "$output" | head -5
token=$(echo "$output" | grep '^CODEX_TOKEN=' | cut -d= -f2-)
if [ -z "$token" ] || [ ${#token} -lt 100 ]; then
echo "ERROR: no token in output"
echo "$output"
exit 1
fi
echo "Got token (len=${#token}), pushing to sidecar..."
http_code=$(curl -s -o /tmp/push_resp -w "%{http_code}" -X POST \
-H "Content-Type: text/plain" \
--data-raw "$token" \
"http://57.130.19.92:8080/push")
if [ "$http_code" = "204" ]; then
echo "Push OK"
else
echo "Push failed (HTTP $http_code): $(cat /tmp/push_resp)"
exit 1
fi
112 changes: 112 additions & 0 deletions benchmarks/apps/04-addendum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# `/apps` — Addendum aux décisions ouvertes

**Date : 9 août 2026.** Ce document tranche les trois points laissés ouverts dans
`00-EXECUTION-BRIEF.md` et corrige un passage approximatif sur le budget de recompute.

---

## Décision 1 — Renommage de la colonne de classement

`net_real_revenue` est un abus de langage dès qu'on y inclut des buybacks : ce n'est pas
du revenue au sens comptable. Le terme induit le même péché de fusion que DefiLlama.

**Décision** : la colonne de classement s'appelle `net_value_capture_usd`, libellé UI
**« Valeur nette captée »**. La formule est affichée **en permanence** sous l'en-tête de
colonne (pas au survol) :

```
Valeur nette captée
= trésor + holders + burn − émissions
```

La barre segmentée décompose visuellement les trois termes positifs. Le chiffre scalaire
reste disponible pour le tri mais n'est jamais présenté sans sa formule.

**Cohérence avec P4** : `with_holders` est le défaut. `treasury_only` est disponible en
toggle discret. Les deux variantes sont calculées et stockées dans `fee_facts_windowed`
sous `variant IN ('with_holders', 'treasury_only')`.

---

## Décision 2 — Budget de recompute : critère chiffré

La formulation « c'est un simple GROUP BY, ça tient en 30 minutes » était paresseuse. Le
vrai goulot d'étranglement est la jointure de pricing sur `(token, hour)`.

**Analyse** :

- Seules les paires `(token, heure)` où un event a eu lieu sont pricées : la table de
prix est **creuse et pilotée par la demande**, pas dense.
- Les prix sont une observation (pas un artefact de méthodologie) : un recompute de
formule ne les invalide pas. Seul un changement de méthode de pricing le fait, et c'est
rare.
- Le long tail Solana (memecoins) tombe en `pool_ratio`, dérivé du swap lui-même. Ce sont
les cas les moins chers : aucun appel externe. Seuls ~50 tokens majeurs touchent Pyth.

**Critère d'acceptation chiffré (Phase 1)** :

```
Benchmark sur 20M d'events synthétiques, 3 000 tokens distincts :
- Recompute complet < 30 minutes sur le VPS (4 cores, 15GB RAM)
- EXPLAIN ANALYZE ne montre aucun Seq Scan sur fee_events ou fee_facts
- Si ces deux conditions ne sont pas satisfaites simultanément :
partitionner fee_events par mois (PARTITION BY RANGE sur ts)
et fee_facts par (bucket_start, methodology_version)
```

Le partitionnement n'est pas activé par défaut : il complique le schéma sans bénéfice
prouvé à l'échelle MVP. Le benchmark tranche, pas le raisonnement.

---

## Décision 3 — Aerodrome en T1, phase 4a

**Constat** : indexer les swaps Aerodrome en direct getLogs est intenable (milliers de
pools × millions de swaps). Mais on n'a pas besoin des swaps.

Les fees d'Aerodrome atterrissent dans les contrats `FeesVotingReward` (un par gauge),
via `notifyRewardAmount()` appelé par le Voter. L'event émis est :

```solidity
// IReward.sol — vérifié sur aerodrome-finance/contracts main
event NotifyReward(
address indexed from, // Voter
address indexed reward, // token de fee (USDC, WETH, etc.)
uint256 indexed epoch, // epochStart en secondes
uint256 amount // montant en unités natives
);

// topic0 vérifié :
// 0x52977ea98a2220a03ee9ba5cb003ada08d394ea10155483c95dc2dc77a7eb24b
```

Volume réel : O(epoch × gauges actives × tokens) — quelques centaines d'events par
semaine, pas un par swap. **Aerodrome est indexable en T1 sans Envio.**

**Prix à payer documenté** : granularité epoch (hebdomadaire). La fenêtre 24h d'Aerodrome
est de résolution dégradée — l'émission AERO est répartie uniformément sur 7 jours
(cf. `aerodrome.yaml : spread_over_epoch: true`) mais les fees sont discrets. L'UI affiche
un badge « résolution hebdomadaire » sur la ligne Aerodrome pour les fenêtres 24h et 7j.
La fenêtre 30j est pleine résolution.

**Comment découvrir les FeesVotingReward** : via `Voter.gaugeToFees(gaugeAddress)`.
Énumérer les gauges actifs depuis `Voter`, résoudre leur contrat de fees à l'init,
surveiller les nouveaux gauges à chaque epoch.

**Aerodrome passe de Phase 4 à Phase 4a** (parallèle à Uniswap, avant Raydium qui reste
le plus complexe).

---

## Correction — passage approximatif dans 01-architecture.md

Le §7 (séquencement) listait Raydium avant Uniswap. Ordre corrigé :

| Phase | Contenu |
|---|---|
| 1 | Socle + dYdX |
| 2 | Hyperliquid + GMX V2 |
| 3 | Page `/apps` + API publique (3 protocoles) |
| 4a | Aerodrome (T1 via NotifyReward) + Uniswap |
| 4b | Raydium (le plus complexe : accrual Solana) |
| 5 | Changelog, exports CSV, coverage page |
111 changes: 111 additions & 0 deletions benchmarks/apps/_taxonomy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Taxonomie partagée par toutes les specs /apps.
# Un fee_event ne peut porter qu'un `component` et qu'un `beneficiary` de ces listes.
# Toute modification ici est un changement de méthodologie : bump obligatoire de
# methodology_version sur les specs affectées + recompute complet.

schema_version: 1

components:
taker_fee:
included_in_gross: true
label: "Frais preneur"
maker_fee:
included_in_gross: true
label: "Frais offreur"
maker_rebate:
included_in_gross: false
label: "Rabais offreur"
note: "Montant stocké positif, beneficiary=lp. Sortie de trésorerie, pas un fee."
swap_fee:
included_in_gross: true
label: "Frais de swap AMM"
borrow_fee:
included_in_gross: true
label: "Frais d'emprunt"
note: "Payé au pool, pas à une contrepartie. Revenue réel du système."
liquidation_fee:
included_in_gross: true
label: "Frais de liquidation"
note: "Uniquement la part retenue par le protocole ou le pool. Le collatéral saisi est une perte du trader, jamais un fee."
pool_creation_fee:
included_in_gross: true
label: "Frais de création de pool"
bonding_curve_fee:
included_in_gross: true
label: "Frais de bonding curve"

# --- Collectés mais exclus des agrégats par défaut ---
funding_payment:
included_in_gross: false
toggleable: true
label: "Paiements de funding"
rationale: >-
Transfert de somme nulle entre longs et shorts. Le protocole n'en retient rien.
L'inclure gonfle mécaniquement les perps face aux DEX spot et rend le classement
inter-catégories inutilisable.
interface_fee:
included_in_gross: true
beneficiary_forced: third_party
is_app_layer: true
excluded_from_ranking: true
rationale: >-
Réel, mais Uniswap Labs a coupé ses frontend fees lors d'UNIfication. Les compter
chez les autres fausserait la comparaison. Mesuré, affiché, hors classement.
external_bribe:
included_in_gross: false
label: "Incentives externes"
rationale: "Payé par des tiers aux voters, pas un revenue généré par le protocole."
sequencer_revenue:
included_in_gross: false
counted_in: non_trading_holder_value
rationale: >-
Cas Unichain : entre dans le même mécanisme de burn que les protocol fees, mais
n'est pas un frais de trading. Additionné séparément et visiblement.

exclusions:
# Jamais collectés. Documentés pour que la page méthodologie soit complète.
- id: price_impact
reason: "Capté par l'inventaire du LP, non identifiable comme fee dans les events."
- id: mev
reason: "Va au searcher et au validateur, pas au protocole."
- id: gas_and_priority_fees
reason: "Coût réseau, pas revenue protocole."
- id: seized_collateral
reason: "Perte du trader, pas un frais payé au système."
- id: treasury_one_offs
reason: >-
Burns rétroactifs et distributions exceptionnelles (ex. les 100M UNI du trésor
lors d'UNIfication). Ce n'est pas du revenue récurrent ; l'inclure produirait des
pics absurdes.

beneficiaries:
lp: { label: "Fournisseurs de liquidité", in_protocol_cut: false, in_holder_value: false }
token_holder: { label: "Détenteurs du token", in_protocol_cut: false, in_holder_value: true }
staker: { label: "Stakers / validateurs", in_protocol_cut: false, in_holder_value: true }
burn: { label: "Brûlé", in_protocol_cut: false, in_holder_value: true }
treasury: { label: "Trésor", in_protocol_cut: true, in_holder_value: false }
insurance_fund: { label: "Fonds d'assurance", in_protocol_cut: true, in_holder_value: false }
third_party: { label: "Tiers (frontends, affiliés)", in_protocol_cut: false, in_holder_value: false }
creator: { label: "Créateur du pool / token", in_protocol_cut: false, in_holder_value: false }

# Métriques dérivées. Ce sont des VUES sur la partition ci-dessus, pas des colonnes
# indépendantes. Aucune ne peut compter deux fois le même event.
derived:
gross_fees: "Σ components[included_in_gross]"
lp_revenue: "Σ beneficiary == lp"
protocol_cut: "Σ beneficiary.in_protocol_cut"
token_holder_value: "Σ beneficiary.in_holder_value"
emissions_cost: "Σ_jours tokens_émis(j) × TWAP_usd(j)"
net_real_revenue:
with_holders: "protocol_cut + token_holder_value + non_trading_holder_value − emissions_cost"
treasury_only: "protocol_cut − emissions_cost"
default: with_holders
note: >-
`treasury_only` correspond à la définition littérale du brief mais classe Hyperliquid
comme quasi nul, ce qui contredit l'intention. `with_holders` produit le classement
décrit. Les deux sont calculées ; à trancher avant le lancement public.

invariants:
unallocated_tolerance_bps: 50
witness_divergence_warn_bps: 200
witness_divergence_quarantine_bps: 500
Loading
Loading