From df101f0cec9e1be9414e06ddbffe7facaae652ee Mon Sep 17 00:00:00 2001
From: Milos Dzepina
Date: Thu, 21 May 2026 12:25:45 +0200
Subject: [PATCH 01/38] Merge development to main (Release) (#146)
Signed-off-by: Milos Dzepina
---
src/data/testimonials.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/data/testimonials.json b/src/data/testimonials.json
index fd8fb8d..2846926 100644
--- a/src/data/testimonials.json
+++ b/src/data/testimonials.json
@@ -14,8 +14,8 @@
"name": "Paul Otto",
"organization": "F5 Crypto",
"avatar": "/images/testimonials/paul-otto.png",
- "url": "https://www.f5.xyz/",
- "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF has become a vital part in our token analysis at F5 Crypto."
+ "url": "https://f5crypto.com/en/",
+ "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
}
]
}
From 458faf3483dccc788641a3e7022a1b7ab2230fea Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 12:23:03 +0200
Subject: [PATCH 02/38] refactor: normalize token data into content atoms with
composed read models
---
.github/workflows/update-token-timestamps.yml | 10 +-
.../aave/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
.../evaluations/aave/offchain/_metric.json | 6 +
.../aave/offchain/offchain__distribution.json | 15 +
.../aave/offchain/offchain__licensing.json | 5 +
.../aave/offchain/offchain__trademark.json | 15 +
.../aave/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 64 ++
.../onchain-ctrl__censorship.json | 15 +
.../onchain-ctrl__governance-workflow.json | 15 +
.../onchain-ctrl__protocol-upgrade.json | 43 +
.../onchain-ctrl__role-accountability.json | 21 +
.../onchain-ctrl/onchain-ctrl__supply.json | 15 +
.../onchain-ctrl__token-upgrade.json | 27 +
.../evaluations/aave/val-accrual/_metric.json | 6 +
.../aave/val-accrual/val-accrual__active.json | 25 +
.../val-accrual/val-accrual__mechanism.json | 22 +
.../val-accrual/val-accrual__offchain.json | 8 +
.../val-accrual/val-accrual__treasury.json | 38 +
.../aave/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 15 +
.../verifiability__token-source.json | 20 +
.../aero/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
.../evaluations/aero/offchain/_metric.json | 6 +
.../aero/offchain/offchain__distribution.json | 15 +
.../aero/offchain/offchain__licensing.json | 5 +
.../aero/offchain/offchain__trademark.json | 15 +
.../aero/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 44 +
.../onchain-ctrl__censorship.json | 38 +
.../onchain-ctrl__governance-workflow.json | 43 +
.../onchain-ctrl__protocol-upgrade.json | 15 +
.../onchain-ctrl__role-accountability.json | 22 +
.../onchain-ctrl/onchain-ctrl__supply.json | 55 ++
.../onchain-ctrl__token-upgrade.json | 20 +
.../evaluations/aero/val-accrual/_metric.json | 6 +
.../aero/val-accrual/val-accrual__active.json | 84 ++
.../val-accrual/val-accrual__mechanism.json | 33 +
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 5 +
.../aero/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 20 +
.../verifiability__token-source.json | 20 +
.../evaluations/crv/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 15 +
content/evaluations/crv/offchain/_metric.json | 6 +
.../crv/offchain/offchain__distribution.json | 15 +
.../crv/offchain/offchain__licensing.json | 5 +
.../crv/offchain/offchain__trademark.json | 15 +
.../evaluations/crv/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 17 +
.../onchain-ctrl__censorship.json | 20 +
.../onchain-ctrl__governance-workflow.json | 25 +
.../onchain-ctrl__protocol-upgrade.json | 44 +
.../onchain-ctrl__role-accountability.json | 28 +
.../onchain-ctrl/onchain-ctrl__supply.json | 38 +
.../onchain-ctrl__token-upgrade.json | 15 +
.../evaluations/crv/val-accrual/_metric.json | 6 +
.../crv/val-accrual/val-accrual__active.json | 39 +
.../val-accrual/val-accrual__mechanism.json | 39 +
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 15 +
.../crv/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 15 +
.../verifiability__token-source.json | 20 +
.../evaluations/ena/distribution/_metric.json | 6 +
.../distribution__concentration.json | 22 +
.../distribution__supply-schedule.json | 22 +
content/evaluations/ena/offchain/_metric.json | 6 +
.../ena/offchain/offchain__distribution.json | 15 +
.../ena/offchain/offchain__licensing.json | 20 +
.../ena/offchain/offchain__trademark.json | 15 +
.../evaluations/ena/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 43 +
.../onchain-ctrl__censorship.json | 27 +
.../onchain-ctrl__governance-workflow.json | 33 +
.../onchain-ctrl__protocol-upgrade.json | 68 ++
.../onchain-ctrl__role-accountability.json | 58 ++
.../onchain-ctrl/onchain-ctrl__supply.json | 22 +
.../onchain-ctrl__token-upgrade.json | 22 +
.../evaluations/ena/val-accrual/_metric.json | 6 +
.../ena/val-accrual/val-accrual__active.json | 59 ++
.../val-accrual/val-accrual__mechanism.json | 38 +
.../val-accrual/val-accrual__offchain.json | 33 +
.../val-accrual/val-accrual__treasury.json | 43 +
.../ena/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 71 ++
.../verifiability__token-source.json | 20 +
.../ethfi/distribution/_metric.json | 6 +
.../distribution__concentration.json | 16 +
.../distribution__supply-schedule.json | 21 +
.../evaluations/ethfi/offchain/_metric.json | 6 +
.../offchain/offchain__distribution.json | 16 +
.../ethfi/offchain/offchain__licensing.json | 21 +
.../ethfi/offchain/offchain__trademark.json | 16 +
.../ethfi/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 17 +
.../onchain-ctrl__censorship.json | 27 +
.../onchain-ctrl__governance-workflow.json | 27 +
.../onchain-ctrl__protocol-upgrade.json | 38 +
.../onchain-ctrl__role-accountability.json | 43 +
.../onchain-ctrl/onchain-ctrl__supply.json | 22 +
.../onchain-ctrl__token-upgrade.json | 43 +
.../ethfi/val-accrual/_metric.json | 6 +
.../val-accrual/val-accrual__active.json | 32 +
.../val-accrual/val-accrual__mechanism.json | 17 +
.../val-accrual/val-accrual__offchain.json | 8 +
.../val-accrual/val-accrual__treasury.json | 22 +
.../ethfi/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 21 +
.../verifiability__token-source.json | 17 +
.../evaluations/ldo/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
content/evaluations/ldo/offchain/_metric.json | 6 +
.../ldo/offchain/offchain__distribution.json | 25 +
.../ldo/offchain/offchain__licensing.json | 25 +
.../ldo/offchain/offchain__trademark.json | 20 +
.../evaluations/ldo/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 43 +
.../onchain-ctrl__censorship.json | 33 +
.../onchain-ctrl__governance-workflow.json | 64 ++
.../onchain-ctrl__protocol-upgrade.json | 48 +
.../onchain-ctrl__role-accountability.json | 50 ++
.../onchain-ctrl/onchain-ctrl__supply.json | 17 +
.../onchain-ctrl__token-upgrade.json | 33 +
.../evaluations/ldo/val-accrual/_metric.json | 6 +
.../ldo/val-accrual/val-accrual__active.json | 46 +
.../val-accrual/val-accrual__mechanism.json | 15 +
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 28 +
.../ldo/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 15 +
.../verifiability__token-source.json | 20 +
.../lqty/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 20 +
.../evaluations/lqty/offchain/_metric.json | 6 +
.../lqty/offchain/offchain__distribution.json | 25 +
.../lqty/offchain/offchain__licensing.json | 25 +
.../lqty/offchain/offchain__trademark.json | 25 +
.../lqty/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 16 +
.../onchain-ctrl__censorship.json | 15 +
.../onchain-ctrl__governance-workflow.json | 20 +
.../onchain-ctrl__protocol-upgrade.json | 15 +
.../onchain-ctrl__role-accountability.json | 15 +
.../onchain-ctrl/onchain-ctrl__supply.json | 15 +
.../onchain-ctrl__token-upgrade.json | 15 +
.../evaluations/lqty/val-accrual/_metric.json | 6 +
.../lqty/val-accrual/val-accrual__active.json | 40 +
.../val-accrual/val-accrual__mechanism.json | 20 +
.../val-accrual/val-accrual__offchain.json | 8 +
.../val-accrual/val-accrual__treasury.json | 15 +
.../lqty/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 20 +
.../verifiability__token-source.json | 20 +
.../ondo/distribution/_metric.json | 6 +
.../distribution__concentration.json | 22 +
.../distribution__supply-schedule.json | 22 +
.../evaluations/ondo/offchain/_metric.json | 6 +
.../ondo/offchain/offchain__distribution.json | 17 +
.../ondo/offchain/offchain__licensing.json | 27 +
.../ondo/offchain/offchain__trademark.json | 17 +
.../ondo/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 43 +
.../onchain-ctrl__censorship.json | 22 +
.../onchain-ctrl__governance-workflow.json | 42 +
.../onchain-ctrl__protocol-upgrade.json | 63 ++
.../onchain-ctrl__role-accountability.json | 94 ++
.../onchain-ctrl/onchain-ctrl__supply.json | 38 +
.../onchain-ctrl__token-upgrade.json | 33 +
.../evaluations/ondo/val-accrual/_metric.json | 6 +
.../ondo/val-accrual/val-accrual__active.json | 32 +
.../val-accrual/val-accrual__mechanism.json | 48 +
.../val-accrual/val-accrual__offchain.json | 51 ++
.../val-accrual/val-accrual__treasury.json | 17 +
.../ondo/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 51 ++
.../verifiability__token-source.json | 20 +
.../evaluations/sky/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 17 +
content/evaluations/sky/offchain/_metric.json | 6 +
.../sky/offchain/offchain__distribution.json | 17 +
.../sky/offchain/offchain__licensing.json | 17 +
.../sky/offchain/offchain__trademark.json | 28 +
.../evaluations/sky/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 27 +
.../onchain-ctrl__censorship.json | 17 +
.../onchain-ctrl__governance-workflow.json | 38 +
.../onchain-ctrl__protocol-upgrade.json | 38 +
.../onchain-ctrl__role-accountability.json | 43 +
.../onchain-ctrl/onchain-ctrl__supply.json | 33 +
.../onchain-ctrl__token-upgrade.json | 17 +
.../evaluations/sky/val-accrual/_metric.json | 6 +
.../sky/val-accrual/val-accrual__active.json | 48 +
.../val-accrual/val-accrual__mechanism.json | 38 +
.../val-accrual/val-accrual__offchain.json | 20 +
.../val-accrual/val-accrual__treasury.json | 17 +
.../sky/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 22 +
.../verifiability__token-source.json | 22 +
.../evaluations/uni/distribution/_metric.json | 6 +
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 37 +
content/evaluations/uni/offchain/_metric.json | 6 +
.../uni/offchain/offchain__distribution.json | 15 +
.../uni/offchain/offchain__licensing.json | 5 +
.../uni/offchain/offchain__trademark.json | 15 +
.../evaluations/uni/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 5 +
.../onchain-ctrl__censorship.json | 15 +
.../onchain-ctrl__governance-workflow.json | 20 +
.../onchain-ctrl__protocol-upgrade.json | 38 +
.../onchain-ctrl__role-accountability.json | 55 ++
.../onchain-ctrl/onchain-ctrl__supply.json | 33 +
.../onchain-ctrl__token-upgrade.json | 20 +
.../evaluations/uni/val-accrual/_metric.json | 6 +
.../uni/val-accrual/val-accrual__active.json | 65 ++
.../val-accrual/val-accrual__mechanism.json | 49 +
.../val-accrual/val-accrual__offchain.json | 15 +
.../val-accrual/val-accrual__treasury.json | 15 +
.../uni/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 30 +
.../verifiability__token-source.json | 20 +
.../evaluations/yb/distribution/_metric.json | 6 +
.../distribution__concentration.json | 22 +
.../distribution__supply-schedule.json | 17 +
content/evaluations/yb/offchain/_metric.json | 6 +
.../yb/offchain/offchain__distribution.json | 15 +
.../yb/offchain/offchain__licensing.json | 22 +
.../yb/offchain/offchain__trademark.json | 5 +
.../evaluations/yb/onchain-ctrl/_metric.json | 6 +
.../onchain-ctrl__access-gating.json | 22 +
.../onchain-ctrl__censorship.json | 15 +
.../onchain-ctrl__governance-workflow.json | 32 +
.../onchain-ctrl__protocol-upgrade.json | 27 +
.../onchain-ctrl__role-accountability.json | 43 +
.../yb/onchain-ctrl/onchain-ctrl__supply.json | 27 +
.../onchain-ctrl__token-upgrade.json | 22 +
.../evaluations/yb/val-accrual/_metric.json | 6 +
.../yb/val-accrual/val-accrual__active.json | 42 +
.../val-accrual/val-accrual__mechanism.json | 38 +
.../yb/val-accrual/val-accrual__offchain.json | 8 +
.../yb/val-accrual/val-accrual__treasury.json | 27 +
.../evaluations/yb/verifiability/_metric.json | 6 +
.../verifiability__protocol-source.json | 22 +
.../verifiability__token-source.json | 20 +
{src/data => content}/faq.json | 0
content/framework/_meta.json | 10 +
content/framework/distribution.json | 19 +
content/framework/offchain.json | 24 +
content/framework/onchain-ctrl.json | 44 +
content/framework/val-accrual.json | 29 +
content/framework/verifiability.json | 19 +
{src/data => content}/testimonials.json | 0
content/tokens/aave.json | 21 +
content/tokens/aero.json | 21 +
content/tokens/crv.json | 21 +
content/tokens/ena.json | 21 +
content/tokens/ethfi.json | 21 +
content/tokens/ldo.json | 21 +
content/tokens/lqty.json | 21 +
content/tokens/ondo.json | 21 +
content/tokens/sky.json | 21 +
content/tokens/uni.json | 21 +
content/tokens/yb.json | 21 +
package.json | 5 +-
scripts/compose-data.mjs | 177 ++++
scripts/get-changed-token-ids.mjs | 149 +---
scripts/migrate-to-atoms.mjs | 127 +++
scripts/sync-coingecko-ids.mjs | 28 +-
scripts/update-token-timestamps.mjs | 42 +-
src/components/ui/evidence-link.tsx | 7 +-
src/data/generated/faq.json | 60 ++
src/data/generated/framework.json | 140 +++
.../{tokens.json => generated/index.json} | 269 +++---
src/data/generated/testimonials.json | 21 +
src/data/generated/tokens/aave.json | 550 ++++++++++++
src/data/generated/tokens/aero.json | 628 +++++++++++++
src/data/generated/tokens/crv.json | 554 ++++++++++++
src/data/generated/tokens/ena.json | 810 +++++++++++++++++
src/data/generated/tokens/ethfi.json | 601 +++++++++++++
src/data/generated/tokens/ldo.json | 676 ++++++++++++++
src/data/generated/tokens/lqty.json | 510 +++++++++++
src/data/generated/tokens/ondo.json | 836 ++++++++++++++++++
src/data/generated/tokens/sky.json | 641 ++++++++++++++
src/data/generated/tokens/uni.json | 636 +++++++++++++
src/data/generated/tokens/yb.json | 603 +++++++++++++
src/lib/data-fetcher.ts | 166 ----
src/lib/faq-data.ts | 19 +-
src/lib/framework.ts | 39 +-
src/lib/metrics-data.ts | 102 +--
src/lib/schemas/atoms.ts | 121 +++
src/lib/schemas/common.ts | 53 ++
src/lib/schemas/index.ts | 10 +
src/lib/schemas/read-models.ts | 116 +++
src/lib/scoring.ts | 45 +-
src/lib/testimonials-data.ts | 17 +-
src/lib/token-data-dynamic.ts | 91 --
src/lib/token-data.ts | 7 +-
tests/atoms-valid.test.ts | 106 +++
tests/freshness.test.ts | 43 +
tests/golden/faq.json | 58 ++
{src/data => tests/golden}/framework.json | 0
{src/data => tests/golden}/metrics.json | 350 +++++---
tests/golden/scores.json | 585 ++++++++++++
tests/golden/testimonials.json | 21 +
tests/golden/tokens.json | 277 ++++++
tests/round-trip.test.ts | 120 +++
vitest.config.ts | 14 +
317 files changed, 15445 insertions(+), 790 deletions(-)
create mode 100644 content/evaluations/aave/distribution/_metric.json
create mode 100644 content/evaluations/aave/distribution/distribution__concentration.json
create mode 100644 content/evaluations/aave/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/aave/offchain/_metric.json
create mode 100644 content/evaluations/aave/offchain/offchain__distribution.json
create mode 100644 content/evaluations/aave/offchain/offchain__licensing.json
create mode 100644 content/evaluations/aave/offchain/offchain__trademark.json
create mode 100644 content/evaluations/aave/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/aave/val-accrual/_metric.json
create mode 100644 content/evaluations/aave/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/aave/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/aave/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/aave/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/aave/verifiability/_metric.json
create mode 100644 content/evaluations/aave/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/aave/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/aero/distribution/_metric.json
create mode 100644 content/evaluations/aero/distribution/distribution__concentration.json
create mode 100644 content/evaluations/aero/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/aero/offchain/_metric.json
create mode 100644 content/evaluations/aero/offchain/offchain__distribution.json
create mode 100644 content/evaluations/aero/offchain/offchain__licensing.json
create mode 100644 content/evaluations/aero/offchain/offchain__trademark.json
create mode 100644 content/evaluations/aero/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/aero/val-accrual/_metric.json
create mode 100644 content/evaluations/aero/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/aero/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/aero/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/aero/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/aero/verifiability/_metric.json
create mode 100644 content/evaluations/aero/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/aero/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/crv/distribution/_metric.json
create mode 100644 content/evaluations/crv/distribution/distribution__concentration.json
create mode 100644 content/evaluations/crv/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/crv/offchain/_metric.json
create mode 100644 content/evaluations/crv/offchain/offchain__distribution.json
create mode 100644 content/evaluations/crv/offchain/offchain__licensing.json
create mode 100644 content/evaluations/crv/offchain/offchain__trademark.json
create mode 100644 content/evaluations/crv/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/crv/val-accrual/_metric.json
create mode 100644 content/evaluations/crv/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/crv/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/crv/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/crv/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/crv/verifiability/_metric.json
create mode 100644 content/evaluations/crv/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/crv/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/ena/distribution/_metric.json
create mode 100644 content/evaluations/ena/distribution/distribution__concentration.json
create mode 100644 content/evaluations/ena/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/ena/offchain/_metric.json
create mode 100644 content/evaluations/ena/offchain/offchain__distribution.json
create mode 100644 content/evaluations/ena/offchain/offchain__licensing.json
create mode 100644 content/evaluations/ena/offchain/offchain__trademark.json
create mode 100644 content/evaluations/ena/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/ena/val-accrual/_metric.json
create mode 100644 content/evaluations/ena/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/ena/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/ena/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/ena/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/ena/verifiability/_metric.json
create mode 100644 content/evaluations/ena/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/ena/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/ethfi/distribution/_metric.json
create mode 100644 content/evaluations/ethfi/distribution/distribution__concentration.json
create mode 100644 content/evaluations/ethfi/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/ethfi/offchain/_metric.json
create mode 100644 content/evaluations/ethfi/offchain/offchain__distribution.json
create mode 100644 content/evaluations/ethfi/offchain/offchain__licensing.json
create mode 100644 content/evaluations/ethfi/offchain/offchain__trademark.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/ethfi/val-accrual/_metric.json
create mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/ethfi/verifiability/_metric.json
create mode 100644 content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/ethfi/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/ldo/distribution/_metric.json
create mode 100644 content/evaluations/ldo/distribution/distribution__concentration.json
create mode 100644 content/evaluations/ldo/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/ldo/offchain/_metric.json
create mode 100644 content/evaluations/ldo/offchain/offchain__distribution.json
create mode 100644 content/evaluations/ldo/offchain/offchain__licensing.json
create mode 100644 content/evaluations/ldo/offchain/offchain__trademark.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/ldo/val-accrual/_metric.json
create mode 100644 content/evaluations/ldo/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/ldo/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/ldo/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/ldo/verifiability/_metric.json
create mode 100644 content/evaluations/ldo/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/ldo/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/lqty/distribution/_metric.json
create mode 100644 content/evaluations/lqty/distribution/distribution__concentration.json
create mode 100644 content/evaluations/lqty/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/lqty/offchain/_metric.json
create mode 100644 content/evaluations/lqty/offchain/offchain__distribution.json
create mode 100644 content/evaluations/lqty/offchain/offchain__licensing.json
create mode 100644 content/evaluations/lqty/offchain/offchain__trademark.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/lqty/val-accrual/_metric.json
create mode 100644 content/evaluations/lqty/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/lqty/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/lqty/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/lqty/verifiability/_metric.json
create mode 100644 content/evaluations/lqty/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/lqty/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/ondo/distribution/_metric.json
create mode 100644 content/evaluations/ondo/distribution/distribution__concentration.json
create mode 100644 content/evaluations/ondo/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/ondo/offchain/_metric.json
create mode 100644 content/evaluations/ondo/offchain/offchain__distribution.json
create mode 100644 content/evaluations/ondo/offchain/offchain__licensing.json
create mode 100644 content/evaluations/ondo/offchain/offchain__trademark.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/ondo/val-accrual/_metric.json
create mode 100644 content/evaluations/ondo/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/ondo/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/ondo/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/ondo/verifiability/_metric.json
create mode 100644 content/evaluations/ondo/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/ondo/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/sky/distribution/_metric.json
create mode 100644 content/evaluations/sky/distribution/distribution__concentration.json
create mode 100644 content/evaluations/sky/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/sky/offchain/_metric.json
create mode 100644 content/evaluations/sky/offchain/offchain__distribution.json
create mode 100644 content/evaluations/sky/offchain/offchain__licensing.json
create mode 100644 content/evaluations/sky/offchain/offchain__trademark.json
create mode 100644 content/evaluations/sky/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/sky/val-accrual/_metric.json
create mode 100644 content/evaluations/sky/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/sky/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/sky/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/sky/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/sky/verifiability/_metric.json
create mode 100644 content/evaluations/sky/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/sky/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/uni/distribution/_metric.json
create mode 100644 content/evaluations/uni/distribution/distribution__concentration.json
create mode 100644 content/evaluations/uni/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/uni/offchain/_metric.json
create mode 100644 content/evaluations/uni/offchain/offchain__distribution.json
create mode 100644 content/evaluations/uni/offchain/offchain__licensing.json
create mode 100644 content/evaluations/uni/offchain/offchain__trademark.json
create mode 100644 content/evaluations/uni/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/uni/val-accrual/_metric.json
create mode 100644 content/evaluations/uni/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/uni/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/uni/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/uni/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/uni/verifiability/_metric.json
create mode 100644 content/evaluations/uni/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/uni/verifiability/verifiability__token-source.json
create mode 100644 content/evaluations/yb/distribution/_metric.json
create mode 100644 content/evaluations/yb/distribution/distribution__concentration.json
create mode 100644 content/evaluations/yb/distribution/distribution__supply-schedule.json
create mode 100644 content/evaluations/yb/offchain/_metric.json
create mode 100644 content/evaluations/yb/offchain/offchain__distribution.json
create mode 100644 content/evaluations/yb/offchain/offchain__licensing.json
create mode 100644 content/evaluations/yb/offchain/offchain__trademark.json
create mode 100644 content/evaluations/yb/onchain-ctrl/_metric.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 content/evaluations/yb/val-accrual/_metric.json
create mode 100644 content/evaluations/yb/val-accrual/val-accrual__active.json
create mode 100644 content/evaluations/yb/val-accrual/val-accrual__mechanism.json
create mode 100644 content/evaluations/yb/val-accrual/val-accrual__offchain.json
create mode 100644 content/evaluations/yb/val-accrual/val-accrual__treasury.json
create mode 100644 content/evaluations/yb/verifiability/_metric.json
create mode 100644 content/evaluations/yb/verifiability/verifiability__protocol-source.json
create mode 100644 content/evaluations/yb/verifiability/verifiability__token-source.json
rename {src/data => content}/faq.json (100%)
create mode 100644 content/framework/_meta.json
create mode 100644 content/framework/distribution.json
create mode 100644 content/framework/offchain.json
create mode 100644 content/framework/onchain-ctrl.json
create mode 100644 content/framework/val-accrual.json
create mode 100644 content/framework/verifiability.json
rename {src/data => content}/testimonials.json (100%)
create mode 100644 content/tokens/aave.json
create mode 100644 content/tokens/aero.json
create mode 100644 content/tokens/crv.json
create mode 100644 content/tokens/ena.json
create mode 100644 content/tokens/ethfi.json
create mode 100644 content/tokens/ldo.json
create mode 100644 content/tokens/lqty.json
create mode 100644 content/tokens/ondo.json
create mode 100644 content/tokens/sky.json
create mode 100644 content/tokens/uni.json
create mode 100644 content/tokens/yb.json
create mode 100644 scripts/compose-data.mjs
create mode 100644 scripts/migrate-to-atoms.mjs
create mode 100644 src/data/generated/faq.json
create mode 100644 src/data/generated/framework.json
rename src/data/{tokens.json => generated/index.json} (83%)
create mode 100644 src/data/generated/testimonials.json
create mode 100644 src/data/generated/tokens/aave.json
create mode 100644 src/data/generated/tokens/aero.json
create mode 100644 src/data/generated/tokens/crv.json
create mode 100644 src/data/generated/tokens/ena.json
create mode 100644 src/data/generated/tokens/ethfi.json
create mode 100644 src/data/generated/tokens/ldo.json
create mode 100644 src/data/generated/tokens/lqty.json
create mode 100644 src/data/generated/tokens/ondo.json
create mode 100644 src/data/generated/tokens/sky.json
create mode 100644 src/data/generated/tokens/uni.json
create mode 100644 src/data/generated/tokens/yb.json
delete mode 100644 src/lib/data-fetcher.ts
create mode 100644 src/lib/schemas/atoms.ts
create mode 100644 src/lib/schemas/common.ts
create mode 100644 src/lib/schemas/index.ts
create mode 100644 src/lib/schemas/read-models.ts
delete mode 100644 src/lib/token-data-dynamic.ts
create mode 100644 tests/atoms-valid.test.ts
create mode 100644 tests/freshness.test.ts
create mode 100644 tests/golden/faq.json
rename {src/data => tests/golden}/framework.json (100%)
rename {src/data => tests/golden}/metrics.json (95%)
create mode 100644 tests/golden/scores.json
create mode 100644 tests/golden/testimonials.json
create mode 100644 tests/golden/tokens.json
create mode 100644 tests/round-trip.test.ts
create mode 100644 vitest.config.ts
diff --git a/.github/workflows/update-token-timestamps.yml b/.github/workflows/update-token-timestamps.yml
index 0bd701b..c91649e 100644
--- a/.github/workflows/update-token-timestamps.yml
+++ b/.github/workflows/update-token-timestamps.yml
@@ -4,8 +4,8 @@ on:
push:
branches: [development]
paths:
- - src/data/metrics.json
- - src/data/tokens.json
+ - content/tokens/**
+ - content/evaluations/**
permissions:
contents: write
@@ -59,6 +59,10 @@ jobs:
if: steps.changed.outputs.ids != ''
run: node scripts/update-token-timestamps.mjs --ids "${{ steps.changed.outputs.ids }}" --timestamp "${{ steps.timestamp.outputs.value }}"
+ - name: Recompose read models
+ if: steps.changed.outputs.ids != ''
+ run: node scripts/compose-data.mjs
+
- name: Set commit message
id: commit-message
run: |
@@ -70,6 +74,6 @@ jobs:
echo "No changes to commit."
exit 0
fi
- git add src/data/tokens.json
+ git add content src/data/generated
git commit -am "${{ steps.commit-message.outputs.message }}"
git push origin HEAD:development
diff --git a/content/evaluations/aave/distribution/_metric.json b/content/evaluations/aave/distribution/_metric.json
new file mode 100644
index 0000000..2163fcd
--- /dev/null
+++ b/content/evaluations/aave/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/aave/distribution/distribution__concentration.json b/content/evaluations/aave/distribution/distribution__concentration.json
new file mode 100644
index 0000000..5e8dfb9
--- /dev/null
+++ b/content/evaluations/aave/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "evidence": []
+}
diff --git a/content/evaluations/aave/distribution/distribution__supply-schedule.json b/content/evaluations/aave/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..195571e
--- /dev/null
+++ b/content/evaluations/aave/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
+ "evidence": []
+}
diff --git a/content/evaluations/aave/offchain/_metric.json b/content/evaluations/aave/offchain/_metric.json
new file mode 100644
index 0000000..3c60448
--- /dev/null
+++ b/content/evaluations/aave/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/aave/offchain/offchain__distribution.json b/content/evaluations/aave/offchain/offchain__distribution.json
new file mode 100644
index 0000000..729980a
--- /dev/null
+++ b/content/evaluations/aave/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface terms identify Aave Labs as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://aave.com/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/offchain/offchain__licensing.json b/content/evaluations/aave/offchain/offchain__licensing.json
new file mode 100644
index 0000000..5cae96f
--- /dev/null
+++ b/content/evaluations/aave/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/content/evaluations/aave/offchain/offchain__trademark.json b/content/evaluations/aave/offchain/offchain__trademark.json
new file mode 100644
index 0000000..46ea782
--- /dev/null
+++ b/content/evaluations/aave/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Trademark filing",
+ "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/_metric.json b/content/evaluations/aave/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..af0a600
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..4a5906e
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,64 @@
+{
+ "status": "positive",
+ "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
+ "evidence": [
+ {
+ "name": "Core",
+ "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
+ "urls": [
+ {
+ "name": "Core Protocol Role addresses",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
+ "type": "github"
+ },
+ {
+ "name": "Core Protocol Roles in ACLManager",
+ "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
+ "type": "explorer"
+ },
+ {
+ "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
+ "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
+ "type": "explorer"
+ },
+ {
+ "name": "POOL_ADMIN_ROLE: Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Delegated Steward Roles",
+ "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
+ "urls": [
+ {
+ "name": "Stewards (docs)",
+ "url": "https://aave.com/help/governance/aave-community",
+ "type": "docs"
+ },
+ {
+ "name": "Stewards (addresses)",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Protocol Emergency Guardian",
+ "summary": "A separate multisig that executes limited emergency operations for the protocol.",
+ "urls": [
+ {
+ "name": "Protocol Emergency Guardian",
+ "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
+ "type": "docs"
+ },
+ {
+ "name": "Detailed protocol permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..7ca7f0a
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token's implementation code",
+ "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..e0d0466
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://aave.com/docs/ecosystem/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..27b3b55
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "Holders control implementation upgrades for all v3 market deployments.",
+ "evidence": [
+ {
+ "name": "Upgrade Documentation",
+ "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
+ "urls": [
+ {
+ "name": "Upgradability per contract",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Ownership Chain",
+ "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
+ "urls": [
+ {
+ "name": "Pool",
+ "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance",
+ "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..a065c83
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,21 @@
+{
+ "status": "positive",
+ "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
+ "evidence": [
+ {
+ "name": "Governance Emergency Guardian",
+ "urls": [
+ {
+ "name": "Onchain address",
+ "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Detailed Governance Permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..32d8315
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..1182c67
--- /dev/null
+++ b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "The AAVE token is upgradeable but controlled by token holders.",
+ "evidence": [
+ {
+ "name": "Ownership Chain",
+ "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
+ "urls": [
+ {
+ "name": "AAVE Proxy",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ProxyAdmin",
+ "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/val-accrual/_metric.json b/content/evaluations/aave/val-accrual/_metric.json
new file mode 100644
index 0000000..d5958bb
--- /dev/null
+++ b/content/evaluations/aave/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__active.json b/content/evaluations/aave/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..497f899
--- /dev/null
+++ b/content/evaluations/aave/val-accrual/val-accrual__active.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Safety Module - Incentives",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Transition",
+ "url": "https://aave.com/help/umbrella/stake",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Activation Proposal",
+ "url": "https://vote.onaave.com/proposal/?proposalId=320",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__mechanism.json b/content/evaluations/aave/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..a0753b1
--- /dev/null
+++ b/content/evaluations/aave/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
+ "evidence": [
+ {
+ "name": "ACL Control",
+ "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
+ "urls": [
+ {
+ "name": "POOL_ADMIN role",
+ "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
+ "type": "docs"
+ },
+ {
+ "name": "ACLManager",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__offchain.json b/content/evaluations/aave/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..7d7ee44
--- /dev/null
+++ b/content/evaluations/aave/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__treasury.json b/content/evaluations/aave/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..cb89d8e
--- /dev/null
+++ b/content/evaluations/aave/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "Token holders direct treasury via governance.",
+ "urls": [
+ {
+ "name": "Treasury docs",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Fee Sources",
+ "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
+ "urls": [
+ {
+ "name": "mintToTreasury (PoolLogic)",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
+ "type": "github"
+ },
+ {
+ "name": "Flashloan premium",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
+ "type": "github"
+ },
+ {
+ "name": "Liquidation fee",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/verifiability/_metric.json b/content/evaluations/aave/verifiability/_metric.json
new file mode 100644
index 0000000..6bfa4a9
--- /dev/null
+++ b/content/evaluations/aave/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/aave/verifiability/verifiability__protocol-source.json b/content/evaluations/aave/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..92845b9
--- /dev/null
+++ b/content/evaluations/aave/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aave/verifiability/verifiability__token-source.json b/content/evaluations/aave/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..5f8b629
--- /dev/null
+++ b/content/evaluations/aave/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/distribution/_metric.json b/content/evaluations/aero/distribution/_metric.json
new file mode 100644
index 0000000..5ca27bd
--- /dev/null
+++ b/content/evaluations/aero/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/aero/distribution/distribution__concentration.json b/content/evaluations/aero/distribution/distribution__concentration.json
new file mode 100644
index 0000000..dad8ff0
--- /dev/null
+++ b/content/evaluations/aero/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "evidence": []
+}
diff --git a/content/evaluations/aero/distribution/distribution__supply-schedule.json b/content/evaluations/aero/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..ccc8eba
--- /dev/null
+++ b/content/evaluations/aero/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
+ "evidence": []
+}
diff --git a/content/evaluations/aero/offchain/_metric.json b/content/evaluations/aero/offchain/_metric.json
new file mode 100644
index 0000000..e86b6c4
--- /dev/null
+++ b/content/evaluations/aero/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/aero/offchain/offchain__distribution.json b/content/evaluations/aero/offchain/offchain__distribution.json
new file mode 100644
index 0000000..bc7fd01
--- /dev/null
+++ b/content/evaluations/aero/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Legal",
+ "url": "https://aero.drome.eth.link/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/offchain/offchain__licensing.json b/content/evaluations/aero/offchain/offchain__licensing.json
new file mode 100644
index 0000000..e33118a
--- /dev/null
+++ b/content/evaluations/aero/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/content/evaluations/aero/offchain/offchain__trademark.json b/content/evaluations/aero/offchain/offchain__trademark.json
new file mode 100644
index 0000000..af8ead8
--- /dev/null
+++ b/content/evaluations/aero/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "USPTO Report",
+ "url": "https://uspto.report/TM/99083103",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/_metric.json b/content/evaluations/aero/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..2c8fa4d
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..f854e83
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,44 @@
+{
+ "status": "warning",
+ "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
+ "evidence": [
+ {
+ "name": "Fee Manager Role",
+ "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
+ "urls": [
+ {
+ "name": "Safe (Fee Manager)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-SlipStream Fees",
+ "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
+ "urls": [
+ {
+ "name": "PoolFactory: FeeManager",
+ "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "SlipStream Fees",
+ "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
+ "urls": [
+ {
+ "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
+ "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "SwapFeeModule: setCustomFee",
+ "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..de6f75c
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
+ "evidence": [
+ {
+ "name": "Team Rate",
+ "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
+ "urls": [
+ {
+ "name": "Safe (Team)",
+ "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
+ "urls": [
+ {
+ "name": "Governor (Safe)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
+ "type": "explorer"
+ },
+ {
+ "name": "Emission Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..c6dac94
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
+ "evidence": [
+ {
+ "name": "Voting System",
+ "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "VotingEscrow",
+ "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Voter",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Council",
+ "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
+ "urls": [
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://aerodrome.limited/pages/security.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..3e17d2e
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contract Addresses",
+ "url": "https://aerodrome.finance/security",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..2c27da6
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
+ "evidence": [
+ {
+ "name": "Emergency Council",
+ "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
+ "urls": [
+ {
+ "name": "Voter: emergencyCouncil",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..0dfcfda
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,55 @@
+{
+ "status": "positive",
+ "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
+ "evidence": [
+ {
+ "name": "Minter Contract",
+ "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
+ "urls": [
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
+ "urls": [
+ {
+ "name": "Minter Emission Increase (Epochs 1-14)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
+ "type": "github"
+ },
+ {
+ "name": "Minter Emission Decay",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Growth Emissions",
+ "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
+ "urls": [
+ {
+ "name": "Growth Emissions Formula",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Team Emission Rate",
+ "summary": "Currently set to 0% of total weekly emissions.",
+ "urls": [
+ {
+ "name": "Team Emission Rate",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..f04a477
--- /dev/null
+++ b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/val-accrual/_metric.json b/content/evaluations/aero/val-accrual/_metric.json
new file mode 100644
index 0000000..98d089b
--- /dev/null
+++ b/content/evaluations/aero/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__active.json b/content/evaluations/aero/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..09489eb
--- /dev/null
+++ b/content/evaluations/aero/val-accrual/val-accrual__active.json
@@ -0,0 +1,84 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
+ "evidence": [
+ {
+ "name": "Growth Emissions",
+ "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
+ "urls": [
+ {
+ "name": "Growth Transfer to RewardDistributor",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
+ "type": "github"
+ },
+ {
+ "name": "RewardsDistributor Claim",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Non-Slipstream Trading Fees",
+ "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Gauge Deposit Logic",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Accrued",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
+ "type": "github"
+ },
+ {
+ "name": "Voter calling Gauge to claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed by Gauge on PoolFees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Slipstream Trading Fees",
+ "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Fees Split",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees calculated separately",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
+ "type": "github"
+ },
+ {
+ "name": "Non Staked LP Fees collected",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees to feesVotingReward",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
+ "type": "github"
+ },
+ {
+ "name": "veAERO voters claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__mechanism.json b/content/evaluations/aero/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..463eee0
--- /dev/null
+++ b/content/evaluations/aero/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
+ "evidence": [
+ {
+ "name": "Locking Control",
+ "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
+ "urls": [
+ {
+ "name": "VotingEscrow create_lock",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
+ "urls": [
+ {
+ "name": "Voter vote function",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
+ "type": "github"
+ },
+ {
+ "name": "Gauge getReward",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__offchain.json b/content/evaluations/aero/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..ee52be6
--- /dev/null
+++ b/content/evaluations/aero/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
+ "evidence": []
+}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__treasury.json b/content/evaluations/aero/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..3c85ba0
--- /dev/null
+++ b/content/evaluations/aero/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
+ "evidence": []
+}
diff --git a/content/evaluations/aero/verifiability/_metric.json b/content/evaluations/aero/verifiability/_metric.json
new file mode 100644
index 0000000..41079e6
--- /dev/null
+++ b/content/evaluations/aero/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/aero/verifiability/verifiability__protocol-source.json b/content/evaluations/aero/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..13be4d3
--- /dev/null
+++ b/content/evaluations/aero/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contracts (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Aerodrome Slipstream (GitHub)",
+ "url": "https://github.com/aerodrome-finance/slipstream",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/aero/verifiability/verifiability__token-source.json b/content/evaluations/aero/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..a7da64f
--- /dev/null
+++ b/content/evaluations/aero/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token (Basescan)",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Aero.sol Source (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/distribution/_metric.json b/content/evaluations/crv/distribution/_metric.json
new file mode 100644
index 0000000..40ad32e
--- /dev/null
+++ b/content/evaluations/crv/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/crv/distribution/distribution__concentration.json b/content/evaluations/crv/distribution/distribution__concentration.json
new file mode 100644
index 0000000..b5fa2a4
--- /dev/null
+++ b/content/evaluations/crv/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
+ "evidence": []
+}
diff --git a/content/evaluations/crv/distribution/distribution__supply-schedule.json b/content/evaluations/crv/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..5f677ee
--- /dev/null
+++ b/content/evaluations/crv/distribution/distribution__supply-schedule.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/offchain/_metric.json b/content/evaluations/crv/offchain/_metric.json
new file mode 100644
index 0000000..74fb5a8
--- /dev/null
+++ b/content/evaluations/crv/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/crv/offchain/offchain__distribution.json b/content/evaluations/crv/offchain/offchain__distribution.json
new file mode 100644
index 0000000..7a6be45
--- /dev/null
+++ b/content/evaluations/crv/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve Legal",
+ "url": "https://www.curve.finance/dex/ethereum/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/offchain/offchain__licensing.json b/content/evaluations/crv/offchain/offchain__licensing.json
new file mode 100644
index 0000000..a17a25c
--- /dev/null
+++ b/content/evaluations/crv/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/content/evaluations/crv/offchain/offchain__trademark.json b/content/evaluations/crv/offchain/offchain__trademark.json
new file mode 100644
index 0000000..a7441b2
--- /dev/null
+++ b/content/evaluations/crv/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Swiss Trademark Registry",
+ "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/_metric.json b/content/evaluations/crv/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..5e84784
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..b8d6f95
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
+ "evidence": [
+ {
+ "name": "Add/Kill Gauge",
+ "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
+ "urls": [
+ {
+ "name": "Gauge Kill Implementation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5704953
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Standard Transfer",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
+ "type": "github"
+ },
+ {
+ "name": "ERC20CRV.vy Metadata Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..5617c7a
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aragon Voting Contract",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent Contract",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
+ "type": "explorer"
+ },
+ {
+ "name": "CRV Token: Admin is set to Agent",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..2e50f5a
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,44 @@
+{
+ "status": "positive",
+ "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
+ "evidence": [
+ {
+ "name": "Core Contracts",
+ "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
+ "urls": [
+ {
+ "name": "CRV Token (Admin: Agent)",
+ "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
+ "type": "explorer"
+ },
+ {
+ "name": "GaugeController (Admin: Agent)",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent Contract",
+ "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Voting Contract",
+ "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..c84b85c
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,28 @@
+{
+ "status": "positive",
+ "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
+ "evidence": [
+ {
+ "name": "Gauge Addition",
+ "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
+ "urls": [
+ {
+ "name": "GaugeController: admin is Agent",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Pool Factory Ownership",
+ "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
+ "urls": [
+ {
+ "name": "Curve Pool Factory: admin is OwnerProxy",
+ "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..ef408a0
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
+ "evidence": [
+ {
+ "name": "Supply Schedule",
+ "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ },
+ {
+ "name": "ERC20CRV.vy Yearly Epoch Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Access",
+ "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Mint Access",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
+ "type": "github"
+ },
+ {
+ "name": "Minter.vy Gauge Validation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..0f5537c
--- /dev/null
+++ b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Source",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/val-accrual/_metric.json b/content/evaluations/crv/val-accrual/_metric.json
new file mode 100644
index 0000000..6260c77
--- /dev/null
+++ b/content/evaluations/crv/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__active.json b/content/evaluations/crv/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..66103a1
--- /dev/null
+++ b/content/evaluations/crv/val-accrual/val-accrual__active.json
@@ -0,0 +1,39 @@
+{
+ "status": "positive",
+ "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
+ "evidence": [
+ {
+ "name": "CRV Emissions Rewards",
+ "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
+ "urls": [
+ {
+ "name": "working_balance reward calculation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Pool Rewards in crvUSD",
+ "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
+ "urls": [
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Borrow Rewards in crvUSD",
+ "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
+ "urls": [
+ {
+ "name": "FeeSplitter",
+ "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__mechanism.json b/content/evaluations/crv/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..5989d6d
--- /dev/null
+++ b/content/evaluations/crv/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,39 @@
+{
+ "status": "positive",
+ "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
+ "evidence": [
+ {
+ "name": "Pool Fee Control",
+ "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "DAI/USDC/USDT Pool: commit_new_fee",
+ "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burner Attachment",
+ "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "StableSwapProxy: set_burner",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burn Execution",
+ "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
+ "urls": [
+ {
+ "name": "StableSwapProxy: burn",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__offchain.json b/content/evaluations/crv/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..ed5f6d9
--- /dev/null
+++ b/content/evaluations/crv/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
+ "evidence": []
+}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__treasury.json b/content/evaluations/crv/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..a1ca859
--- /dev/null
+++ b/content/evaluations/crv/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "veCRV Revenue Share (Docs)",
+ "url": "https://docs.curve.finance/user/vecrv/revenue",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/verifiability/_metric.json b/content/evaluations/crv/verifiability/_metric.json
new file mode 100644
index 0000000..8a84410
--- /dev/null
+++ b/content/evaluations/crv/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/crv/verifiability/verifiability__protocol-source.json b/content/evaluations/crv/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..dfa266b
--- /dev/null
+++ b/content/evaluations/crv/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Curve DAO protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve DAO Contracts (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/crv/verifiability/verifiability__token-source.json b/content/evaluations/crv/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..88abb06
--- /dev/null
+++ b/content/evaluations/crv/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Token (Etherscan)",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ERC20CRV.vy Source (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/distribution/_metric.json b/content/evaluations/ena/distribution/_metric.json
new file mode 100644
index 0000000..99cf88c
--- /dev/null
+++ b/content/evaluations/ena/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/ena/distribution/distribution__concentration.json b/content/evaluations/ena/distribution/distribution__concentration.json
new file mode 100644
index 0000000..6302a56
--- /dev/null
+++ b/content/evaluations/ena/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
+ "urls": [
+ {
+ "name": "Tokenomist.ai - ENA",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ },
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/distribution/distribution__supply-schedule.json b/content/evaluations/ena/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..2906392
--- /dev/null
+++ b/content/evaluations/ena/distribution/distribution__supply-schedule.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
+ "evidence": [
+ {
+ "name": "Vesting Schedules",
+ "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
+ "urls": [
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ },
+ {
+ "name": "Tokenomist.ai - ENA Vesting",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/offchain/_metric.json b/content/evaluations/ena/offchain/_metric.json
new file mode 100644
index 0000000..692c514
--- /dev/null
+++ b/content/evaluations/ena/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/ena/offchain/offchain__distribution.json b/content/evaluations/ena/offchain/offchain__distribution.json
new file mode 100644
index 0000000..09259c1
--- /dev/null
+++ b/content/evaluations/ena/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/offchain/offchain__licensing.json b/content/evaluations/ena/offchain/offchain__licensing.json
new file mode 100644
index 0000000..5df1cf4
--- /dev/null
+++ b/content/evaluations/ena/offchain/offchain__licensing.json
@@ -0,0 +1,20 @@
+{
+ "status": "warning",
+ "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena GitHub License",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/offchain/offchain__trademark.json b/content/evaluations/ena/offchain/offchain__trademark.json
new file mode 100644
index 0000000..3ea8daa
--- /dev/null
+++ b/content/evaluations/ena/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/_metric.json b/content/evaluations/ena/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..aa732f2
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..85c8a35
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
+ "evidence": [
+ {
+ "name": "Privileged Roles (per Multisig Matrix)",
+ "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Gatekeeper Powers",
+ "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
+ "urls": [
+ {
+ "name": "`disableMintRedeem()` (line 278)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
+ "type": "github"
+ },
+ {
+ "name": "`removeMinterRole()` (line 339)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
+ "type": "github"
+ },
+ {
+ "name": "`removeRedeemerRole()` (line 345)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..ea421fc
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,27 @@
+{
+ "status": "warning",
+ "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
+ "evidence": [
+ {
+ "name": "sENA/sUSDe Blacklist Capabilities",
+ "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
+ "urls": [
+ {
+ "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
+ "type": "github"
+ },
+ {
+ "name": "`redistributeLockedAmount()` (lines 106-127)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
+ "type": "github"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..f3a9970
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,33 @@
+{
+ "status": "warning",
+ "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
+ "evidence": [
+ {
+ "name": "Snapshot Governance",
+ "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
+ "urls": [
+ {
+ "name": "Snapshot Space",
+ "url": "https://snapshot.org/#/ethenagovernance.eth",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Multisig Execution",
+ "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
+ "urls": [
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..967e44f
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,68 @@
+{
+ "status": "warning",
+ "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Contracts",
+ "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Contracts (sENA and rsENA)",
+ "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
+ "urls": [
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Implementation",
+ "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Implementation",
+ "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..b840de7
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,58 @@
+{
+ "status": "warning",
+ "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
+ "evidence": [
+ {
+ "name": "Multisig Control Matrix",
+ "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ },
+ {
+ "name": "Hot Swap Multisig",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "Trading Operations Multisig",
+ "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
+ "type": "explorer"
+ },
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "EOA Control Points",
+ "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
+ "urls": [
+ {
+ "name": "StakingRewardsDistributor Operator (EOA)",
+ "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
+ "type": "explorer"
+ },
+ {
+ "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..ff12bcc
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
+ "evidence": [
+ {
+ "name": "Mint Function",
+ "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
+ "urls": [
+ {
+ "name": "ENA.sol `mint()` function (lines 42-49)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token totalSupply",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..6f0354c
--- /dev/null
+++ b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
+ "evidence": [
+ {
+ "name": "ENA Non-Upgradeability Verification",
+ "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
+ "urls": [
+ {
+ "name": "ENA.sol Source",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/val-accrual/_metric.json b/content/evaluations/ena/val-accrual/_metric.json
new file mode 100644
index 0000000..12be505
--- /dev/null
+++ b/content/evaluations/ena/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__active.json b/content/evaluations/ena/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..35bf37b
--- /dev/null
+++ b/content/evaluations/ena/val-accrual/val-accrual__active.json
@@ -0,0 +1,59 @@
+{
+ "status": "warning",
+ "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
+ "evidence": [
+ {
+ "name": "Fee Switch Status",
+ "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "USDe Token (verify totalSupply)",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Ethena Network Airdrops",
+ "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
+ "urls": [
+ {
+ "name": "Ethena Network Documentation",
+ "url": "https://docs.ethena.fi/ethena-network",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "rsENA (Restaked ENA via Symbiotic)",
+ "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
+ "urls": [
+ {
+ "name": "rsENA Contract",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA Staking Documentation",
+ "url": "https://docs.ethena.fi/ena",
+ "type": "docs"
+ },
+ {
+ "name": "Mellow Finance rsENA Vault",
+ "url": "https://app.mellow.finance/vaults/ethereum-rsena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__mechanism.json b/content/evaluations/ena/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..1e775e7
--- /dev/null
+++ b/content/evaluations/ena/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "warning",
+ "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
+ "evidence": [
+ {
+ "name": "ENA Value Accrual Controls",
+ "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
+ "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Tokenholder Cannot Force Activation",
+ "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__offchain.json b/content/evaluations/ena/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..dd3c133
--- /dev/null
+++ b/content/evaluations/ena/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,33 @@
+{
+ "status": "warning",
+ "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
+ "evidence": [
+ {
+ "name": "USDe Yield Sources",
+ "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
+ "urls": [
+ {
+ "name": "Coin Metrics Analysis (USDe Yield Sources)",
+ "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Yield Distribution Flow",
+ "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
+ "urls": [
+ {
+ "name": "`transferInRewards()` (lines 88-94)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
+ "type": "github"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__treasury.json b/content/evaluations/ena/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..cec61a8
--- /dev/null
+++ b/content/evaluations/ena/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
+ "evidence": [
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
+ "urls": [
+ {
+ "name": "Key Addresses Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-addresses",
+ "type": "docs"
+ },
+ {
+ "name": "Hot Swap Multisig (revenue receiver)",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Reserve Fund (Negative Funding Backup)",
+ "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
+ "urls": [
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/verifiability/_metric.json b/content/evaluations/ena/verifiability/_metric.json
new file mode 100644
index 0000000..9ae768f
--- /dev/null
+++ b/content/evaluations/ena/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/ena/verifiability/verifiability__protocol-source.json b/content/evaluations/ena/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..f2d5e2d
--- /dev/null
+++ b/content/evaluations/ena/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,71 @@
+{
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
+ "evidence": [
+ {
+ "name": "Verified Contracts",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "GitHub Repository",
+ "urls": [
+ {
+ "name": "Ethena Public Assets (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Audits",
+ "urls": [
+ {
+ "name": "Code4rena 2023 Audit",
+ "url": "https://github.com/code-423n4/2023-10-ethena",
+ "type": "github"
+ },
+ {
+ "name": "Code4rena 2024 Audit",
+ "url": "https://github.com/code-423n4/2024-11-ethena-labs",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ena/verifiability/verifiability__token-source.json b/content/evaluations/ena/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..832ff34
--- /dev/null
+++ b/content/evaluations/ena/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA.sol Source (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/distribution/_metric.json b/content/evaluations/ethfi/distribution/_metric.json
new file mode 100644
index 0000000..e97bf51
--- /dev/null
+++ b/content/evaluations/ethfi/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/ethfi/distribution/distribution__concentration.json b/content/evaluations/ethfi/distribution/distribution__concentration.json
new file mode 100644
index 0000000..a95862d
--- /dev/null
+++ b/content/evaluations/ethfi/distribution/distribution__concentration.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/distribution/distribution__supply-schedule.json b/content/evaluations/ethfi/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..2fbf530
--- /dev/null
+++ b/content/evaluations/ethfi/distribution/distribution__supply-schedule.json
@@ -0,0 +1,21 @@
+{
+ "status": "warning",
+ "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "DefiLlama Unlocks",
+ "url": "https://defillama.com/unlocks/ether.fi",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/offchain/_metric.json b/content/evaluations/ethfi/offchain/_metric.json
new file mode 100644
index 0000000..e2152cc
--- /dev/null
+++ b/content/evaluations/ethfi/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/ethfi/offchain/offchain__distribution.json b/content/evaluations/ethfi/offchain/offchain__distribution.json
new file mode 100644
index 0000000..45c898e
--- /dev/null
+++ b/content/evaluations/ethfi/offchain/offchain__distribution.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
+ "evidence": [
+ {
+ "name": "Legal Entity",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/offchain/offchain__licensing.json b/content/evaluations/ethfi/offchain/offchain__licensing.json
new file mode 100644
index 0000000..bfa11ce
--- /dev/null
+++ b/content/evaluations/ethfi/offchain/offchain__licensing.json
@@ -0,0 +1,21 @@
+{
+ "status": "warning",
+ "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
+ "evidence": [
+ {
+ "name": "License",
+ "urls": [
+ {
+ "name": "GitHub Repository",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Terms of Use (Non-Contract IP)",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/offchain/offchain__trademark.json b/content/evaluations/ethfi/offchain/offchain__trademark.json
new file mode 100644
index 0000000..c573eef
--- /dev/null
+++ b/content/evaluations/ethfi/offchain/offchain__trademark.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
+ "evidence": [
+ {
+ "name": "Trademark Ownership",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/_metric.json b/content/evaluations/ethfi/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..ca55eb6
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..5b3acc3
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
+ "evidence": [
+ {
+ "name": "Pause Authority",
+ "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
+ "urls": [
+ {
+ "name": "EtherFiAdmin Pause Function",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..2c44b78
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,27 @@
+{
+ "status": "warning",
+ "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
+ "evidence": [
+ {
+ "name": "Token Analysis",
+ "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum ETHFI (Upgradeable)",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI (Upgradeable)",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..472575d
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,27 @@
+{
+ "status": "at_risk",
+ "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "evidence": [
+ {
+ "name": "Governance Structure",
+ "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "urls": [
+ {
+ "name": "Governance Info",
+ "url": "https://vote.ether.fi/info",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Resources",
+ "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Roadmap",
+ "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..a68cded
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "warning",
+ "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
+ "urls": [
+ {
+ "name": "RoleRegistry Upgrade Check",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
+ "type": "github"
+ },
+ {
+ "name": "LiquidityPool Upgrade Authorization",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "RoleRegistry Owner",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..0936aa7
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
+ "evidence": [
+ {
+ "name": "RoleRegistry Owner (Upgrade Timelock)",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock (72h)",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Two-Timelock System",
+ "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
+ "urls": [
+ {
+ "name": "Upgrade Admin (4-of-7)",
+ "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Timelock (8h)",
+ "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Admin (3-of-5)",
+ "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..98f9307
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
+ "evidence": [
+ {
+ "name": "Fixed Supply",
+ "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..4024ae0
--- /dev/null
+++ b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
+ "evidence": [
+ {
+ "name": "Mainnet Token (Not Upgradeable)",
+ "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "L2 Tokens (Upgradeable, No Timelock)",
+ "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
+ "urls": [
+ {
+ "name": "Arbitrum ETHFI",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum Admin (3-of-6)",
+ "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ },
+ {
+ "name": "Base Admin (3-of-6)",
+ "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/val-accrual/_metric.json b/content/evaluations/ethfi/val-accrual/_metric.json
new file mode 100644
index 0000000..aad827f
--- /dev/null
+++ b/content/evaluations/ethfi/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__active.json b/content/evaluations/ethfi/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..84671dc
--- /dev/null
+++ b/content/evaluations/ethfi/val-accrual/val-accrual__active.json
@@ -0,0 +1,32 @@
+{
+ "status": "positive",
+ "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
+ "evidence": [
+ {
+ "name": "Buyback Program",
+ "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
+ "urls": [
+ {
+ "name": "ETHFI Buyback Program",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback History (Dune)",
+ "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
+ "type": "docs"
+ },
+ {
+ "name": "sETHFI Staking",
+ "url": "https://www.ether.fi/app/ethfi",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback Wallet (1-of-5)",
+ "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json b/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..0e84742
--- /dev/null
+++ b/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
+ "evidence": [
+ {
+ "name": "Fee Configuration",
+ "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
+ "urls": [
+ {
+ "name": "LiquidityPool Fee Functions",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json b/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..be71a37
--- /dev/null
+++ b/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json b/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..1e800d0
--- /dev/null
+++ b/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/verifiability/_metric.json b/content/evaluations/ethfi/verifiability/_metric.json
new file mode 100644
index 0000000..14c61d2
--- /dev/null
+++ b/content/evaluations/ethfi/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json b/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..17de7d2
--- /dev/null
+++ b/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,21 @@
+{
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
+ "evidence": [
+ {
+ "name": "Protocol Source & Audits",
+ "urls": [
+ {
+ "name": "etherfi-protocol/smart-contracts",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ethfi/verifiability/verifiability__token-source.json b/content/evaluations/ethfi/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..04155b4
--- /dev/null
+++ b/content/evaluations/ethfi/verifiability/verifiability__token-source.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
+ "evidence": [
+ {
+ "name": "Token Verification",
+ "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
+ "urls": [
+ {
+ "name": "Etherscan Verified Source",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/distribution/_metric.json b/content/evaluations/ldo/distribution/_metric.json
new file mode 100644
index 0000000..01ef2fb
--- /dev/null
+++ b/content/evaluations/ldo/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/ldo/distribution/distribution__concentration.json b/content/evaluations/ldo/distribution/distribution__concentration.json
new file mode 100644
index 0000000..f0ea33e
--- /dev/null
+++ b/content/evaluations/ldo/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
+ "evidence": []
+}
diff --git a/content/evaluations/ldo/distribution/distribution__supply-schedule.json b/content/evaluations/ldo/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..b781f77
--- /dev/null
+++ b/content/evaluations/ldo/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
+ "evidence": []
+}
diff --git a/content/evaluations/ldo/offchain/_metric.json b/content/evaluations/ldo/offchain/_metric.json
new file mode 100644
index 0000000..4da96c8
--- /dev/null
+++ b/content/evaluations/ldo/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/ldo/offchain/offchain__distribution.json b/content/evaluations/ldo/offchain/offchain__distribution.json
new file mode 100644
index 0000000..0ba589a
--- /dev/null
+++ b/content/evaluations/ldo/offchain/offchain__distribution.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/offchain/offchain__licensing.json b/content/evaluations/ldo/offchain/offchain__licensing.json
new file mode 100644
index 0000000..0ba589a
--- /dev/null
+++ b/content/evaluations/ldo/offchain/offchain__licensing.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/offchain/offchain__trademark.json b/content/evaluations/ldo/offchain/offchain__trademark.json
new file mode 100644
index 0000000..ebae64a
--- /dev/null
+++ b/content/evaluations/ldo/offchain/offchain__trademark.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UK IPO Trademark Journal",
+ "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Logo",
+ "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/_metric.json b/content/evaluations/ldo/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..5a79c2d
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..30793e1
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
+ "evidence": [
+ {
+ "name": "Guardian Role",
+ "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
+ "urls": [
+ {
+ "name": "DepositSecurityModule",
+ "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Lido.sol deposit logic",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
+ "type": "github"
+ },
+ {
+ "name": "Guardians use automated software",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Guardian Accountability",
+ "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
+ "urls": [
+ {
+ "name": "Guardian Committee Membership",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
+ "type": "docs"
+ },
+ {
+ "name": "Guardians cannot control stake allocation",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..adf749d
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
+ "evidence": [
+ {
+ "name": "Burn Capability",
+ "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
+ "urls": [
+ {
+ "name": "MiniMeToken.destroyTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
+ "type": "github"
+ },
+ {
+ "name": "Aragon ACL",
+ "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Transfer Control",
+ "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
+ "urls": [
+ {
+ "name": "MiniMeToken.enableTransfers",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..3b27084
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,64 @@
+{
+ "status": "positive",
+ "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
+ "evidence": [
+ {
+ "name": "Governance 1A",
+ "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ },
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Governance 1B",
+ "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Easy Track",
+ "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
+ "urls": [
+ {
+ "name": "Easy Track Interface",
+ "url": "https://easytrack.lido.fi/",
+ "type": "docs"
+ },
+ {
+ "name": "Easy Track Guide",
+ "url": "https://docs.lido.fi/guides/easy-track-guide",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..a3a5da8
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,48 @@
+{
+ "status": "positive",
+ "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Upgradeable Contracts",
+ "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-upgradeable Contracts",
+ "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
+ "urls": [
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..deeabc7
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,50 @@
+{
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
+ "evidence": [
+ {
+ "name": "Voting",
+ "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent",
+ "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "TokenManager",
+ "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "StakingRouter",
+ "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..a476ae1
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
+ "evidence": [
+ {
+ "name": "Minting Path",
+ "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
+ "urls": [
+ {
+ "name": "MiniMeToken.generateTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..2f65c1e
--- /dev/null
+++ b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
+ "evidence": [
+ {
+ "name": "Token Contract",
+ "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
+ "urls": [
+ {
+ "name": "LDO Token",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Controller Upgrade Path",
+ "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/val-accrual/_metric.json b/content/evaluations/ldo/val-accrual/_metric.json
new file mode 100644
index 0000000..15c6eb7
--- /dev/null
+++ b/content/evaluations/ldo/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__active.json b/content/evaluations/ldo/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..558e4a9
--- /dev/null
+++ b/content/evaluations/ldo/val-accrual/val-accrual__active.json
@@ -0,0 +1,46 @@
+{
+ "status": "positive",
+ "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
+ "evidence": [
+ {
+ "name": "Treasury Fee Flow",
+ "urls": [
+ {
+ "name": "StakingRouter (read contract)",
+ "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
+ "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Buyback Program",
+ "urls": [
+ {
+ "name": "stETH/LDO Buyback Proposal",
+ "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
+ "type": "docs"
+ },
+ {
+ "name": "stETH/LDO Buyback Snapshot Vote",
+ "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
+ "type": "vote"
+ },
+ {
+ "name": "NEST",
+ "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
+ "type": "docs"
+ },
+ {
+ "name": "Liquid buybacks research",
+ "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json b/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..0b6d587
--- /dev/null
+++ b/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "StakingRouter add/update",
+ "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__offchain.json b/content/evaluations/ldo/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..57a1dff
--- /dev/null
+++ b/content/evaluations/ldo/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
+ "evidence": []
+}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__treasury.json b/content/evaluations/ldo/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..f1662c6
--- /dev/null
+++ b/content/evaluations/ldo/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,28 @@
+{
+ "status": "positive",
+ "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "Agent (Treasury)",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/verifiability/_metric.json b/content/evaluations/ldo/verifiability/_metric.json
new file mode 100644
index 0000000..3fa336c
--- /dev/null
+++ b/content/evaluations/ldo/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/ldo/verifiability/verifiability__protocol-source.json b/content/evaluations/ldo/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..cefc201
--- /dev/null
+++ b/content/evaluations/ldo/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Lido core protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Core Contracts (GitHub)",
+ "url": "https://github.com/lidofinance/core",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ldo/verifiability/verifiability__token-source.json b/content/evaluations/ldo/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..713a79f
--- /dev/null
+++ b/content/evaluations/ldo/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LDO Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ },
+ {
+ "name": "MiniMeToken Source (GitHub)",
+ "url": "https://github.com/aragon/minime",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/distribution/_metric.json b/content/evaluations/lqty/distribution/_metric.json
new file mode 100644
index 0000000..18de867
--- /dev/null
+++ b/content/evaluations/lqty/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/lqty/distribution/distribution__concentration.json b/content/evaluations/lqty/distribution/distribution__concentration.json
new file mode 100644
index 0000000..110aef5
--- /dev/null
+++ b/content/evaluations/lqty/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+}
diff --git a/content/evaluations/lqty/distribution/distribution__supply-schedule.json b/content/evaluations/lqty/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..836aa8d
--- /dev/null
+++ b/content/evaluations/lqty/distribution/distribution__supply-schedule.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LockupContractFactory (Etherscan)",
+ "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
+ "type": "explorer"
+ },
+ {
+ "name": "CommunityIssuance (Etherscan)",
+ "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/offchain/_metric.json b/content/evaluations/lqty/offchain/_metric.json
new file mode 100644
index 0000000..df30ae9
--- /dev/null
+++ b/content/evaluations/lqty/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/lqty/offchain/offchain__distribution.json b/content/evaluations/lqty/offchain/offchain__distribution.json
new file mode 100644
index 0000000..cad5d6b
--- /dev/null
+++ b/content/evaluations/lqty/offchain/offchain__distribution.json
@@ -0,0 +1,25 @@
+{
+ "status": "partial",
+ "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity Runs on Decentralized Frontends - Official Blog",
+ "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
+ "type": "website"
+ },
+ {
+ "name": "Frontend Operators Page",
+ "url": "https://www.liquity.org/frontend-operators",
+ "type": "website"
+ },
+ {
+ "name": "Liquity Launch Details (AG does not run frontend)",
+ "url": "https://www.liquity.org/blog/liquity-launch-details",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/offchain/offchain__licensing.json b/content/evaluations/lqty/offchain/offchain__licensing.json
new file mode 100644
index 0000000..782d787
--- /dev/null
+++ b/content/evaluations/lqty/offchain/offchain__licensing.json
@@ -0,0 +1,25 @@
+{
+ "status": "fail",
+ "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Licensing Liquity V2 - Official Blog",
+ "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
+ "type": "website"
+ },
+ {
+ "name": "Liquity V2 Core LICENSE File (GitHub)",
+ "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
+ "type": "github"
+ },
+ {
+ "name": "What's New in Liquity V2 - Bankless",
+ "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/offchain/offchain__trademark.json b/content/evaluations/lqty/offchain/offchain__trademark.json
new file mode 100644
index 0000000..c87d208
--- /dev/null
+++ b/content/evaluations/lqty/offchain/offchain__trademark.json
@@ -0,0 +1,25 @@
+{
+ "status": "fail",
+ "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity AG - Crunchbase Company Profile",
+ "url": "https://www.crunchbase.com/organization/liquity-1d3e",
+ "type": "website"
+ },
+ {
+ "name": "Liquity - Tracxn Company Profile",
+ "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
+ "type": "website"
+ },
+ {
+ "name": "Team Page - Liquity.org",
+ "url": "https://www.liquity.org/team",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/_metric.json b/content/evaluations/lqty/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..1893248
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..8bca964
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,16 @@
+{
+ "name": "Access Gating",
+ "status": "positive",
+ "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..f76566d
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY token's implementation code",
+ "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..ff7b2b4
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..c6e33ce
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..02906f9
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..eb35281
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..9495e41
--- /dev/null
+++ b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token Source",
+ "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/val-accrual/_metric.json b/content/evaluations/lqty/val-accrual/_metric.json
new file mode 100644
index 0000000..9ad32dc
--- /dev/null
+++ b/content/evaluations/lqty/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__active.json b/content/evaluations/lqty/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..f67d587
--- /dev/null
+++ b/content/evaluations/lqty/val-accrual/val-accrual__active.json
@@ -0,0 +1,40 @@
+{
+ "status": "positive",
+ "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
+ "type": "github"
+ },
+ {
+ "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
+ "type": "github"
+ },
+ {
+ "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
+ "url": "https://docs.liquity.org/v2-faq/lqty-staking",
+ "type": "docs"
+ },
+ {
+ "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json b/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..c9c1666
--- /dev/null
+++ b/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__offchain.json b/content/evaluations/lqty/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..54f5685
--- /dev/null
+++ b/content/evaluations/lqty/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__treasury.json b/content/evaluations/lqty/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..40dc2ab
--- /dev/null
+++ b/content/evaluations/lqty/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Docs",
+ "url": "https://www.liquity.org/blog/liquity-v2-is-live",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/verifiability/_metric.json b/content/evaluations/lqty/verifiability/_metric.json
new file mode 100644
index 0000000..53b7a50
--- /dev/null
+++ b/content/evaluations/lqty/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/lqty/verifiability/verifiability__protocol-source.json b/content/evaluations/lqty/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..0170fd6
--- /dev/null
+++ b/content/evaluations/lqty/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Liquity protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Core (GitHub)",
+ "url": "https://github.com/liquity/bold",
+ "type": "github"
+ },
+ {
+ "name": "Liquity V2 Governance (GitHub)",
+ "url": "https://github.com/liquity/V2-gov",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/lqty/verifiability/verifiability__token-source.json b/content/evaluations/lqty/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..c4daa88
--- /dev/null
+++ b/content/evaluations/lqty/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
+ "type": "explorer"
+ },
+ {
+ "name": "LQTYToken.sol Source (GitHub)",
+ "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/distribution/_metric.json b/content/evaluations/ondo/distribution/_metric.json
new file mode 100644
index 0000000..6ff8f37
--- /dev/null
+++ b/content/evaluations/ondo/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/ondo/distribution/distribution__concentration.json b/content/evaluations/ondo/distribution/distribution__concentration.json
new file mode 100644
index 0000000..b811b98
--- /dev/null
+++ b/content/evaluations/ondo/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "at_risk",
+ "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
+ "evidence": [
+ {
+ "name": "Team Holdings",
+ "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
+ "urls": [
+ {
+ "name": "Team Multisig holdings",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/distribution/distribution__supply-schedule.json b/content/evaluations/ondo/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..dc07df0
--- /dev/null
+++ b/content/evaluations/ondo/distribution/distribution__supply-schedule.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
+ "evidence": [
+ {
+ "name": "Documented Schedule",
+ "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
+ "urls": [
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ },
+ {
+ "name": "CoinList - ONDO Community Sale",
+ "url": "https://coinlist.co/ondo",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/offchain/_metric.json b/content/evaluations/ondo/offchain/_metric.json
new file mode 100644
index 0000000..cdc655c
--- /dev/null
+++ b/content/evaluations/ondo/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/ondo/offchain/offchain__distribution.json b/content/evaluations/ondo/offchain/offchain__distribution.json
new file mode 100644
index 0000000..e5575dc
--- /dev/null
+++ b/content/evaluations/ondo/offchain/offchain__distribution.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Interface Services",
+ "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/offchain/offchain__licensing.json b/content/evaluations/ondo/offchain/offchain__licensing.json
new file mode 100644
index 0000000..f3632d4
--- /dev/null
+++ b/content/evaluations/ondo/offchain/offchain__licensing.json
@@ -0,0 +1,27 @@
+{
+ "status": "unevaluated",
+ "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
+ "evidence": [
+ {
+ "name": "BUSL-1.1 Source Headers",
+ "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
+ "urls": [
+ {
+ "name": "USDY source SPDX header",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "rOUSG source SPDX header",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "BUSL-1.1 license text",
+ "url": "https://spdx.org/licenses/BUSL-1.1.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/offchain/offchain__trademark.json b/content/evaluations/ondo/offchain/offchain__trademark.json
new file mode 100644
index 0000000..d53d771
--- /dev/null
+++ b/content/evaluations/ondo/offchain/offchain__trademark.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Proprietary Rights",
+ "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/_metric.json b/content/evaluations/ondo/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..c2dfc4d
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..3a6f103
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
+ "evidence": [
+ {
+ "name": "OUSG Transfer Restrictions",
+ "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
+ "urls": [
+ {
+ "name": "OUSG Contract (KYC enforcement)",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG KYC check (source)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
+ "type": "github"
+ },
+ {
+ "name": "KYCRegistry",
+ "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "USDY Transfer Restrictions",
+ "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
+ "urls": [
+ {
+ "name": "USDY restrictions (source)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
+ "type": "github"
+ },
+ {
+ "name": "USDY Contract",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..a5dc7f1
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
+ "evidence": [
+ {
+ "name": "No Censorship Capability",
+ "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Source code (ondo-v1)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..4c5b928
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,42 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
+ "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (OUSG admin)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin owner",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..1cee348
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,63 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY (Team-Controlled)",
+ "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
+ "urls": [
+ {
+ "name": "OUSG Proxy",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Proxy",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Polygon OUSG ProxyAdmin Owner",
+ "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
+ "type": "explorer"
+ },
+ {
+ "name": "Mantle USDY ProxyAdmin Owner",
+ "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum USDY ProxyAdmin Owner",
+ "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Team-Controlled via TimelockController)",
+ "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
+ "urls": [
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..8e32210
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,94 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
+ "evidence": [
+ {
+ "name": "Team-Controlled Roles (ONDO Token)",
+ "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (OUSG/USDY)",
+ "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "rOUSG",
+ "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "rUSDY",
+ "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (Global Markets)",
+ "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ },
+ {
+ "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
+ "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
+ "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (EOA)",
+ "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
+ "type": "explorer"
+ },
+ {
+ "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
+ "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..fb8a3ba
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,38 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
+ "evidence": [
+ {
+ "name": "Current Supply",
+ "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
+ "urls": [
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Mint Function Exists",
+ "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "ONDO Token (verified source)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (MINTER_ROLE holder)",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..578d308
--- /dev/null
+++ b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
+ "evidence": [
+ {
+ "name": "ONDO Token Roles",
+ "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Contract Source Note",
+ "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
+ "urls": [
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/val-accrual/_metric.json b/content/evaluations/ondo/val-accrual/_metric.json
new file mode 100644
index 0000000..f11d02f
--- /dev/null
+++ b/content/evaluations/ondo/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__active.json b/content/evaluations/ondo/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..7939a86
--- /dev/null
+++ b/content/evaluations/ondo/val-accrual/val-accrual__active.json
@@ -0,0 +1,32 @@
+{
+ "status": "at_risk",
+ "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
+ "evidence": [
+ {
+ "name": "Product Economics vs ONDO Holder Accrual",
+ "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json b/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..ee2c0ab
--- /dev/null
+++ b/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,48 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY Price Oracles (Company-Controlled)",
+ "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
+ "urls": [
+ {
+ "name": "OUSG Oracle",
+ "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Oracle",
+ "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
+ "type": "explorer"
+ },
+ {
+ "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
+ "type": "github"
+ },
+ {
+ "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Company-Controlled via TimelockController)",
+ "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__offchain.json b/content/evaluations/ondo/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..1c5bd2f
--- /dev/null
+++ b/content/evaluations/ondo/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,51 @@
+{
+ "status": "warning",
+ "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": [
+ {
+ "name": "Ondo Product Economics",
+ "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Issuer / Ondo Finance Relationship",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets Revenue",
+ "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
+ "urls": [
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__treasury.json b/content/evaluations/ondo/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..4157d3a
--- /dev/null
+++ b/content/evaluations/ondo/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,17 @@
+{
+ "status": "at_risk",
+ "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
+ "evidence": [
+ {
+ "name": "No Treasury Identified",
+ "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
+ "urls": [
+ {
+ "name": "Ondo DAO Proposals",
+ "url": "https://www.tally.xyz/gov/ondo-dao",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/verifiability/_metric.json b/content/evaluations/ondo/verifiability/_metric.json
new file mode 100644
index 0000000..9d49936
--- /dev/null
+++ b/content/evaluations/ondo/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/ondo/verifiability/verifiability__protocol-source.json b/content/evaluations/ondo/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..dc042a9
--- /dev/null
+++ b/content/evaluations/ondo/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,51 @@
+{
+ "status": "positive",
+ "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY GitHub",
+ "url": "https://github.com/ondoprotocol/usdy",
+ "type": "github"
+ },
+ {
+ "name": "Audit code (Code4rena)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDonManager",
+ "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/ondo/verifiability/verifiability__token-source.json b/content/evaluations/ondo/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..69b23f7
--- /dev/null
+++ b/content/evaluations/ondo/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ONDO Token (Etherscan verified)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/distribution/_metric.json b/content/evaluations/sky/distribution/_metric.json
new file mode 100644
index 0000000..d46c247
--- /dev/null
+++ b/content/evaluations/sky/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not been able to verify the concentration of holdings.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/sky/distribution/distribution__concentration.json b/content/evaluations/sky/distribution/distribution__concentration.json
new file mode 100644
index 0000000..14854bc
--- /dev/null
+++ b/content/evaluations/sky/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify the concentration of holdings.",
+ "evidence": []
+}
diff --git a/content/evaluations/sky/distribution/distribution__supply-schedule.json b/content/evaluations/sky/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..ea1ed76
--- /dev/null
+++ b/content/evaluations/sky/distribution/distribution__supply-schedule.json
@@ -0,0 +1,17 @@
+{
+ "status": "unevaluated",
+ "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
+ "evidence": [
+ {
+ "name": "Vesting Contracts",
+ "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
+ "urls": [
+ {
+ "name": "Vest Contract",
+ "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/offchain/_metric.json b/content/evaluations/sky/offchain/_metric.json
new file mode 100644
index 0000000..5919811
--- /dev/null
+++ b/content/evaluations/sky/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/sky/offchain/offchain__distribution.json b/content/evaluations/sky/offchain/offchain__distribution.json
new file mode 100644
index 0000000..ab1dfb9
--- /dev/null
+++ b/content/evaluations/sky/offchain/offchain__distribution.json
@@ -0,0 +1,17 @@
+{
+ "status": "unevaluated",
+ "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
+ "evidence": [
+ {
+ "name": "Open Source Frontends",
+ "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
+ "urls": [
+ {
+ "name": "Governance Portal Source",
+ "url": "https://github.com/sky-ecosystem/governance-portal-v2",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/offchain/offchain__licensing.json b/content/evaluations/sky/offchain/offchain__licensing.json
new file mode 100644
index 0000000..aa47403
--- /dev/null
+++ b/content/evaluations/sky/offchain/offchain__licensing.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
+ "evidence": [
+ {
+ "name": "AGPL-3.0 License",
+ "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
+ "urls": [
+ {
+ "name": "License File",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/offchain/offchain__trademark.json b/content/evaluations/sky/offchain/offchain__trademark.json
new file mode 100644
index 0000000..7dda59a
--- /dev/null
+++ b/content/evaluations/sky/offchain/offchain__trademark.json
@@ -0,0 +1,28 @@
+{
+ "status": "warning",
+ "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
+ "evidence": [
+ {
+ "name": "Skybase International Terms of Use",
+ "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "DAI Foundation",
+ "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
+ "urls": [
+ {
+ "name": "Foundation Website",
+ "url": "https://daifoundation.org",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/_metric.json b/content/evaluations/sky/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..17b64c3
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..2a8eb2b
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
+ "evidence": [
+ {
+ "name": "Emergency Shutdown",
+ "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
+ "urls": [
+ {
+ "name": "ESM source code",
+ "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
+ "type": "github"
+ },
+ {
+ "name": "ESM contract on Etherscan",
+ "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "No Arbitrary Pause",
+ "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
+ "urls": []
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5515ba9
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
+ "evidence": [
+ {
+ "name": "No Censorship Functions",
+ "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
+ "urls": [
+ {
+ "name": "Transfer Functions (L96-135)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..210d15f
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
+ "evidence": [
+ {
+ "name": "Governance Workflow",
+ "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
+ "urls": [
+ {
+ "name": "Voting Contract",
+ "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "plot() delay enforcement (L111-116)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Timelock Contract",
+ "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
+ "urls": [
+ {
+ "name": "Pause Proxy (Etherscan)",
+ "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "exec() function (L124-136)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..b5ad61d
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
+ "evidence": [
+ {
+ "name": "Immutable Core",
+ "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
+ "urls": [
+ {
+ "name": "Vat source code",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
+ "type": "github"
+ },
+ {
+ "name": "SKY token source code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Stablecoins",
+ "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
+ "urls": [
+ {
+ "name": "USDS upgrade authorization",
+ "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
+ "type": "github"
+ },
+ {
+ "name": "sUSDS source code",
+ "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..b56bd54
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
+ "evidence": [
+ {
+ "name": "Core Contracts Controlled by Governance",
+ "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
+ "urls": [
+ {
+ "name": "Vat wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Vow wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "SKY wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Controls",
+ "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
+ "urls": [
+ {
+ "name": "Mom authority pattern (source)",
+ "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
+ "type": "github"
+ },
+ {
+ "name": "OSM_MOM — verify authority()",
+ "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..2655fba
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
+ "evidence": [
+ {
+ "name": "Minting Restricted to Governance",
+ "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
+ "urls": [
+ {
+ "name": "mint() function (L146-154)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "MKR Conversion",
+ "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
+ "urls": [
+ {
+ "name": "rate() returns 24000",
+ "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Immutable rate declaration",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..8678d04
--- /dev/null
+++ b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Token",
+ "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
+ "urls": [
+ {
+ "name": "SKY Token Contract",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/val-accrual/_metric.json b/content/evaluations/sky/val-accrual/_metric.json
new file mode 100644
index 0000000..0d3d99d
--- /dev/null
+++ b/content/evaluations/sky/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__active.json b/content/evaluations/sky/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..5595264
--- /dev/null
+++ b/content/evaluations/sky/val-accrual/val-accrual__active.json
@@ -0,0 +1,48 @@
+{
+ "status": "positive",
+ "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
+ "evidence": [
+ {
+ "name": "Smart Burn Engine",
+ "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
+ "urls": [
+ {
+ "name": "Splitter contract",
+ "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper (buyback executor)",
+ "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper source code",
+ "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
+ "type": "github"
+ },
+ {
+ "name": "Smart Burn Engine Dashboard",
+ "url": "https://info.sky.money/smart-burn-engine",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
+ "urls": [
+ {
+ "name": "Stability fee accrual",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
+ "type": "github"
+ },
+ {
+ "name": "Surplus routing to flapper",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__mechanism.json b/content/evaluations/sky/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..bdb8dc4
--- /dev/null
+++ b/content/evaluations/sky/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
+ "evidence": [
+ {
+ "name": "Fee Rate Control",
+ "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
+ "urls": [
+ {
+ "name": "Jug fee configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
+ "type": "github"
+ },
+ {
+ "name": "Jug contract",
+ "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Surplus Buffer Control",
+ "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
+ "urls": [
+ {
+ "name": "Vow hump configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
+ "type": "github"
+ },
+ {
+ "name": "Vow contract — read hump",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__offchain.json b/content/evaluations/sky/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..a541c0a
--- /dev/null
+++ b/content/evaluations/sky/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,20 @@
+{
+ "status": "unevaluated",
+ "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": [
+ {
+ "name": "Foundation Independence",
+ "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
+ "urls": [
+ {
+ "name": "Foundation Mandate",
+ "url": "https://daifoundation.org/mandate",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__treasury.json b/content/evaluations/sky/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..832c737
--- /dev/null
+++ b/content/evaluations/sky/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
+ "evidence": [
+ {
+ "name": "Onchain Treasury",
+ "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/verifiability/_metric.json b/content/evaluations/sky/verifiability/_metric.json
new file mode 100644
index 0000000..7655c73
--- /dev/null
+++ b/content/evaluations/sky/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/sky/verifiability/verifiability__protocol-source.json b/content/evaluations/sky/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..648a473
--- /dev/null
+++ b/content/evaluations/sky/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
+ "evidence": [
+ {
+ "name": "Open Source Repositories",
+ "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
+ "urls": [
+ {
+ "name": "Core Protocol",
+ "url": "https://github.com/sky-ecosystem/dss",
+ "type": "github"
+ },
+ {
+ "name": "Contract Registry",
+ "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/sky/verifiability/verifiability__token-source.json b/content/evaluations/sky/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..0d71b8d
--- /dev/null
+++ b/content/evaluations/sky/verifiability/verifiability__token-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
+ "evidence": [
+ {
+ "name": "Verified Source",
+ "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
+ "urls": [
+ {
+ "name": "Source Code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ },
+ {
+ "name": "Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/distribution/_metric.json b/content/evaluations/uni/distribution/_metric.json
new file mode 100644
index 0000000..69c4a54
--- /dev/null
+++ b/content/evaluations/uni/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/uni/distribution/distribution__concentration.json b/content/evaluations/uni/distribution/distribution__concentration.json
new file mode 100644
index 0000000..110aef5
--- /dev/null
+++ b/content/evaluations/uni/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+}
diff --git a/content/evaluations/uni/distribution/distribution__supply-schedule.json b/content/evaluations/uni/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..aa8e115
--- /dev/null
+++ b/content/evaluations/uni/distribution/distribution__supply-schedule.json
@@ -0,0 +1,37 @@
+{
+ "status": "positive",
+ "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
+ "evidence": [
+ {
+ "name": "TreasuryVester Contracts",
+ "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
+ "urls": [
+ {
+ "name": "TreasuryVester Code",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
+ "type": "github"
+ },
+ {
+ "name": "TreasuryVester 1",
+ "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 2",
+ "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 3",
+ "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 4",
+ "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/offchain/_metric.json b/content/evaluations/uni/offchain/_metric.json
new file mode 100644
index 0000000..32abe85
--- /dev/null
+++ b/content/evaluations/uni/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/uni/offchain/offchain__distribution.json b/content/evaluations/uni/offchain/offchain__distribution.json
new file mode 100644
index 0000000..83546db
--- /dev/null
+++ b/content/evaluations/uni/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Terms of Service",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/offchain/offchain__licensing.json b/content/evaluations/uni/offchain/offchain__licensing.json
new file mode 100644
index 0000000..20a3717
--- /dev/null
+++ b/content/evaluations/uni/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "warning",
+ "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
+ "evidence": []
+}
diff --git a/content/evaluations/uni/offchain/offchain__trademark.json b/content/evaluations/uni/offchain/offchain__trademark.json
new file mode 100644
index 0000000..def920e
--- /dev/null
+++ b/content/evaluations/uni/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Trademark Guidelines",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/_metric.json b/content/evaluations/uni/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..a1bf5bc
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..81720c4
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
+ "evidence": []
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5f6c7c5
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..4ba972f
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..d3f6dd6
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
+ "evidence": [
+ {
+ "name": "Non-upgradeable Protocol Contracts",
+ "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
+ "urls": [
+ {
+ "name": "V2 Factory Create2",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
+ "type": "github"
+ },
+ {
+ "name": "V3 Pool Protection",
+ "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
+ "type": "github"
+ },
+ {
+ "name": "V4 PoolManager: Singleton",
+ "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Governance Contract",
+ "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..981f1bb
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,55 @@
+{
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
+ "evidence": [
+ {
+ "name": "V2 Factory",
+ "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
+ "urls": [
+ {
+ "name": "V2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Factory",
+ "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
+ "urls": [
+ {
+ "name": "V3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V4 PoolManager",
+ "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
+ "urls": [
+ {
+ "name": "V4PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "UNI Token",
+ "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
+ "urls": [
+ {
+ "name": "UNI Token",
+ "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock (deployed minter)",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..2b18768
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
+ "evidence": [
+ {
+ "name": "Inflation Cap",
+ "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
+ "urls": [
+ {
+ "name": "Mint once per year logic",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
+ "type": "github"
+ },
+ {
+ "name": "2% mint cap",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Control",
+ "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..e50c26f
--- /dev/null
+++ b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol Source",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ },
+ {
+ "name": "Etherscan",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/val-accrual/_metric.json b/content/evaluations/uni/val-accrual/_metric.json
new file mode 100644
index 0000000..3c8d23e
--- /dev/null
+++ b/content/evaluations/uni/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__active.json b/content/evaluations/uni/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..9360e90
--- /dev/null
+++ b/content/evaluations/uni/val-accrual/val-accrual__active.json
@@ -0,0 +1,65 @@
+{
+ "status": "positive",
+ "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
+ "evidence": [
+ {
+ "name": "V2 Fees",
+ "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
+ "urls": [
+ {
+ "name": "UniswapV2Pool: feeTo",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Pool: Fee Destination",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fees",
+ "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
+ "urls": [
+ {
+ "name": "V3FeeAdapter",
+ "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: collectProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fees",
+ "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
+ "urls": [
+ {
+ "name": "V4 PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ },
+ {
+ "name": "V4 PoolManager: CollectProtocolFees",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Burn Mechanism",
+ "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
+ "urls": [
+ {
+ "name": "FirePit 4000 UNI Requirement",
+ "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__mechanism.json b/content/evaluations/uni/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..f500fa5
--- /dev/null
+++ b/content/evaluations/uni/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,49 @@
+{
+ "status": "positive",
+ "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
+ "evidence": [
+ {
+ "name": "V2 Fee Control",
+ "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fee Control",
+ "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
+ "urls": [
+ {
+ "name": "UniswapV3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: setFeeProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fee Control",
+ "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
+ "urls": [
+ {
+ "name": "PoolManager(V4): setProtocolFee",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__offchain.json b/content/evaluations/uni/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..8c00c48
--- /dev/null
+++ b/content/evaluations/uni/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,15 @@
+{
+ "status": "unevaluated",
+ "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "DUNI Proposal",
+ "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__treasury.json b/content/evaluations/uni/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..2afc7f0
--- /dev/null
+++ b/content/evaluations/uni/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/verifiability/_metric.json b/content/evaluations/uni/verifiability/_metric.json
new file mode 100644
index 0000000..40ae2ee
--- /dev/null
+++ b/content/evaluations/uni/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/uni/verifiability/verifiability__protocol-source.json b/content/evaluations/uni/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..5d637b5
--- /dev/null
+++ b/content/evaluations/uni/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,30 @@
+{
+ "status": "positive",
+ "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap V2 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v2-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V3 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v3-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V4 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v4-core",
+ "type": "github"
+ },
+ {
+ "name": "UniswapX (GitHub)",
+ "url": "https://github.com/Uniswap/UniswapX",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/uni/verifiability/verifiability__token-source.json b/content/evaluations/uni/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..33eea24
--- /dev/null
+++ b/content/evaluations/uni/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UNI Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Uni.sol Source (GitHub)",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/distribution/_metric.json b/content/evaluations/yb/distribution/_metric.json
new file mode 100644
index 0000000..d1b94bc
--- /dev/null
+++ b/content/evaluations/yb/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/content/evaluations/yb/distribution/distribution__concentration.json b/content/evaluations/yb/distribution/distribution__concentration.json
new file mode 100644
index 0000000..47c4744
--- /dev/null
+++ b/content/evaluations/yb/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
+ "evidence": [
+ {
+ "name": "veYB Supply",
+ "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/distribution/distribution__supply-schedule.json b/content/evaluations/yb/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..9e11843
--- /dev/null
+++ b/content/evaluations/yb/distribution/distribution__supply-schedule.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
+ "urls": [
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/offchain/_metric.json b/content/evaluations/yb/offchain/_metric.json
new file mode 100644
index 0000000..6c4bba4
--- /dev/null
+++ b/content/evaluations/yb/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/content/evaluations/yb/offchain/offchain__distribution.json b/content/evaluations/yb/offchain/offchain__distribution.json
new file mode 100644
index 0000000..d5547e1
--- /dev/null
+++ b/content/evaluations/yb/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YieldBasis Website",
+ "url": "https://yieldbasis.com/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/offchain/offchain__licensing.json b/content/evaluations/yb/offchain/offchain__licensing.json
new file mode 100644
index 0000000..9374e87
--- /dev/null
+++ b/content/evaluations/yb/offchain/offchain__licensing.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
+ "evidence": [
+ {
+ "name": "License Analysis",
+ "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
+ "urls": [
+ {
+ "name": "yb-core contracts directory",
+ "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Curve Licensing Vesting",
+ "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/offchain/offchain__trademark.json b/content/evaluations/yb/offchain/offchain__trademark.json
new file mode 100644
index 0000000..00e0821
--- /dev/null
+++ b/content/evaluations/yb/offchain/offchain__trademark.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify trademark ownership.",
+ "evidence": []
+}
diff --git a/content/evaluations/yb/onchain-ctrl/_metric.json b/content/evaluations/yb/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..03c2d81
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..e2feb0c
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
+ "evidence": [
+ {
+ "name": "Exit Paths",
+ "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
+ "urls": [
+ {
+ "name": "VotingEscrow.withdraw",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor.claim",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..e76cece
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB.vy full source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..1b7a16e
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,32 @@
+{
+ "status": "positive",
+ "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
+ "evidence": [
+ {
+ "name": "Governance System",
+ "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
+ "urls": [
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB (VotingEscrow)",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "TokenVoting Plugin",
+ "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.yieldbasis.com/user/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..e0368ef
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
+ "urls": [
+ {
+ "name": "Factory Contract",
+ "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
+ "type": "explorer"
+ },
+ {
+ "name": "Factory.set_implementations",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
+ "type": "github"
+ },
+ {
+ "name": "MigrationFactoryOwner ADMIN immutable",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..93f7045
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
+ "evidence": [
+ {
+ "name": "DAO-Controlled Contracts",
+ "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
+ "urls": [
+ {
+ "name": "GaugeController",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ },
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "MigrationFactoryOwner",
+ "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "veYB Owner (_yb.eth)",
+ "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "set_transfer_clearance_checker",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..0203010
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
+ "evidence": [
+ {
+ "name": "Emission Mechanism",
+ "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
+ "urls": [
+ {
+ "name": "get_adjustment (minting rate)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
+ "type": "github"
+ },
+ {
+ "name": "YB.emit function",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
+ "type": "github"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..788c4e7
--- /dev/null
+++ b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
+ "evidence": [
+ {
+ "name": "Token Ownership",
+ "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
+ "urls": [
+ {
+ "name": "YB Token Contract",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "renounce_ownership",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/val-accrual/_metric.json b/content/evaluations/yb/val-accrual/_metric.json
new file mode 100644
index 0000000..689d6be
--- /dev/null
+++ b/content/evaluations/yb/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__active.json b/content/evaluations/yb/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..dd9e19d
--- /dev/null
+++ b/content/evaluations/yb/val-accrual/val-accrual__active.json
@@ -0,0 +1,42 @@
+{
+ "status": "positive",
+ "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
+ "evidence": [
+ {
+ "name": "Fee Flow",
+ "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
+ "urls": [
+ {
+ "name": "LT.withdraw_admin_fees",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
+ "type": "github"
+ },
+ {
+ "name": "Factory.fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor Contract",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB Documentation",
+ "url": "https://docs.yieldbasis.com/user/veyb",
+ "type": "docs"
+ },
+ {
+ "name": "Fee Data (ValueVerse)",
+ "url": "https://yb.valueverse.ai",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__mechanism.json b/content/evaluations/yb/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..8b8ce8b
--- /dev/null
+++ b/content/evaluations/yb/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
+ "evidence": [
+ {
+ "name": "Fee Flow Direction",
+ "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
+ "urls": [
+ {
+ "name": "MigrationFactoryOwner.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
+ "type": "github"
+ },
+ {
+ "name": "Factory.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
+ "urls": [
+ {
+ "name": "vote_for_gauge_weights",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
+ "type": "github"
+ },
+ {
+ "name": "GaugeController Contract",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__offchain.json b/content/evaluations/yb/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..084ddf2
--- /dev/null
+++ b/content/evaluations/yb/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__treasury.json b/content/evaluations/yb/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..ed8c75a
--- /dev/null
+++ b/content/evaluations/yb/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,27 @@
+{
+ "status": "at_risk",
+ "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
+ "evidence": [
+ {
+ "name": "Ecosystem Reserve",
+ "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
+ "urls": [
+ {
+ "name": "Ecosystem Reserve",
+ "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
+ "type": "explorer"
+ },
+ {
+ "name": "Ecosystem Reserve Owner (EOA)",
+ "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
+ "type": "explorer"
+ },
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/verifiability/_metric.json b/content/evaluations/yb/verifiability/_metric.json
new file mode 100644
index 0000000..df29e57
--- /dev/null
+++ b/content/evaluations/yb/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/content/evaluations/yb/verifiability/verifiability__protocol-source.json b/content/evaluations/yb/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..57de733
--- /dev/null
+++ b/content/evaluations/yb/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
+ "evidence": [
+ {
+ "name": "Verification and Audits",
+ "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
+ "urls": [
+ {
+ "name": "yb-core GitHub Repository",
+ "url": "https://github.com/yield-basis/yb-core",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/evaluations/yb/verifiability/verifiability__token-source.json b/content/evaluations/yb/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..fe6d309
--- /dev/null
+++ b/content/evaluations/yb/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB Token Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "YB.vy Source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/data/faq.json b/content/faq.json
similarity index 100%
rename from src/data/faq.json
rename to content/faq.json
diff --git a/content/framework/_meta.json b/content/framework/_meta.json
new file mode 100644
index 0000000..2f58a3f
--- /dev/null
+++ b/content/framework/_meta.json
@@ -0,0 +1,10 @@
+{
+ "baseUrl": "https://github.com/aragon/ownership-token-framework/blob/development/README.md",
+ "order": [
+ "onchain-ctrl",
+ "val-accrual",
+ "verifiability",
+ "distribution",
+ "offchain"
+ ]
+}
diff --git a/content/framework/distribution.json b/content/framework/distribution.json
new file mode 100644
index 0000000..52be47f
--- /dev/null
+++ b/content/framework/distribution.json
@@ -0,0 +1,19 @@
+{
+ "id": "distribution",
+ "name": "Metric 4: Token Distribution",
+ "displayName": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "anchor": "#metric-4-token-distribution",
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
+ }
+ ]
+}
diff --git a/content/framework/offchain.json b/content/framework/offchain.json
new file mode 100644
index 0000000..9dc3d8d
--- /dev/null
+++ b/content/framework/offchain.json
@@ -0,0 +1,24 @@
+{
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "displayName": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "anchor": "#offchain-dependencies",
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
+ }
+ ]
+}
diff --git a/content/framework/onchain-ctrl.json b/content/framework/onchain-ctrl.json
new file mode 100644
index 0000000..57f816a
--- /dev/null
+++ b/content/framework/onchain-ctrl.json
@@ -0,0 +1,44 @@
+{
+ "id": "onchain-ctrl",
+ "name": "Metric 1: Onchain Control",
+ "displayName": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "anchor": "#metric-1-onchain-control",
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
+ }
+ ]
+}
diff --git a/content/framework/val-accrual.json b/content/framework/val-accrual.json
new file mode 100644
index 0000000..676fa1a
--- /dev/null
+++ b/content/framework/val-accrual.json
@@ -0,0 +1,29 @@
+{
+ "id": "val-accrual",
+ "name": "Metric 2: Value Accrual",
+ "displayName": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "anchor": "#metric-2-value-accrual",
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
+ }
+ ]
+}
diff --git a/content/framework/verifiability.json b/content/framework/verifiability.json
new file mode 100644
index 0000000..9e0f5b8
--- /dev/null
+++ b/content/framework/verifiability.json
@@ -0,0 +1,19 @@
+{
+ "id": "verifiability",
+ "name": "Metric 3: Verifiability",
+ "displayName": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "anchor": "#metric-3-verifiability",
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
+ }
+ ]
+}
diff --git a/src/data/testimonials.json b/content/testimonials.json
similarity index 100%
rename from src/data/testimonials.json
rename to content/testimonials.json
diff --git a/content/tokens/aave.json b/content/tokens/aave.json
new file mode 100644
index 0000000..96d8e46
--- /dev/null
+++ b/content/tokens/aave.json
@@ -0,0 +1,21 @@
+{
+ "id": "aave",
+ "coingeckoId": "aave",
+ "name": "AAVE",
+ "symbol": "AAVE",
+ "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
+ "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
+ "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aave.com/",
+ "twitter": "https://twitter.com/aave",
+ "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
+ },
+ "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
+}
diff --git a/content/tokens/aero.json b/content/tokens/aero.json
new file mode 100644
index 0000000..fe193fc
--- /dev/null
+++ b/content/tokens/aero.json
@@ -0,0 +1,21 @@
+{
+ "id": "aero",
+ "coingeckoId": "aerodrome-finance",
+ "name": "AERO",
+ "symbol": "AERO",
+ "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
+ "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
+ "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
+ "network": "base",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aerodrome.finance/",
+ "twitter": "https://twitter.com/Aerodrome",
+ "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
+ },
+ "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
+}
diff --git a/content/tokens/crv.json b/content/tokens/crv.json
new file mode 100644
index 0000000..7db7514
--- /dev/null
+++ b/content/tokens/crv.json
@@ -0,0 +1,21 @@
+{
+ "id": "crv",
+ "coingeckoId": "curve-dao-token",
+ "name": "CRV",
+ "symbol": "CRV",
+ "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
+ "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
+ "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://curve.finance/",
+ "twitter": "https://twitter.com/curvefinance",
+ "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
+ },
+ "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
+}
diff --git a/content/tokens/ena.json b/content/tokens/ena.json
new file mode 100644
index 0000000..5b0151f
--- /dev/null
+++ b/content/tokens/ena.json
@@ -0,0 +1,21 @@
+{
+ "id": "ena",
+ "coingeckoId": "ethena",
+ "name": "ENA",
+ "symbol": "ENA",
+ "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
+ "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
+ "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ethena.fi/",
+ "twitter": "https://twitter.com/ethena",
+ "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
+ },
+ "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
+}
diff --git a/content/tokens/ethfi.json b/content/tokens/ethfi.json
new file mode 100644
index 0000000..1e86fa1
--- /dev/null
+++ b/content/tokens/ethfi.json
@@ -0,0 +1,21 @@
+{
+ "id": "ethfi",
+ "coingeckoId": "ether-fi",
+ "name": "ETHFI",
+ "symbol": "ETHFI",
+ "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
+ "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
+ "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ether.fi/",
+ "twitter": "https://twitter.com/ether_fi",
+ "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ },
+ "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
+}
diff --git a/content/tokens/ldo.json b/content/tokens/ldo.json
new file mode 100644
index 0000000..386c487
--- /dev/null
+++ b/content/tokens/ldo.json
@@ -0,0 +1,21 @@
+{
+ "id": "ldo",
+ "coingeckoId": "lido-dao",
+ "name": "LDO",
+ "symbol": "LDO",
+ "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
+ "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
+ "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
+ "network": "ethereum",
+ "lastUpdated": 1777631939,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://lido.fi/",
+ "twitter": "https://twitter.com/lidofinance",
+ "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
+ },
+ "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
+}
diff --git a/content/tokens/lqty.json b/content/tokens/lqty.json
new file mode 100644
index 0000000..406fd2f
--- /dev/null
+++ b/content/tokens/lqty.json
@@ -0,0 +1,21 @@
+{
+ "id": "lqty",
+ "coingeckoId": "liquity",
+ "name": "LQTY",
+ "symbol": "LQTY",
+ "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
+ "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
+ "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
+ "network": "ethereum",
+ "lastUpdated": 1778064256,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://www.liquity.org/",
+ "twitter": "https://twitter.com/LiquityProtocol",
+ "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
+ },
+ "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
+}
diff --git a/content/tokens/ondo.json b/content/tokens/ondo.json
new file mode 100644
index 0000000..fa64d38
--- /dev/null
+++ b/content/tokens/ondo.json
@@ -0,0 +1,21 @@
+{
+ "id": "ondo",
+ "name": "ONDO",
+ "symbol": "ONDO",
+ "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
+ "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
+ "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
+ "network": "ethereum",
+ "lastUpdated": 1778674909,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ondo.finance/",
+ "twitter": "https://twitter.com/OndoFinance",
+ "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
+ },
+ "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
+ "coingeckoId": "ondo-finance"
+}
diff --git a/content/tokens/sky.json b/content/tokens/sky.json
new file mode 100644
index 0000000..bd377b7
--- /dev/null
+++ b/content/tokens/sky.json
@@ -0,0 +1,21 @@
+{
+ "id": "sky",
+ "coingeckoId": "sky",
+ "name": "SKY",
+ "symbol": "SKY",
+ "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
+ "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
+ "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://sky.money/",
+ "twitter": "https://twitter.com/SkyEcosystem",
+ "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
+ },
+ "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
+}
diff --git a/content/tokens/uni.json b/content/tokens/uni.json
new file mode 100644
index 0000000..f3142e2
--- /dev/null
+++ b/content/tokens/uni.json
@@ -0,0 +1,21 @@
+{
+ "id": "uni",
+ "coingeckoId": "uniswap",
+ "name": "UNI",
+ "symbol": "UNI",
+ "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
+ "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
+ "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://uniswap.org/",
+ "twitter": "https://twitter.com/uniswap",
+ "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
+ },
+ "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
+}
diff --git a/content/tokens/yb.json b/content/tokens/yb.json
new file mode 100644
index 0000000..7f9c298
--- /dev/null
+++ b/content/tokens/yb.json
@@ -0,0 +1,21 @@
+{
+ "id": "yb",
+ "coingeckoId": "yield-basis",
+ "name": "YB",
+ "symbol": "YB",
+ "address": "0x01791F726B4103694969820be083196cC7c045fF",
+ "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
+ "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://yieldbasis.com/",
+ "twitter": "https://x.com/yieldbasis",
+ "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
+ },
+ "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
+}
diff --git a/package.json b/package.json
index ab17b46..246590b 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,9 @@
"private": true,
"type": "module",
"scripts": {
- "dev": "node scripts/sync-coingecko-ids.mjs --write && vite dev --port 3000",
- "build": "node scripts/sync-coingecko-ids.mjs --write && vite build",
+ "dev": "node scripts/sync-coingecko-ids.mjs --write && node scripts/compose-data.mjs && vite dev --port 3000",
+ "build": "node scripts/sync-coingecko-ids.mjs --write && node scripts/compose-data.mjs && vite build",
+ "compose": "node scripts/compose-data.mjs",
"preview": "vite preview",
"test": "vitest run",
"format": "biome format",
diff --git a/scripts/compose-data.mjs b/scripts/compose-data.mjs
new file mode 100644
index 0000000..49b22fe
--- /dev/null
+++ b/scripts/compose-data.mjs
@@ -0,0 +1,177 @@
+#!/usr/bin/env node
+/**
+ * Composer: content/ atoms → src/data/generated/ read models.
+ *
+ * Joins research-shaped atoms (registry, framework, evaluations) into
+ * consumer-shaped docs by id:
+ * - criterion name/about come from framework (atom `name` overrides)
+ * - metric display name + about come from framework
+ * - scores and status counts are computed here (compose time), not at render
+ *
+ * Replaces the runtime framework-merge formerly in src/lib/metrics-data.ts.
+ * The scoring logic mirrors the pure functions in src/lib/scoring.ts and is
+ * pinned to them by the golden round-trip tests.
+ *
+ * Exports composeAll() for tests; run directly to write src/data/generated/.
+ */
+import {
+ mkdirSync,
+ readdirSync,
+ readFileSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs"
+import { dirname, join } from "node:path"
+import { fileURLToPath } from "node:url"
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const contentDir = join(root, "content")
+const generatedDir = join(root, "src", "data", "generated")
+
+const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
+
+const SCORED_STATUSES = new Set(["positive", "warning", "at_risk"])
+
+function getMetricScore(metric) {
+ const reference = metric.tags?.includes("Reference") ?? false
+ const evaluatedCriteria = metric.criteria.filter((c) =>
+ SCORED_STATUSES.has(c.status)
+ )
+ const total = evaluatedCriteria.length
+ const passing = evaluatedCriteria.filter(
+ (c) => c.status === "positive"
+ ).length
+ const evaluated = reference ? false : total > 0
+ const percentage = total > 0 ? (passing / total) * 100 : 0
+
+ return {
+ metricId: metric.id,
+ metricName: metric.name,
+ passing,
+ total,
+ percentage,
+ evaluated,
+ reference,
+ }
+}
+
+function getTokenScore(tokenId, metrics) {
+ const metricScores = metrics.map(getMetricScore)
+ const scoredMetrics = metricScores.filter((m) => m.evaluated && !m.reference)
+ const passing = scoredMetrics.reduce((sum, m) => sum + m.passing, 0)
+ const total = scoredMetrics.reduce((sum, m) => sum + m.total, 0)
+ const percentage = total > 0 ? (passing / total) * 100 : 0
+
+ return { tokenId, passing, total, percentage, metrics: metricScores }
+}
+
+export function composeAll(dir = contentDir) {
+ const meta = readJson(join(dir, "framework", "_meta.json"))
+ const framework = meta.order.map((id) =>
+ readJson(join(dir, "framework", `${id}.json`))
+ )
+ const criterionDefs = new Map(
+ framework.flatMap((m) => m.criteria.map((c) => [c.id, c]))
+ )
+
+ const tokenIds = readdirSync(join(dir, "tokens"))
+ .filter((f) => f.endsWith(".json"))
+ .map((f) => f.replace(/\.json$/, ""))
+ .sort()
+
+ const tokenAtoms = new Map(
+ tokenIds.map((id) => [id, readJson(join(dir, "tokens", `${id}.json`))])
+ )
+
+ const tokenDocs = []
+ for (const tokenId of tokenIds) {
+ const metrics = []
+ for (const fm of framework) {
+ const metricDir = join(dir, "evaluations", tokenId, fm.id)
+ const editorial = readJson(join(metricDir, "_metric.json"))
+ const criteria = fm.criteria.map((fc) => {
+ const atom = readJson(join(metricDir, `${fc.id}.json`))
+ const composed = {
+ id: fc.id,
+ name: atom.name ?? fc.name,
+ about: fc.about,
+ status: atom.status,
+ notes: atom.notes,
+ }
+ if ("tags" in atom) composed.tags = atom.tags
+ if ("evidence" in atom) composed.evidence = atom.evidence
+ return composed
+ })
+ metrics.push({
+ id: fm.id,
+ name: fm.displayName,
+ about: fm.about,
+ summary: editorial.summary,
+ tags: editorial.tags,
+ criteria,
+ })
+ }
+
+ const allCriteria = metrics.flatMap((m) => m.criteria)
+ const countBy = (status) =>
+ allCriteria.filter((c) => c.status === status).length
+ const score = getTokenScore(tokenId, metrics)
+
+ tokenDocs.push({
+ ...tokenAtoms.get(tokenId),
+ positive: countBy("positive"),
+ neutral: countBy("warning"),
+ atRisk: countBy("at_risk"),
+ evidenceEntries: allCriteria.flatMap((c) => c.evidence ?? []).length,
+ metrics,
+ score,
+ })
+ }
+
+ const index = {
+ tokens: tokenDocs.map(({ metrics: _m, score, ...row }) => ({
+ ...row,
+ score: {
+ passing: score.passing,
+ total: score.total,
+ percentage: score.percentage,
+ },
+ })),
+ }
+
+ const frameworkDoc = { baseUrl: meta.baseUrl, metrics: framework }
+
+ return {
+ index,
+ tokenDocs,
+ frameworkDoc,
+ faq: readJson(join(dir, "faq.json")),
+ testimonials: readJson(join(dir, "testimonials.json")),
+ }
+}
+
+function main() {
+ const { index, tokenDocs, frameworkDoc, faq, testimonials } = composeAll()
+
+ rmSync(generatedDir, { recursive: true, force: true })
+ const writeJson = (p, data) => {
+ mkdirSync(dirname(p), { recursive: true })
+ writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
+ }
+
+ writeJson(join(generatedDir, "index.json"), index)
+ for (const doc of tokenDocs) {
+ writeJson(join(generatedDir, "tokens", `${doc.id}.json`), doc)
+ }
+ writeJson(join(generatedDir, "framework.json"), frameworkDoc)
+ writeJson(join(generatedDir, "faq.json"), faq)
+ writeJson(join(generatedDir, "testimonials.json"), testimonials)
+
+ console.log(
+ `composed: index (${index.tokens.length} rows), ${tokenDocs.length} token docs, framework, faq, testimonials`
+ )
+}
+
+if (process.argv[1] === fileURLToPath(import.meta.url)) {
+ main()
+}
diff --git a/scripts/get-changed-token-ids.mjs b/scripts/get-changed-token-ids.mjs
index 5a087af..aa6ddcc 100644
--- a/scripts/get-changed-token-ids.mjs
+++ b/scripts/get-changed-token-ids.mjs
@@ -1,8 +1,15 @@
-import { readFile } from "node:fs/promises"
+/**
+ * Emit a comma-separated list of token ids whose content changed between two
+ * git refs. A token counts as changed when its registry atom
+ * (content/tokens/.json) or any of its evaluation atoms
+ * (content/evaluations//**) differ.
+ *
+ * Usage: node scripts/get-changed-token-ids.mjs --before --after
+ * With no usable --before (e.g. zero sha on first push), all token ids are
+ * reported.
+ */
import { execSync } from "node:child_process"
-
-const TOKENS_PATH = "src/data/tokens.json"
-const METRICS_PATH = "src/data/metrics.json"
+import { readdir } from "node:fs/promises"
function parseArgs(argv) {
const beforeIndex = argv.indexOf("--before")
@@ -13,50 +20,19 @@ function parseArgs(argv) {
}
}
-function stableStringify(value) {
- if (value === null || value === undefined) {
- return "null"
- }
- if (Array.isArray(value)) {
- return `[${value.map(stableStringify).join(",")}]`
- }
- if (typeof value === "object") {
- const keys = Object.keys(value).sort()
- return `{${keys
- .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`)
- .join(",")}}`
- }
- return JSON.stringify(value)
-}
-
-function readJsonFile(path) {
- return readFile(path, "utf-8").then((data) => JSON.parse(data))
+function tokenIdFromPath(filePath) {
+ const registry = filePath.match(/^content\/tokens\/([^/]+)\.json$/)
+ if (registry) return registry[1]
+ const evaluation = filePath.match(/^content\/evaluations\/([^/]+)\//)
+ if (evaluation) return evaluation[1]
+ return null
}
-function readJsonFromGit(before, path) {
- try {
- const data = execSync(`git show ${before}:${path}`, {
- encoding: "utf-8",
- stdio: ["ignore", "pipe", "ignore"],
- })
- return JSON.parse(data)
- } catch (error) {
- return null
- }
-}
-
-function collectTokenMap(payload) {
- if (!payload?.tokens || !Array.isArray(payload.tokens)) {
- return new Map()
- }
- return new Map(payload.tokens.map((token) => [token.id, token]))
-}
-
-function collectMetricsMap(payload) {
- if (!payload || typeof payload !== "object") {
- return new Map()
- }
- return new Map(Object.entries(payload))
+async function allTokenIds() {
+ const files = await readdir("content/tokens")
+ return files
+ .filter((f) => f.endsWith(".json"))
+ .map((f) => f.replace(/\.json$/, ""))
}
const { before, after } = parseArgs(process.argv.slice(2))
@@ -64,66 +40,31 @@ const zeroSha = /^0+$/
const hasBefore = before && !zeroSha.test(before)
const hasAfter = after && !zeroSha.test(after)
-const [currentTokens, currentMetrics] = hasAfter
- ? [
- readJsonFromGit(after, TOKENS_PATH),
- readJsonFromGit(after, METRICS_PATH),
- ]
- : await Promise.all([readJsonFile(TOKENS_PATH), readJsonFile(METRICS_PATH)])
-
-const previousTokens = hasBefore ? readJsonFromGit(before, TOKENS_PATH) : null
-const previousMetrics = hasBefore ? readJsonFromGit(before, METRICS_PATH) : null
-
-if (hasAfter && (!currentTokens || !currentMetrics)) {
- console.error(
- "::warning::Unable to load after JSON from git; skipping updates."
- )
- process.exit(0)
-}
-
-if (hasBefore && (!previousTokens || !previousMetrics)) {
- console.error(
- "::warning::Unable to load before JSON from git; skipping updates."
- )
- process.exit(0)
-}
-
-const currentTokenMap = collectTokenMap(currentTokens)
-const previousTokenMap = collectTokenMap(previousTokens)
-const currentMetricsMap = collectMetricsMap(currentMetrics)
-const previousMetricsMap = collectMetricsMap(previousMetrics)
+let ids
-const changed = new Set()
-
-if (!hasBefore || !previousTokens) {
- for (const id of currentTokenMap.keys()) {
- changed.add(id)
- }
+if (!hasBefore) {
+ ids = await allTokenIds()
} else {
- const ids = new Set([...currentTokenMap.keys(), ...previousTokenMap.keys()])
- for (const id of ids) {
- const beforeValue = previousTokenMap.get(id)
- const afterValue = currentTokenMap.get(id)
- if (stableStringify(beforeValue) !== stableStringify(afterValue)) {
- changed.add(id)
- }
- }
-}
-
-if (!hasBefore || !previousMetrics) {
- for (const id of currentMetricsMap.keys()) {
- changed.add(id)
- }
-} else {
- const ids = new Set([...currentMetricsMap.keys(), ...previousMetricsMap.keys()])
- for (const id of ids) {
- const beforeValue = previousMetricsMap.get(id)
- const afterValue = currentMetricsMap.get(id)
- if (stableStringify(beforeValue) !== stableStringify(afterValue)) {
- changed.add(id)
- }
+ try {
+ const range = hasAfter ? `${before} ${after}` : before
+ const diff = execSync(
+ `git diff --name-only ${range} -- content/tokens content/evaluations`,
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
+ )
+ ids = [
+ ...new Set(
+ diff
+ .split("\n")
+ .map((line) => tokenIdFromPath(line.trim()))
+ .filter(Boolean)
+ ),
+ ]
+ } catch (_error) {
+ console.error(
+ "::warning::Unable to diff content paths from git; skipping updates."
+ )
+ process.exit(0)
}
}
-const output = Array.from(changed).filter(Boolean).join(",")
-process.stdout.write(output)
+process.stdout.write(ids.join(","))
diff --git a/scripts/migrate-to-atoms.mjs b/scripts/migrate-to-atoms.mjs
new file mode 100644
index 0000000..a42c163
--- /dev/null
+++ b/scripts/migrate-to-atoms.mjs
@@ -0,0 +1,127 @@
+#!/usr/bin/env node
+/**
+ * One-shot migration: src/data/*.json (legacy monoliths) → content/ atoms.
+ *
+ * Deterministic and idempotent — wipes and rebuilds content/ from the legacy
+ * files. Kept for re-runs during review; obsolete once the legacy files are
+ * deleted.
+ *
+ * What it strips (and why):
+ * - token positive/neutral/atRisk/evidenceEntries: derived counts, stale for
+ * every token in the legacy data — recomputed at compose time
+ * - metric/criterion `about`: framework-owned, masked at runtime today
+ * (metrics-data.ts merge) — composed from framework atoms
+ * - metric `name`: uniform per metric id across tokens — becomes
+ * framework displayName
+ * - criterion `name`: kept ONLY where it diverges from the framework name
+ * (exactly one case today: lqty onchain-ctrl__access-gating)
+ */
+import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
+import { dirname, join } from "node:path"
+import { fileURLToPath } from "node:url"
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const src = join(root, "src", "data")
+const out = join(root, "content")
+
+const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
+const writeJson = (p, data) => {
+ mkdirSync(dirname(p), { recursive: true })
+ writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
+}
+
+// Framework constants leaving src/lib/framework.ts
+const METRIC_ANCHORS = {
+ "onchain-ctrl": "#metric-1-onchain-control",
+ "val-accrual": "#metric-2-value-accrual",
+ verifiability: "#metric-3-verifiability",
+ distribution: "#metric-4-token-distribution",
+ offchain: "#offchain-dependencies",
+}
+const FRAMEWORK_BASE_URL =
+ "https://github.com/aragon/ownership-token-framework/blob/development/README.md"
+
+const tokens = readJson(join(src, "tokens.json")).tokens
+const metricsByToken = readJson(join(src, "metrics.json"))
+const framework = readJson(join(src, "framework.json"))
+
+rmSync(out, { recursive: true, force: true })
+
+// --- content/tokens/.json ---------------------------------------------
+for (const t of tokens) {
+ const {
+ positive: _p,
+ neutral: _n,
+ atRisk: _r,
+ evidenceEntries: _e,
+ ...atom
+ } = t
+ writeJson(join(out, "tokens", `${t.id}.json`), atom)
+}
+
+// --- content/framework/ ----------------------------------------------------
+// displayName = the per-token metric name, asserted uniform across tokens
+const displayNames = new Map()
+for (const [tokenId, metrics] of Object.entries(metricsByToken)) {
+ for (const m of metrics) {
+ const seen = displayNames.get(m.id)
+ if (seen !== undefined && seen !== m.name) {
+ throw new Error(
+ `metric ${m.id} display name diverges at ${tokenId}: "${m.name}" vs "${seen}"`
+ )
+ }
+ displayNames.set(m.id, m.name)
+ }
+}
+
+for (const fm of framework) {
+ const atom = {
+ id: fm.id,
+ name: fm.name,
+ displayName: displayNames.get(fm.id) ?? fm.name,
+ about: fm.about,
+ ...(METRIC_ANCHORS[fm.id] ? { anchor: METRIC_ANCHORS[fm.id] } : {}),
+ criteria: fm.criteria,
+ }
+ writeJson(join(out, "framework", `${fm.id}.json`), atom)
+}
+writeJson(join(out, "framework", "_meta.json"), {
+ baseUrl: FRAMEWORK_BASE_URL,
+ order: framework.map((m) => m.id),
+})
+
+// --- content/evaluations/// -----------------------------
+const frameworkCriterionNames = new Map(
+ framework.flatMap((m) => m.criteria.map((c) => [c.id, c.name]))
+)
+
+let criterionCount = 0
+let nameOverrides = 0
+for (const [tokenId, metrics] of Object.entries(metricsByToken)) {
+ for (const m of metrics) {
+ const dir = join(out, "evaluations", tokenId, m.id)
+ writeJson(join(dir, "_metric.json"), { summary: m.summary, tags: m.tags })
+ for (const c of m.criteria) {
+ const atom = {}
+ if (c.name !== frameworkCriterionNames.get(c.id)) {
+ atom.name = c.name
+ nameOverrides++
+ }
+ atom.status = c.status
+ atom.notes = c.notes
+ if ("tags" in c) atom.tags = c.tags
+ if ("evidence" in c) atom.evidence = c.evidence
+ writeJson(join(dir, `${c.id}.json`), atom)
+ criterionCount++
+ }
+ }
+}
+
+// --- content/faq.json + content/testimonials.json --------------------------
+writeJson(join(out, "faq.json"), readJson(join(src, "faq.json")))
+writeJson(join(out, "testimonials.json"), readJson(join(src, "testimonials.json")))
+
+console.log(
+ `migrated: ${tokens.length} tokens, ${framework.length} framework metrics, ` +
+ `${criterionCount} criterion evaluations (${nameOverrides} name overrides)`
+)
diff --git a/scripts/sync-coingecko-ids.mjs b/scripts/sync-coingecko-ids.mjs
index 8b85ad1..0fc7e44 100644
--- a/scripts/sync-coingecko-ids.mjs
+++ b/scripts/sync-coingecko-ids.mjs
@@ -1,23 +1,23 @@
#!/usr/bin/env node
/**
- * Sync CoinGecko IDs for tokens in tokens.json
+ * Sync CoinGecko IDs for the token registry atoms in content/tokens/
*
* Uses CoinGecko's /coins/{platform}/contract/{address} endpoint
* to resolve the canonical CoinGecko ID from contract address + network.
*
* Usage:
* node scripts/sync-coingecko-ids.mjs # dry-run, skips tokens with existing IDs
- * node scripts/sync-coingecko-ids.mjs --write # writes back to tokens.json
+ * node scripts/sync-coingecko-ids.mjs --write # writes back to content/tokens/.json
* node scripts/sync-coingecko-ids.mjs --force # re-verify all tokens (ignores cached IDs)
*/
-import { readFileSync, writeFileSync } from "node:fs"
-import { resolve, dirname } from "node:path"
+import { readdirSync, readFileSync, writeFileSync } from "node:fs"
+import { dirname, join, resolve } from "node:path"
import { fileURLToPath } from "node:url"
const __dirname = dirname(fileURLToPath(import.meta.url))
-const TOKENS_PATH = resolve(__dirname, "../src/data/tokens.json")
+const TOKENS_DIR = resolve(__dirname, "../content/tokens")
// CoinGecko platform IDs mapped from our network names
const NETWORK_TO_PLATFORM = {
@@ -68,10 +68,14 @@ async function lookupCoingeckoId(address, network) {
async function main() {
const writeMode = process.argv.includes("--write")
- const tokensFile = JSON.parse(readFileSync(TOKENS_PATH, "utf-8"))
- const tokens = tokensFile.tokens
+ const tokenFiles = readdirSync(TOKENS_DIR).filter((f) => f.endsWith(".json"))
+ const tokens = tokenFiles.map((file) => ({
+ file: join(TOKENS_DIR, file),
+ ...JSON.parse(readFileSync(join(TOKENS_DIR, file), "utf-8")),
+ }))
let changes = 0
+ const changedFiles = new Set()
console.log(`\n${c.cyan}${c.bold} 🦎 CoinGecko Sync${c.reset}`)
console.log(`${c.dim} ─────────────────────────────${c.reset}\n`)
@@ -100,10 +104,12 @@ async function main() {
console.log(`${c.green}+ ${result.id}${c.reset}`)
token.coingeckoId = result.id
changes++
+ changedFiles.add(token.file)
} else if (token.coingeckoId !== result.id) {
console.log(`${c.yellow}≠ ${token.coingeckoId} → ${result.id}${c.reset}`)
token.coingeckoId = result.id
changes++
+ changedFiles.add(token.file)
} else {
console.log(`${c.green}✓ ${result.id}${c.reset}`)
}
@@ -113,8 +119,12 @@ async function main() {
console.log()
if (changes > 0 && writeMode) {
- writeFileSync(TOKENS_PATH, JSON.stringify(tokensFile, null, 2) + "\n")
- console.log(` ${c.green}✓${c.reset} Written ${c.bold}${changes}${c.reset} update(s) to tokens.json\n`)
+ for (const token of tokens) {
+ if (!changedFiles.has(token.file)) continue
+ const { file, ...atom } = token
+ writeFileSync(file, JSON.stringify(atom, null, 2) + "\n")
+ }
+ console.log(` ${c.green}✓${c.reset} Written ${c.bold}${changes}${c.reset} update(s) to content/tokens/\n`)
} else if (changes > 0) {
console.log(` ${c.yellow}${changes}${c.reset} update(s) pending ${c.dim}· run with --write to save${c.reset}\n`)
} else {
diff --git a/scripts/update-token-timestamps.mjs b/scripts/update-token-timestamps.mjs
index addab78..5e55bfa 100644
--- a/scripts/update-token-timestamps.mjs
+++ b/scripts/update-token-timestamps.mjs
@@ -1,7 +1,7 @@
-import { readFile, writeFile } from "node:fs/promises"
+import { readdir, readFile, writeFile } from "node:fs/promises"
import path from "node:path"
-const dataPath = path.resolve("src/data/tokens.json")
+const tokensDir = path.resolve("content/tokens")
function normalizeSymbol(value) {
return value.split("/").pop()?.trim().toUpperCase() ?? ""
@@ -31,42 +31,32 @@ const nextTimestamp = Number.isFinite(timestamp)
? timestamp
: Math.floor(Date.now() / 1000)
-const raw = await readFile(dataPath, "utf-8")
-const payload = JSON.parse(raw)
-
-if (!payload?.tokens || !Array.isArray(payload.tokens)) {
- throw new Error("Expected src/data/tokens.json to contain a tokens array")
-}
-
const idSet = ids ? new Set(ids.map((id) => id.toLowerCase())) : null
let updated = 0
-payload.tokens = payload.tokens.map((token) => {
- if (updateAll) {
- updated += 1
- return { ...token, lastUpdated: nextTimestamp }
- }
+const files = (await readdir(tokensDir)).filter((f) => f.endsWith(".json"))
- if (idSet && idSet.has(token.id.toLowerCase())) {
- updated += 1
- return { ...token, lastUpdated: nextTimestamp }
- }
+for (const file of files) {
+ const filePath = path.join(tokensDir, file)
+ const token = JSON.parse(await readFile(filePath, "utf-8"))
- if (symbol && token.symbol.toUpperCase() === symbol) {
- updated += 1
- return { ...token, lastUpdated: nextTimestamp }
- }
+ const matches =
+ updateAll ||
+ (idSet?.has(token.id.toLowerCase()) ?? false) ||
+ (symbol !== "" && token.symbol.toUpperCase() === symbol)
+
+ if (!matches) continue
- return token
-})
+ token.lastUpdated = nextTimestamp
+ await writeFile(filePath, `${JSON.stringify(token, null, 2)}\n`, "utf-8")
+ updated += 1
+}
if (updated === 0) {
console.log("No tokens matched; nothing updated.")
process.exit(0)
}
-await writeFile(dataPath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8")
-
console.log(
`Updated ${updated} token${updated === 1 ? "" : "s"} to ${nextTimestamp}.`
)
diff --git a/src/components/ui/evidence-link.tsx b/src/components/ui/evidence-link.tsx
index d71724d..e19dcc1 100644
--- a/src/components/ui/evidence-link.tsx
+++ b/src/components/ui/evidence-link.tsx
@@ -3,7 +3,12 @@ import type { ComponentProps } from "react"
import { cn } from "@/lib/utils"
import { ExplorerIcon } from "./explore-icon.tsx"
-export type EvidenceLinkType = "github" | "docs" | "explorer"
+export type EvidenceLinkType =
+ | "github"
+ | "docs"
+ | "explorer"
+ | "vote"
+ | "website"
interface IEvidenceLinkProps extends ComponentProps<"a"> {
type?: EvidenceLinkType
diff --git a/src/data/generated/faq.json b/src/data/generated/faq.json
new file mode 100644
index 0000000..64170db
--- /dev/null
+++ b/src/data/generated/faq.json
@@ -0,0 +1,60 @@
+{
+ "topics": [
+ {
+ "id": "basics",
+ "name": "Basics",
+ "about": "Core definitions and how to use the framework.",
+ "questions": [
+ {
+ "id": "basics__ownership-token",
+ "question": "What is an ownership token?",
+ "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
+ },
+ {
+ "id": "basics__how-to-use",
+ "question": "How can I use the Ownership Token Framework?",
+ "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
+ }
+ ]
+ },
+ {
+ "id": "methodology",
+ "name": "Methodology",
+ "about": "How evaluation, sourcing, and verification work.",
+ "questions": [
+ {
+ "id": "methodology__evaluation",
+ "question": "How do you evaluate tokens?",
+ "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ },
+ {
+ "id": "methodology__evidence",
+ "question": "How do you source and verify evidence?",
+ "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ }
+ ]
+ },
+ {
+ "id": "participation",
+ "name": "Participation",
+ "about": "How tokens are selected and how to get involved.",
+ "questions": [
+ {
+ "id": "participation__selection",
+ "question": "How do you choose which tokens to feature?",
+ "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
+ },
+ {
+ "id": "participation__listing",
+ "question": "How can I get a token listed?",
+ "answer": "Submit a request (or refer a token) using this [here](submit-token)."
+ },
+ {
+ "id": "participation__contribute",
+ "question": "How can I contribute to this initiative?",
+ "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/data/generated/framework.json b/src/data/generated/framework.json
new file mode 100644
index 0000000..7ff73b9
--- /dev/null
+++ b/src/data/generated/framework.json
@@ -0,0 +1,140 @@
+{
+ "baseUrl": "https://github.com/aragon/ownership-token-framework/blob/development/README.md",
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Metric 1: Onchain Control",
+ "displayName": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "anchor": "#metric-1-onchain-control",
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Metric 2: Value Accrual",
+ "displayName": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "anchor": "#metric-2-value-accrual",
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Metric 3: Verifiability",
+ "displayName": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "anchor": "#metric-3-verifiability",
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Metric 4: Token Distribution",
+ "displayName": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "anchor": "#metric-4-token-distribution",
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "displayName": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "anchor": "#offchain-dependencies",
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/data/tokens.json b/src/data/generated/index.json
similarity index 83%
rename from src/data/tokens.json
rename to src/data/generated/index.json
index e619bc2..801c790 100644
--- a/src/data/tokens.json
+++ b/src/data/generated/index.json
@@ -9,10 +9,6 @@
"icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
"description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 14,
- "neutral": 3,
- "atRisk": 1,
"lastUpdated": 1775651992,
"updatedBy": {
"avatar": "/logo192.png",
@@ -23,7 +19,16 @@
"twitter": "https://twitter.com/aave",
"scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
},
- "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
+ "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate.",
+ "positive": 12,
+ "neutral": 2,
+ "atRisk": 0,
+ "evidenceEntries": 18,
+ "score": {
+ "passing": 12,
+ "total": 12,
+ "percentage": 100
+ }
},
{
"id": "aero",
@@ -34,10 +39,6 @@
"icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
"description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
"network": "base",
- "evidenceEntries": 22,
- "positive": 19,
- "neutral": 2,
- "atRisk": 1,
"lastUpdated": 1775651992,
"updatedBy": {
"avatar": "/logo192.png",
@@ -48,7 +49,16 @@
"twitter": "https://twitter.com/Aerodrome",
"scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
},
- "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
+ "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy.",
+ "positive": 12,
+ "neutral": 3,
+ "atRisk": 0,
+ "evidenceEntries": 23,
+ "score": {
+ "passing": 12,
+ "total": 13,
+ "percentage": 92.3076923076923
+ }
},
{
"id": "crv",
@@ -59,10 +69,6 @@
"icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
"description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
"network": "ethereum",
- "evidenceEntries": 4,
- "positive": 4,
- "neutral": 0,
- "atRisk": 0,
"lastUpdated": 1775651992,
"updatedBy": {
"avatar": "/logo192.png",
@@ -73,7 +79,16 @@
"twitter": "https://twitter.com/curvefinance",
"scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
},
- "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
+ "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets.",
+ "positive": 13,
+ "neutral": 2,
+ "atRisk": 0,
+ "evidenceEntries": 23,
+ "score": {
+ "passing": 13,
+ "total": 13,
+ "percentage": 100
+ }
},
{
"id": "ena",
@@ -84,10 +99,6 @@
"icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
"description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 2,
- "neutral": 0,
- "atRisk": 16,
"lastUpdated": 1775651992,
"updatedBy": {
"avatar": "/logo192.png",
@@ -98,7 +109,46 @@
"twitter": "https://twitter.com/ethena",
"scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
},
- "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
+ "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe.",
+ "positive": 2,
+ "neutral": 16,
+ "atRisk": 0,
+ "evidenceEntries": 29,
+ "score": {
+ "passing": 2,
+ "total": 15,
+ "percentage": 13.333333333333334
+ }
+ },
+ {
+ "id": "ethfi",
+ "coingeckoId": "ether-fi",
+ "name": "ETHFI",
+ "symbol": "ETHFI",
+ "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
+ "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
+ "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ether.fi/",
+ "twitter": "https://twitter.com/ether_fi",
+ "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ },
+ "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking.",
+ "positive": 3,
+ "neutral": 13,
+ "atRisk": 1,
+ "evidenceEntries": 20,
+ "score": {
+ "passing": 3,
+ "total": 14,
+ "percentage": 21.428571428571427
+ }
},
{
"id": "ldo",
@@ -109,10 +159,6 @@
"icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
"description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
"network": "ethereum",
- "evidenceEntries": 12,
- "positive": 8,
- "neutral": 3,
- "atRisk": 1,
"lastUpdated": 1777631939,
"updatedBy": {
"avatar": "/logo192.png",
@@ -123,7 +169,16 @@
"twitter": "https://twitter.com/lidofinance",
"scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
},
- "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
+ "infoDescription": "Lido is the leading liquid staking solution for Ethereum.",
+ "positive": 15,
+ "neutral": 0,
+ "atRisk": 0,
+ "evidenceEntries": 26,
+ "score": {
+ "passing": 12,
+ "total": 12,
+ "percentage": 100
+ }
},
{
"id": "lqty",
@@ -134,10 +189,6 @@
"icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
"description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
"network": "ethereum",
- "evidenceEntries": 0,
- "positive": 0,
- "neutral": 0,
- "atRisk": 0,
"lastUpdated": 1778064256,
"updatedBy": {
"avatar": "/logo192.png",
@@ -148,57 +199,46 @@
"twitter": "https://twitter.com/LiquityProtocol",
"scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
},
- "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
- },
- {
- "id": "uni",
- "coingeckoId": "uniswap",
- "name": "UNI",
- "symbol": "UNI",
- "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
- "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
- "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
- "network": "ethereum",
- "evidenceEntries": 18,
+ "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters.",
"positive": 13,
- "neutral": 4,
- "atRisk": 1,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://uniswap.org/",
- "twitter": "https://twitter.com/uniswap",
- "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
- },
- "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
+ "neutral": 0,
+ "atRisk": 0,
+ "evidenceEntries": 16,
+ "score": {
+ "passing": 13,
+ "total": 13,
+ "percentage": 100
+ }
},
{
- "id": "yb",
- "coingeckoId": "yield-basis",
- "name": "YB",
- "symbol": "YB",
- "address": "0x01791F726B4103694969820be083196cC7c045fF",
- "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
- "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
+ "id": "ondo",
+ "name": "ONDO",
+ "symbol": "ONDO",
+ "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
+ "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
+ "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 11,
- "neutral": 3,
- "atRisk": 4,
- "lastUpdated": 1774549304,
+ "lastUpdated": 1778674909,
"updatedBy": {
"avatar": "/logo192.png",
"name": "Aragon Developers"
},
"links": {
- "website": "https://yieldbasis.com/",
- "twitter": "https://x.com/yieldbasis",
- "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
+ "website": "https://ondo.finance/",
+ "twitter": "https://twitter.com/OndoFinance",
+ "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
},
- "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
+ "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
+ "coingeckoId": "ondo-finance",
+ "positive": 4,
+ "neutral": 4,
+ "atRisk": 9,
+ "evidenceEntries": 27,
+ "score": {
+ "passing": 4,
+ "total": 15,
+ "percentage": 26.666666666666668
+ }
},
{
"id": "sky",
@@ -209,10 +249,6 @@
"icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
"description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 13,
- "neutral": 3,
- "atRisk": 2,
"lastUpdated": 1774549304,
"updatedBy": {
"avatar": "/logo192.png",
@@ -223,57 +259,76 @@
"twitter": "https://twitter.com/SkyEcosystem",
"scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
},
- "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
+ "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable).",
+ "positive": 13,
+ "neutral": 1,
+ "atRisk": 0,
+ "evidenceEntries": 25,
+ "score": {
+ "passing": 12,
+ "total": 12,
+ "percentage": 100
+ }
},
{
- "id": "ethfi",
- "coingeckoId": "ether-fi",
- "name": "ETHFI",
- "symbol": "ETHFI",
- "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
- "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
- "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "id": "uni",
+ "coingeckoId": "uniswap",
+ "name": "UNI",
+ "symbol": "UNI",
+ "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
+ "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
+ "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 3,
- "neutral": 13,
- "atRisk": 2,
- "lastUpdated": 1774549304,
+ "lastUpdated": 1775651992,
"updatedBy": {
"avatar": "/logo192.png",
"name": "Aragon Developers"
},
"links": {
- "website": "https://ether.fi/",
- "twitter": "https://twitter.com/ether_fi",
- "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ "website": "https://uniswap.org/",
+ "twitter": "https://twitter.com/uniswap",
+ "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
},
- "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
+ "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains.",
+ "positive": 13,
+ "neutral": 3,
+ "atRisk": 0,
+ "evidenceEntries": 25,
+ "score": {
+ "passing": 13,
+ "total": 13,
+ "percentage": 100
+ }
},
{
- "id": "ondo",
- "name": "ONDO",
- "symbol": "ONDO",
- "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
- "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
- "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
+ "id": "yb",
+ "coingeckoId": "yield-basis",
+ "name": "YB",
+ "symbol": "YB",
+ "address": "0x01791F726B4103694969820be083196cC7c045fF",
+ "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
+ "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
"network": "ethereum",
- "evidenceEntries": 18,
- "positive": 3,
- "neutral": 2,
- "atRisk": 13,
- "lastUpdated": 1778674909,
+ "lastUpdated": 1774549304,
"updatedBy": {
"avatar": "/logo192.png",
"name": "Aragon Developers"
},
"links": {
- "website": "https://ondo.finance/",
- "twitter": "https://twitter.com/OndoFinance",
- "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
+ "website": "https://yieldbasis.com/",
+ "twitter": "https://x.com/yieldbasis",
+ "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
},
- "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
- "coingeckoId": "ondo-finance"
+ "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision.",
+ "positive": 11,
+ "neutral": 4,
+ "atRisk": 1,
+ "evidenceEntries": 18,
+ "score": {
+ "passing": 11,
+ "total": 14,
+ "percentage": 78.57142857142857
+ }
}
]
}
diff --git a/src/data/generated/testimonials.json b/src/data/generated/testimonials.json
new file mode 100644
index 0000000..2846926
--- /dev/null
+++ b/src/data/generated/testimonials.json
@@ -0,0 +1,21 @@
+{
+ "title": "Evidence-backed due diligence for investors",
+ "testimonials": [
+ {
+ "id": "miles-a16z",
+ "name": "Miles Jennings",
+ "organization": "a16z",
+ "avatar": "/images/testimonials/miles-jennings.png",
+ "url": "https://a16zcrypto.com/",
+ "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
+ },
+ {
+ "id": "f5-crypto",
+ "name": "Paul Otto",
+ "organization": "F5 Crypto",
+ "avatar": "/images/testimonials/paul-otto.png",
+ "url": "https://f5crypto.com/en/",
+ "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
+ }
+ ]
+}
diff --git a/src/data/generated/tokens/aave.json b/src/data/generated/tokens/aave.json
new file mode 100644
index 0000000..755dae2
--- /dev/null
+++ b/src/data/generated/tokens/aave.json
@@ -0,0 +1,550 @@
+{
+ "id": "aave",
+ "coingeckoId": "aave",
+ "name": "AAVE",
+ "symbol": "AAVE",
+ "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
+ "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
+ "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aave.com/",
+ "twitter": "https://twitter.com/aave",
+ "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
+ },
+ "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate.",
+ "positive": 12,
+ "neutral": 2,
+ "atRisk": 0,
+ "evidenceEntries": 18,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://aave.com/docs/ecosystem/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
+ "evidence": [
+ {
+ "name": "Governance Emergency Guardian",
+ "urls": [
+ {
+ "name": "Onchain address",
+ "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Detailed Governance Permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Holders control implementation upgrades for all v3 market deployments.",
+ "evidence": [
+ {
+ "name": "Upgrade Documentation",
+ "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
+ "urls": [
+ {
+ "name": "Upgradability per contract",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Ownership Chain",
+ "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
+ "urls": [
+ {
+ "name": "Pool",
+ "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance",
+ "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The AAVE token is upgradeable but controlled by token holders.",
+ "evidence": [
+ {
+ "name": "Ownership Chain",
+ "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
+ "urls": [
+ {
+ "name": "AAVE Proxy",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ProxyAdmin",
+ "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
+ "evidence": [
+ {
+ "name": "Core",
+ "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
+ "urls": [
+ {
+ "name": "Core Protocol Role addresses",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
+ "type": "github"
+ },
+ {
+ "name": "Core Protocol Roles in ACLManager",
+ "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
+ "type": "explorer"
+ },
+ {
+ "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
+ "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
+ "type": "explorer"
+ },
+ {
+ "name": "POOL_ADMIN_ROLE: Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Delegated Steward Roles",
+ "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
+ "urls": [
+ {
+ "name": "Stewards (docs)",
+ "url": "https://aave.com/help/governance/aave-community",
+ "type": "docs"
+ },
+ {
+ "name": "Stewards (addresses)",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Protocol Emergency Guardian",
+ "summary": "A separate multisig that executes limited emergency operations for the protocol.",
+ "urls": [
+ {
+ "name": "Protocol Emergency Guardian",
+ "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
+ "type": "docs"
+ },
+ {
+ "name": "Detailed protocol permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token's implementation code",
+ "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Safety Module - Incentives",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Transition",
+ "url": "https://aave.com/help/umbrella/stake",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Activation Proposal",
+ "url": "https://vote.onaave.com/proposal/?proposalId=320",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "Token holders direct treasury via governance.",
+ "urls": [
+ {
+ "name": "Treasury docs",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Fee Sources",
+ "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
+ "urls": [
+ {
+ "name": "mintToTreasury (PoolLogic)",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
+ "type": "github"
+ },
+ {
+ "name": "Flashloan premium",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
+ "type": "github"
+ },
+ {
+ "name": "Liquidation fee",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
+ "evidence": [
+ {
+ "name": "ACL Control",
+ "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
+ "urls": [
+ {
+ "name": "POOL_ADMIN role",
+ "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
+ "type": "docs"
+ },
+ {
+ "name": "ACLManager",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
+ "tags": ["Reference"],
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Trademark filing",
+ "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The primary interface terms identify Aave Labs as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://aave.com/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
+ "evidence": []
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "aave",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/aero.json b/src/data/generated/tokens/aero.json
new file mode 100644
index 0000000..b87f946
--- /dev/null
+++ b/src/data/generated/tokens/aero.json
@@ -0,0 +1,628 @@
+{
+ "id": "aero",
+ "coingeckoId": "aerodrome-finance",
+ "name": "AERO",
+ "symbol": "AERO",
+ "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
+ "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
+ "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
+ "network": "base",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aerodrome.finance/",
+ "twitter": "https://twitter.com/Aerodrome",
+ "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
+ },
+ "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy.",
+ "positive": 12,
+ "neutral": 3,
+ "atRisk": 0,
+ "evidenceEntries": 23,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
+ "evidence": [
+ {
+ "name": "Voting System",
+ "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "VotingEscrow",
+ "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Voter",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Council",
+ "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
+ "urls": [
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://aerodrome.limited/pages/security.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
+ "evidence": [
+ {
+ "name": "Emergency Council",
+ "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
+ "urls": [
+ {
+ "name": "Voter: emergencyCouncil",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contract Addresses",
+ "url": "https://aerodrome.finance/security",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
+ "evidence": [
+ {
+ "name": "Minter Contract",
+ "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
+ "urls": [
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
+ "urls": [
+ {
+ "name": "Minter Emission Increase (Epochs 1-14)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
+ "type": "github"
+ },
+ {
+ "name": "Minter Emission Decay",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Growth Emissions",
+ "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
+ "urls": [
+ {
+ "name": "Growth Emissions Formula",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Team Emission Rate",
+ "summary": "Currently set to 0% of total weekly emissions.",
+ "urls": [
+ {
+ "name": "Team Emission Rate",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "warning",
+ "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
+ "evidence": [
+ {
+ "name": "Fee Manager Role",
+ "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
+ "urls": [
+ {
+ "name": "Safe (Fee Manager)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-SlipStream Fees",
+ "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
+ "urls": [
+ {
+ "name": "PoolFactory: FeeManager",
+ "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "SlipStream Fees",
+ "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
+ "urls": [
+ {
+ "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
+ "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "SwapFeeModule: setCustomFee",
+ "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
+ "evidence": [
+ {
+ "name": "Team Rate",
+ "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
+ "urls": [
+ {
+ "name": "Safe (Team)",
+ "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
+ "urls": [
+ {
+ "name": "Governor (Safe)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
+ "type": "explorer"
+ },
+ {
+ "name": "Emission Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
+ "evidence": [
+ {
+ "name": "Growth Emissions",
+ "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
+ "urls": [
+ {
+ "name": "Growth Transfer to RewardDistributor",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
+ "type": "github"
+ },
+ {
+ "name": "RewardsDistributor Claim",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Non-Slipstream Trading Fees",
+ "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Gauge Deposit Logic",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Accrued",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
+ "type": "github"
+ },
+ {
+ "name": "Voter calling Gauge to claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed by Gauge on PoolFees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Slipstream Trading Fees",
+ "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Fees Split",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees calculated separately",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
+ "type": "github"
+ },
+ {
+ "name": "Non Staked LP Fees collected",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees to feesVotingReward",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
+ "type": "github"
+ },
+ {
+ "name": "veAERO voters claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
+ "evidence": []
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
+ "evidence": [
+ {
+ "name": "Locking Control",
+ "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
+ "urls": [
+ {
+ "name": "VotingEscrow create_lock",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
+ "urls": [
+ {
+ "name": "Voter vote function",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
+ "type": "github"
+ },
+ {
+ "name": "Gauge getReward",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token (Basescan)",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Aero.sol Source (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contracts (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Aerodrome Slipstream (GitHub)",
+ "url": "https://github.com/aerodrome-finance/slipstream",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "positive",
+ "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "USPTO Report",
+ "url": "https://uspto.report/TM/99083103",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Legal",
+ "url": "https://aero.drome.eth.link/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
+ "evidence": []
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "aero",
+ "passing": 12,
+ "total": 13,
+ "percentage": 92.3076923076923,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 6,
+ "total": 7,
+ "percentage": 85.71428571428571,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/crv.json b/src/data/generated/tokens/crv.json
new file mode 100644
index 0000000..a912564
--- /dev/null
+++ b/src/data/generated/tokens/crv.json
@@ -0,0 +1,554 @@
+{
+ "id": "crv",
+ "coingeckoId": "curve-dao-token",
+ "name": "CRV",
+ "symbol": "CRV",
+ "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
+ "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
+ "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://curve.finance/",
+ "twitter": "https://twitter.com/curvefinance",
+ "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
+ },
+ "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets.",
+ "positive": 13,
+ "neutral": 2,
+ "atRisk": 0,
+ "evidenceEntries": 23,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aragon Voting Contract",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent Contract",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
+ "type": "explorer"
+ },
+ {
+ "name": "CRV Token: Admin is set to Agent",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
+ "evidence": [
+ {
+ "name": "Gauge Addition",
+ "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
+ "urls": [
+ {
+ "name": "GaugeController: admin is Agent",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Pool Factory Ownership",
+ "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
+ "urls": [
+ {
+ "name": "Curve Pool Factory: admin is OwnerProxy",
+ "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
+ "evidence": [
+ {
+ "name": "Core Contracts",
+ "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
+ "urls": [
+ {
+ "name": "CRV Token (Admin: Agent)",
+ "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
+ "type": "explorer"
+ },
+ {
+ "name": "GaugeController (Admin: Agent)",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent Contract",
+ "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Voting Contract",
+ "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Source",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
+ "evidence": [
+ {
+ "name": "Supply Schedule",
+ "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ },
+ {
+ "name": "ERC20CRV.vy Yearly Epoch Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Access",
+ "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Mint Access",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
+ "type": "github"
+ },
+ {
+ "name": "Minter.vy Gauge Validation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
+ "evidence": [
+ {
+ "name": "Add/Kill Gauge",
+ "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
+ "urls": [
+ {
+ "name": "Gauge Kill Implementation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Standard Transfer",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
+ "type": "github"
+ },
+ {
+ "name": "ERC20CRV.vy Metadata Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
+ "evidence": [
+ {
+ "name": "CRV Emissions Rewards",
+ "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
+ "urls": [
+ {
+ "name": "working_balance reward calculation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Pool Rewards in crvUSD",
+ "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
+ "urls": [
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Borrow Rewards in crvUSD",
+ "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
+ "urls": [
+ {
+ "name": "FeeSplitter",
+ "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "veCRV Revenue Share (Docs)",
+ "url": "https://docs.curve.finance/user/vecrv/revenue",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
+ "evidence": [
+ {
+ "name": "Pool Fee Control",
+ "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "DAI/USDC/USDT Pool: commit_new_fee",
+ "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burner Attachment",
+ "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "StableSwapProxy: set_burner",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burn Execution",
+ "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
+ "urls": [
+ {
+ "name": "StableSwapProxy: burn",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Token (Etherscan)",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ERC20CRV.vy Source (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Curve DAO protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve DAO Contracts (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "positive",
+ "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Swiss Trademark Registry",
+ "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve Legal",
+ "url": "https://www.curve.finance/dex/ethereum/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
+ "evidence": []
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "crv",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/ena.json b/src/data/generated/tokens/ena.json
new file mode 100644
index 0000000..c354999
--- /dev/null
+++ b/src/data/generated/tokens/ena.json
@@ -0,0 +1,810 @@
+{
+ "id": "ena",
+ "coingeckoId": "ethena",
+ "name": "ENA",
+ "symbol": "ENA",
+ "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
+ "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
+ "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ethena.fi/",
+ "twitter": "https://twitter.com/ethena",
+ "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
+ },
+ "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe.",
+ "positive": 2,
+ "neutral": 16,
+ "atRisk": 0,
+ "evidenceEntries": 29,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "warning",
+ "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
+ "evidence": [
+ {
+ "name": "Snapshot Governance",
+ "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
+ "urls": [
+ {
+ "name": "Snapshot Space",
+ "url": "https://snapshot.org/#/ethenagovernance.eth",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Multisig Execution",
+ "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
+ "urls": [
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "warning",
+ "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
+ "evidence": [
+ {
+ "name": "Multisig Control Matrix",
+ "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ },
+ {
+ "name": "Hot Swap Multisig",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "Trading Operations Multisig",
+ "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
+ "type": "explorer"
+ },
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "EOA Control Points",
+ "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
+ "urls": [
+ {
+ "name": "StakingRewardsDistributor Operator (EOA)",
+ "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
+ "type": "explorer"
+ },
+ {
+ "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "warning",
+ "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Contracts",
+ "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Contracts (sENA and rsENA)",
+ "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
+ "urls": [
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Implementation",
+ "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Implementation",
+ "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "warning",
+ "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
+ "evidence": [
+ {
+ "name": "ENA Non-Upgradeability Verification",
+ "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
+ "urls": [
+ {
+ "name": "ENA.sol Source",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "warning",
+ "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
+ "evidence": [
+ {
+ "name": "Mint Function",
+ "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
+ "urls": [
+ {
+ "name": "ENA.sol `mint()` function (lines 42-49)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token totalSupply",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "warning",
+ "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
+ "evidence": [
+ {
+ "name": "Privileged Roles (per Multisig Matrix)",
+ "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Gatekeeper Powers",
+ "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
+ "urls": [
+ {
+ "name": "`disableMintRedeem()` (line 278)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
+ "type": "github"
+ },
+ {
+ "name": "`removeMinterRole()` (line 339)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
+ "type": "github"
+ },
+ {
+ "name": "`removeRedeemerRole()` (line 345)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "warning",
+ "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
+ "evidence": [
+ {
+ "name": "sENA/sUSDe Blacklist Capabilities",
+ "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
+ "urls": [
+ {
+ "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
+ "type": "github"
+ },
+ {
+ "name": "`redistributeLockedAmount()` (lines 106-127)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
+ "type": "github"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "warning",
+ "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
+ "evidence": [
+ {
+ "name": "Fee Switch Status",
+ "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "USDe Token (verify totalSupply)",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Ethena Network Airdrops",
+ "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
+ "urls": [
+ {
+ "name": "Ethena Network Documentation",
+ "url": "https://docs.ethena.fi/ethena-network",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "rsENA (Restaked ENA via Symbiotic)",
+ "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
+ "urls": [
+ {
+ "name": "rsENA Contract",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA Staking Documentation",
+ "url": "https://docs.ethena.fi/ena",
+ "type": "docs"
+ },
+ {
+ "name": "Mellow Finance rsENA Vault",
+ "url": "https://app.mellow.finance/vaults/ethereum-rsena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "warning",
+ "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
+ "evidence": [
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
+ "urls": [
+ {
+ "name": "Key Addresses Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-addresses",
+ "type": "docs"
+ },
+ {
+ "name": "Hot Swap Multisig (revenue receiver)",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Reserve Fund (Negative Funding Backup)",
+ "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
+ "urls": [
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "warning",
+ "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
+ "evidence": [
+ {
+ "name": "ENA Value Accrual Controls",
+ "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
+ "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Tokenholder Cannot Force Activation",
+ "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "warning",
+ "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
+ "evidence": [
+ {
+ "name": "USDe Yield Sources",
+ "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
+ "urls": [
+ {
+ "name": "Coin Metrics Analysis (USDe Yield Sources)",
+ "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Yield Distribution Flow",
+ "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
+ "urls": [
+ {
+ "name": "`transferInRewards()` (lines 88-94)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
+ "type": "github"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA.sol Source (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
+ "evidence": [
+ {
+ "name": "Verified Contracts",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "GitHub Repository",
+ "urls": [
+ {
+ "name": "Ethena Public Assets (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Audits",
+ "urls": [
+ {
+ "name": "Code4rena 2023 Audit",
+ "url": "https://github.com/code-423n4/2023-10-ethena",
+ "type": "github"
+ },
+ {
+ "name": "Code4rena 2024 Audit",
+ "url": "https://github.com/code-423n4/2024-11-ethena-labs",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "warning",
+ "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
+ "urls": [
+ {
+ "name": "Tokenomist.ai - ENA",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ },
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "warning",
+ "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
+ "evidence": [
+ {
+ "name": "Vesting Schedules",
+ "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
+ "urls": [
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ },
+ {
+ "name": "Tokenomist.ai - ENA Vesting",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena GitHub License",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "ena",
+ "passing": 2,
+ "total": 15,
+ "percentage": 13.333333333333334,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 0,
+ "total": 7,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/ethfi.json b/src/data/generated/tokens/ethfi.json
new file mode 100644
index 0000000..94b51bf
--- /dev/null
+++ b/src/data/generated/tokens/ethfi.json
@@ -0,0 +1,601 @@
+{
+ "id": "ethfi",
+ "coingeckoId": "ether-fi",
+ "name": "ETHFI",
+ "symbol": "ETHFI",
+ "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
+ "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
+ "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ether.fi/",
+ "twitter": "https://twitter.com/ether_fi",
+ "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ },
+ "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking.",
+ "positive": 3,
+ "neutral": 13,
+ "atRisk": 1,
+ "evidenceEntries": 20,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "at_risk",
+ "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "evidence": [
+ {
+ "name": "Governance Structure",
+ "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "urls": [
+ {
+ "name": "Governance Info",
+ "url": "https://vote.ether.fi/info",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Resources",
+ "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Roadmap",
+ "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "warning",
+ "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
+ "evidence": [
+ {
+ "name": "RoleRegistry Owner (Upgrade Timelock)",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock (72h)",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Two-Timelock System",
+ "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
+ "urls": [
+ {
+ "name": "Upgrade Admin (4-of-7)",
+ "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Timelock (8h)",
+ "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Admin (3-of-5)",
+ "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "warning",
+ "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
+ "urls": [
+ {
+ "name": "RoleRegistry Upgrade Check",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
+ "type": "github"
+ },
+ {
+ "name": "LiquidityPool Upgrade Authorization",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "RoleRegistry Owner",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "warning",
+ "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
+ "evidence": [
+ {
+ "name": "Mainnet Token (Not Upgradeable)",
+ "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "L2 Tokens (Upgradeable, No Timelock)",
+ "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
+ "urls": [
+ {
+ "name": "Arbitrum ETHFI",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum Admin (3-of-6)",
+ "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ },
+ {
+ "name": "Base Admin (3-of-6)",
+ "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
+ "evidence": [
+ {
+ "name": "Fixed Supply",
+ "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "warning",
+ "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
+ "evidence": [
+ {
+ "name": "Pause Authority",
+ "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
+ "urls": [
+ {
+ "name": "EtherFiAdmin Pause Function",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "warning",
+ "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
+ "evidence": [
+ {
+ "name": "Token Analysis",
+ "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum ETHFI (Upgradeable)",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI (Upgradeable)",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
+ "evidence": [
+ {
+ "name": "Buyback Program",
+ "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
+ "urls": [
+ {
+ "name": "ETHFI Buyback Program",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback History (Dune)",
+ "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
+ "type": "docs"
+ },
+ {
+ "name": "sETHFI Staking",
+ "url": "https://www.ether.fi/app/ethfi",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback Wallet (1-of-5)",
+ "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "warning",
+ "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "warning",
+ "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
+ "evidence": [
+ {
+ "name": "Fee Configuration",
+ "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
+ "urls": [
+ {
+ "name": "LiquidityPool Fee Functions",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
+ "tags": ["Reference"],
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "warning",
+ "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
+ "evidence": [
+ {
+ "name": "Token Verification",
+ "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
+ "urls": [
+ {
+ "name": "Etherscan Verified Source",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
+ "evidence": [
+ {
+ "name": "Protocol Source & Audits",
+ "urls": [
+ {
+ "name": "etherfi-protocol/smart-contracts",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "warning",
+ "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "warning",
+ "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "DefiLlama Unlocks",
+ "url": "https://defillama.com/unlocks/ether.fi",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
+ "evidence": [
+ {
+ "name": "Trademark Ownership",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
+ "evidence": [
+ {
+ "name": "Legal Entity",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
+ "evidence": [
+ {
+ "name": "License",
+ "urls": [
+ {
+ "name": "GitHub Repository",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Terms of Use (Non-Contract IP)",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "ethfi",
+ "passing": 3,
+ "total": 14,
+ "percentage": 21.428571428571427,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 1,
+ "total": 7,
+ "percentage": 14.285714285714285,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 1,
+ "total": 3,
+ "percentage": 33.33333333333333,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/ldo.json b/src/data/generated/tokens/ldo.json
new file mode 100644
index 0000000..44dc585
--- /dev/null
+++ b/src/data/generated/tokens/ldo.json
@@ -0,0 +1,676 @@
+{
+ "id": "ldo",
+ "coingeckoId": "lido-dao",
+ "name": "LDO",
+ "symbol": "LDO",
+ "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
+ "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
+ "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
+ "network": "ethereum",
+ "lastUpdated": 1777631939,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://lido.fi/",
+ "twitter": "https://twitter.com/lidofinance",
+ "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
+ },
+ "infoDescription": "Lido is the leading liquid staking solution for Ethereum.",
+ "positive": 15,
+ "neutral": 0,
+ "atRisk": 0,
+ "evidenceEntries": 26,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
+ "evidence": [
+ {
+ "name": "Governance 1A",
+ "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ },
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Governance 1B",
+ "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Easy Track",
+ "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
+ "urls": [
+ {
+ "name": "Easy Track Interface",
+ "url": "https://easytrack.lido.fi/",
+ "type": "docs"
+ },
+ {
+ "name": "Easy Track Guide",
+ "url": "https://docs.lido.fi/guides/easy-track-guide",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
+ "evidence": [
+ {
+ "name": "Voting",
+ "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent",
+ "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "TokenManager",
+ "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "StakingRouter",
+ "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Upgradeable Contracts",
+ "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-upgradeable Contracts",
+ "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
+ "urls": [
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
+ "evidence": [
+ {
+ "name": "Token Contract",
+ "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
+ "urls": [
+ {
+ "name": "LDO Token",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Controller Upgrade Path",
+ "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
+ "evidence": [
+ {
+ "name": "Minting Path",
+ "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
+ "urls": [
+ {
+ "name": "MiniMeToken.generateTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
+ "evidence": [
+ {
+ "name": "Guardian Role",
+ "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
+ "urls": [
+ {
+ "name": "DepositSecurityModule",
+ "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Lido.sol deposit logic",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
+ "type": "github"
+ },
+ {
+ "name": "Guardians use automated software",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Guardian Accountability",
+ "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
+ "urls": [
+ {
+ "name": "Guardian Committee Membership",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
+ "type": "docs"
+ },
+ {
+ "name": "Guardians cannot control stake allocation",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
+ "evidence": [
+ {
+ "name": "Burn Capability",
+ "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
+ "urls": [
+ {
+ "name": "MiniMeToken.destroyTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
+ "type": "github"
+ },
+ {
+ "name": "Aragon ACL",
+ "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Transfer Control",
+ "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
+ "urls": [
+ {
+ "name": "MiniMeToken.enableTransfers",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
+ "evidence": [
+ {
+ "name": "Treasury Fee Flow",
+ "urls": [
+ {
+ "name": "StakingRouter (read contract)",
+ "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
+ "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Buyback Program",
+ "urls": [
+ {
+ "name": "stETH/LDO Buyback Proposal",
+ "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
+ "type": "docs"
+ },
+ {
+ "name": "stETH/LDO Buyback Snapshot Vote",
+ "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
+ "type": "vote"
+ },
+ {
+ "name": "NEST",
+ "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
+ "type": "docs"
+ },
+ {
+ "name": "Liquid buybacks research",
+ "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "Agent (Treasury)",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "StakingRouter add/update",
+ "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LDO Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ },
+ {
+ "name": "MiniMeToken Source (GitHub)",
+ "url": "https://github.com/aragon/minime",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Lido core protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Core Contracts (GitHub)",
+ "url": "https://github.com/lidofinance/core",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "positive",
+ "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UK IPO Trademark Journal",
+ "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Logo",
+ "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "ldo",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/lqty.json b/src/data/generated/tokens/lqty.json
new file mode 100644
index 0000000..d8f302c
--- /dev/null
+++ b/src/data/generated/tokens/lqty.json
@@ -0,0 +1,510 @@
+{
+ "id": "lqty",
+ "coingeckoId": "liquity",
+ "name": "LQTY",
+ "symbol": "LQTY",
+ "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
+ "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
+ "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
+ "network": "ethereum",
+ "lastUpdated": 1778064256,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://www.liquity.org/",
+ "twitter": "https://twitter.com/LiquityProtocol",
+ "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
+ },
+ "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters.",
+ "positive": 13,
+ "neutral": 0,
+ "atRisk": 0,
+ "evidenceEntries": 16,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token Source",
+ "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY token's implementation code",
+ "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
+ "type": "github"
+ },
+ {
+ "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
+ "type": "github"
+ },
+ {
+ "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
+ "url": "https://docs.liquity.org/v2-faq/lqty-staking",
+ "type": "docs"
+ },
+ {
+ "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Docs",
+ "url": "https://www.liquity.org/blog/liquity-v2-is-live",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
+ "tags": ["Reference"],
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
+ "type": "explorer"
+ },
+ {
+ "name": "LQTYToken.sol Source (GitHub)",
+ "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Liquity protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Core (GitHub)",
+ "url": "https://github.com/liquity/bold",
+ "type": "github"
+ },
+ {
+ "name": "Liquity V2 Governance (GitHub)",
+ "url": "https://github.com/liquity/V2-gov",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "positive",
+ "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LockupContractFactory (Etherscan)",
+ "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
+ "type": "explorer"
+ },
+ {
+ "name": "CommunityIssuance (Etherscan)",
+ "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "fail",
+ "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity AG - Crunchbase Company Profile",
+ "url": "https://www.crunchbase.com/organization/liquity-1d3e",
+ "type": "website"
+ },
+ {
+ "name": "Liquity - Tracxn Company Profile",
+ "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
+ "type": "website"
+ },
+ {
+ "name": "Team Page - Liquity.org",
+ "url": "https://www.liquity.org/team",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "partial",
+ "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity Runs on Decentralized Frontends - Official Blog",
+ "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
+ "type": "website"
+ },
+ {
+ "name": "Frontend Operators Page",
+ "url": "https://www.liquity.org/frontend-operators",
+ "type": "website"
+ },
+ {
+ "name": "Liquity Launch Details (AG does not run frontend)",
+ "url": "https://www.liquity.org/blog/liquity-launch-details",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "fail",
+ "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Licensing Liquity V2 - Official Blog",
+ "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
+ "type": "website"
+ },
+ {
+ "name": "Liquity V2 Core LICENSE File (GitHub)",
+ "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
+ "type": "github"
+ },
+ {
+ "name": "What's New in Liquity V2 - Bankless",
+ "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "lqty",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/ondo.json b/src/data/generated/tokens/ondo.json
new file mode 100644
index 0000000..a241ebc
--- /dev/null
+++ b/src/data/generated/tokens/ondo.json
@@ -0,0 +1,836 @@
+{
+ "id": "ondo",
+ "name": "ONDO",
+ "symbol": "ONDO",
+ "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
+ "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
+ "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
+ "network": "ethereum",
+ "lastUpdated": 1778674909,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ondo.finance/",
+ "twitter": "https://twitter.com/OndoFinance",
+ "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
+ },
+ "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
+ "coingeckoId": "ondo-finance",
+ "positive": 4,
+ "neutral": 4,
+ "atRisk": 9,
+ "evidenceEntries": 27,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "at_risk",
+ "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
+ "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (OUSG admin)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin owner",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
+ "evidence": [
+ {
+ "name": "Team-Controlled Roles (ONDO Token)",
+ "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (OUSG/USDY)",
+ "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "rOUSG",
+ "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "rUSDY",
+ "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (Global Markets)",
+ "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ },
+ {
+ "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
+ "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
+ "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (EOA)",
+ "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
+ "type": "explorer"
+ },
+ {
+ "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
+ "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY (Team-Controlled)",
+ "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
+ "urls": [
+ {
+ "name": "OUSG Proxy",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Proxy",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Polygon OUSG ProxyAdmin Owner",
+ "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
+ "type": "explorer"
+ },
+ {
+ "name": "Mantle USDY ProxyAdmin Owner",
+ "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum USDY ProxyAdmin Owner",
+ "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Team-Controlled via TimelockController)",
+ "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
+ "urls": [
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
+ "evidence": [
+ {
+ "name": "ONDO Token Roles",
+ "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Contract Source Note",
+ "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
+ "urls": [
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "at_risk",
+ "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
+ "evidence": [
+ {
+ "name": "Current Supply",
+ "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
+ "urls": [
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Mint Function Exists",
+ "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "ONDO Token (verified source)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (MINTER_ROLE holder)",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "at_risk",
+ "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
+ "evidence": [
+ {
+ "name": "OUSG Transfer Restrictions",
+ "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
+ "urls": [
+ {
+ "name": "OUSG Contract (KYC enforcement)",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG KYC check (source)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
+ "type": "github"
+ },
+ {
+ "name": "KYCRegistry",
+ "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "USDY Transfer Restrictions",
+ "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
+ "urls": [
+ {
+ "name": "USDY restrictions (source)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
+ "type": "github"
+ },
+ {
+ "name": "USDY Contract",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
+ "evidence": [
+ {
+ "name": "No Censorship Capability",
+ "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Source code (ondo-v1)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "at_risk",
+ "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
+ "evidence": [
+ {
+ "name": "Product Economics vs ONDO Holder Accrual",
+ "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "at_risk",
+ "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
+ "evidence": [
+ {
+ "name": "No Treasury Identified",
+ "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
+ "urls": [
+ {
+ "name": "Ondo DAO Proposals",
+ "url": "https://www.tally.xyz/gov/ondo-dao",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "at_risk",
+ "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY Price Oracles (Company-Controlled)",
+ "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
+ "urls": [
+ {
+ "name": "OUSG Oracle",
+ "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Oracle",
+ "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
+ "type": "explorer"
+ },
+ {
+ "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
+ "type": "github"
+ },
+ {
+ "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Company-Controlled via TimelockController)",
+ "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "warning",
+ "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
+ "tags": ["Reference"],
+ "evidence": [
+ {
+ "name": "Ondo Product Economics",
+ "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Issuer / Ondo Finance Relationship",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets Revenue",
+ "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
+ "urls": [
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ONDO Token (Etherscan verified)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY GitHub",
+ "url": "https://github.com/ondoprotocol/usdy",
+ "type": "github"
+ },
+ {
+ "name": "Audit code (Code4rena)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDonManager",
+ "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "at_risk",
+ "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
+ "evidence": [
+ {
+ "name": "Team Holdings",
+ "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
+ "urls": [
+ {
+ "name": "Team Multisig holdings",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "warning",
+ "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
+ "evidence": [
+ {
+ "name": "Documented Schedule",
+ "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
+ "urls": [
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ },
+ {
+ "name": "CoinList - ONDO Community Sale",
+ "url": "https://coinlist.co/ondo",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Proprietary Rights",
+ "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Interface Services",
+ "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
+ "evidence": [
+ {
+ "name": "BUSL-1.1 Source Headers",
+ "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
+ "urls": [
+ {
+ "name": "USDY source SPDX header",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "rOUSG source SPDX header",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "BUSL-1.1 license text",
+ "url": "https://spdx.org/licenses/BUSL-1.1.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "ondo",
+ "passing": 4,
+ "total": 15,
+ "percentage": 26.666666666666668,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 2,
+ "total": 7,
+ "percentage": 28.57142857142857,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/sky.json b/src/data/generated/tokens/sky.json
new file mode 100644
index 0000000..c1a3c8e
--- /dev/null
+++ b/src/data/generated/tokens/sky.json
@@ -0,0 +1,641 @@
+{
+ "id": "sky",
+ "coingeckoId": "sky",
+ "name": "SKY",
+ "symbol": "SKY",
+ "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
+ "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
+ "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://sky.money/",
+ "twitter": "https://twitter.com/SkyEcosystem",
+ "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
+ },
+ "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable).",
+ "positive": 13,
+ "neutral": 1,
+ "atRisk": 0,
+ "evidenceEntries": 25,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
+ "evidence": [
+ {
+ "name": "Governance Workflow",
+ "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
+ "urls": [
+ {
+ "name": "Voting Contract",
+ "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "plot() delay enforcement (L111-116)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Timelock Contract",
+ "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
+ "urls": [
+ {
+ "name": "Pause Proxy (Etherscan)",
+ "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "exec() function (L124-136)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
+ "evidence": [
+ {
+ "name": "Core Contracts Controlled by Governance",
+ "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
+ "urls": [
+ {
+ "name": "Vat wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Vow wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "SKY wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Controls",
+ "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
+ "urls": [
+ {
+ "name": "Mom authority pattern (source)",
+ "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
+ "type": "github"
+ },
+ {
+ "name": "OSM_MOM — verify authority()",
+ "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
+ "evidence": [
+ {
+ "name": "Immutable Core",
+ "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
+ "urls": [
+ {
+ "name": "Vat source code",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
+ "type": "github"
+ },
+ {
+ "name": "SKY token source code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Stablecoins",
+ "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
+ "urls": [
+ {
+ "name": "USDS upgrade authorization",
+ "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
+ "type": "github"
+ },
+ {
+ "name": "sUSDS source code",
+ "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Token",
+ "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
+ "urls": [
+ {
+ "name": "SKY Token Contract",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
+ "evidence": [
+ {
+ "name": "Minting Restricted to Governance",
+ "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
+ "urls": [
+ {
+ "name": "mint() function (L146-154)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "MKR Conversion",
+ "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
+ "urls": [
+ {
+ "name": "rate() returns 24000",
+ "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Immutable rate declaration",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
+ "evidence": [
+ {
+ "name": "Emergency Shutdown",
+ "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
+ "urls": [
+ {
+ "name": "ESM source code",
+ "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
+ "type": "github"
+ },
+ {
+ "name": "ESM contract on Etherscan",
+ "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "No Arbitrary Pause",
+ "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
+ "urls": []
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
+ "evidence": [
+ {
+ "name": "No Censorship Functions",
+ "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
+ "urls": [
+ {
+ "name": "Transfer Functions (L96-135)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
+ "evidence": [
+ {
+ "name": "Smart Burn Engine",
+ "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
+ "urls": [
+ {
+ "name": "Splitter contract",
+ "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper (buyback executor)",
+ "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper source code",
+ "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
+ "type": "github"
+ },
+ {
+ "name": "Smart Burn Engine Dashboard",
+ "url": "https://info.sky.money/smart-burn-engine",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
+ "urls": [
+ {
+ "name": "Stability fee accrual",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
+ "type": "github"
+ },
+ {
+ "name": "Surplus routing to flapper",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
+ "evidence": [
+ {
+ "name": "Onchain Treasury",
+ "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
+ "evidence": [
+ {
+ "name": "Fee Rate Control",
+ "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
+ "urls": [
+ {
+ "name": "Jug fee configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
+ "type": "github"
+ },
+ {
+ "name": "Jug contract",
+ "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Surplus Buffer Control",
+ "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
+ "urls": [
+ {
+ "name": "Vow hump configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
+ "type": "github"
+ },
+ {
+ "name": "Vow contract — read hump",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
+ "tags": ["Reference"],
+ "evidence": [
+ {
+ "name": "Foundation Independence",
+ "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
+ "urls": [
+ {
+ "name": "Foundation Mandate",
+ "url": "https://daifoundation.org/mandate",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
+ "evidence": [
+ {
+ "name": "Verified Source",
+ "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
+ "urls": [
+ {
+ "name": "Source Code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ },
+ {
+ "name": "Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
+ "evidence": [
+ {
+ "name": "Open Source Repositories",
+ "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
+ "urls": [
+ {
+ "name": "Core Protocol",
+ "url": "https://github.com/sky-ecosystem/dss",
+ "type": "github"
+ },
+ {
+ "name": "Contract Registry",
+ "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "Aragon has not been able to verify the concentration of holdings.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify the concentration of holdings.",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "unevaluated",
+ "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
+ "evidence": [
+ {
+ "name": "Vesting Contracts",
+ "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
+ "urls": [
+ {
+ "name": "Vest Contract",
+ "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
+ "evidence": [
+ {
+ "name": "Skybase International Terms of Use",
+ "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "DAI Foundation",
+ "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
+ "urls": [
+ {
+ "name": "Foundation Website",
+ "url": "https://daifoundation.org",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
+ "evidence": [
+ {
+ "name": "Open Source Frontends",
+ "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
+ "urls": [
+ {
+ "name": "Governance Portal Source",
+ "url": "https://github.com/sky-ecosystem/governance-portal-v2",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "positive",
+ "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
+ "evidence": [
+ {
+ "name": "AGPL-3.0 License",
+ "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
+ "urls": [
+ {
+ "name": "License File",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "sky",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/uni.json b/src/data/generated/tokens/uni.json
new file mode 100644
index 0000000..dc27c22
--- /dev/null
+++ b/src/data/generated/tokens/uni.json
@@ -0,0 +1,636 @@
+{
+ "id": "uni",
+ "coingeckoId": "uniswap",
+ "name": "UNI",
+ "symbol": "UNI",
+ "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
+ "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
+ "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://uniswap.org/",
+ "twitter": "https://twitter.com/uniswap",
+ "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
+ },
+ "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains.",
+ "positive": 13,
+ "neutral": 3,
+ "atRisk": 0,
+ "evidenceEntries": 25,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
+ "evidence": [
+ {
+ "name": "V2 Factory",
+ "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
+ "urls": [
+ {
+ "name": "V2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Factory",
+ "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
+ "urls": [
+ {
+ "name": "V3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V4 PoolManager",
+ "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
+ "urls": [
+ {
+ "name": "V4PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "UNI Token",
+ "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
+ "urls": [
+ {
+ "name": "UNI Token",
+ "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock (deployed minter)",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
+ "evidence": [
+ {
+ "name": "Non-upgradeable Protocol Contracts",
+ "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
+ "urls": [
+ {
+ "name": "V2 Factory Create2",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
+ "type": "github"
+ },
+ {
+ "name": "V3 Pool Protection",
+ "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
+ "type": "github"
+ },
+ {
+ "name": "V4 PoolManager: Singleton",
+ "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Governance Contract",
+ "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol Source",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ },
+ {
+ "name": "Etherscan",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
+ "evidence": [
+ {
+ "name": "Inflation Cap",
+ "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
+ "urls": [
+ {
+ "name": "Mint once per year logic",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
+ "type": "github"
+ },
+ {
+ "name": "2% mint cap",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Control",
+ "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
+ "evidence": []
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
+ "evidence": [
+ {
+ "name": "V2 Fees",
+ "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
+ "urls": [
+ {
+ "name": "UniswapV2Pool: feeTo",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Pool: Fee Destination",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fees",
+ "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
+ "urls": [
+ {
+ "name": "V3FeeAdapter",
+ "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: collectProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fees",
+ "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
+ "urls": [
+ {
+ "name": "V4 PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ },
+ {
+ "name": "V4 PoolManager: CollectProtocolFees",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Burn Mechanism",
+ "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
+ "urls": [
+ {
+ "name": "FirePit 4000 UNI Requirement",
+ "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
+ "evidence": [
+ {
+ "name": "V2 Fee Control",
+ "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fee Control",
+ "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
+ "urls": [
+ {
+ "name": "UniswapV3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: setFeeProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fee Control",
+ "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
+ "urls": [
+ {
+ "name": "PoolManager(V4): setProtocolFee",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "DUNI Proposal",
+ "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UNI Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Uni.sol Source (GitHub)",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap V2 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v2-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V3 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v3-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V4 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v4-core",
+ "type": "github"
+ },
+ {
+ "name": "UniswapX (GitHub)",
+ "url": "https://github.com/Uniswap/UniswapX",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "positive",
+ "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
+ "evidence": [
+ {
+ "name": "TreasuryVester Contracts",
+ "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
+ "urls": [
+ {
+ "name": "TreasuryVester Code",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
+ "type": "github"
+ },
+ {
+ "name": "TreasuryVester 1",
+ "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 2",
+ "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 3",
+ "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 4",
+ "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Trademark Guidelines",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Terms of Service",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
+ "evidence": []
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "uni",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/data/generated/tokens/yb.json b/src/data/generated/tokens/yb.json
new file mode 100644
index 0000000..530ab94
--- /dev/null
+++ b/src/data/generated/tokens/yb.json
@@ -0,0 +1,603 @@
+{
+ "id": "yb",
+ "coingeckoId": "yield-basis",
+ "name": "YB",
+ "symbol": "YB",
+ "address": "0x01791F726B4103694969820be083196cC7c045fF",
+ "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
+ "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://yieldbasis.com/",
+ "twitter": "https://x.com/yieldbasis",
+ "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
+ },
+ "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision.",
+ "positive": 11,
+ "neutral": 4,
+ "atRisk": 1,
+ "evidenceEntries": 18,
+ "metrics": [
+ {
+ "id": "onchain-ctrl",
+ "name": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
+ "tags": ["Metric 1"],
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
+ "status": "positive",
+ "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
+ "evidence": [
+ {
+ "name": "Governance System",
+ "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
+ "urls": [
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB (VotingEscrow)",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "TokenVoting Plugin",
+ "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.yieldbasis.com/user/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
+ "status": "positive",
+ "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
+ "evidence": [
+ {
+ "name": "DAO-Controlled Contracts",
+ "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
+ "urls": [
+ {
+ "name": "GaugeController",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ },
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "MigrationFactoryOwner",
+ "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "veYB Owner (_yb.eth)",
+ "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "set_transfer_clearance_checker",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
+ "status": "positive",
+ "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
+ "urls": [
+ {
+ "name": "Factory Contract",
+ "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
+ "type": "explorer"
+ },
+ {
+ "name": "Factory.set_implementations",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
+ "type": "github"
+ },
+ {
+ "name": "MigrationFactoryOwner ADMIN immutable",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
+ "status": "positive",
+ "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
+ "evidence": [
+ {
+ "name": "Token Ownership",
+ "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
+ "urls": [
+ {
+ "name": "YB Token Contract",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "renounce_ownership",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
+ "status": "positive",
+ "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
+ "evidence": [
+ {
+ "name": "Emission Mechanism",
+ "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
+ "urls": [
+ {
+ "name": "get_adjustment (minting rate)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
+ "type": "github"
+ },
+ {
+ "name": "YB.emit function",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
+ "type": "github"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
+ "status": "positive",
+ "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
+ "evidence": [
+ {
+ "name": "Exit Paths",
+ "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
+ "urls": [
+ {
+ "name": "VotingEscrow.withdraw",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor.claim",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
+ "status": "positive",
+ "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB.vy full source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual",
+ "name": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
+ "tags": ["Metric 2"],
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
+ "status": "positive",
+ "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
+ "evidence": [
+ {
+ "name": "Fee Flow",
+ "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
+ "urls": [
+ {
+ "name": "LT.withdraw_admin_fees",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
+ "type": "github"
+ },
+ {
+ "name": "Factory.fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor Contract",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB Documentation",
+ "url": "https://docs.yieldbasis.com/user/veyb",
+ "type": "docs"
+ },
+ {
+ "name": "Fee Data (ValueVerse)",
+ "url": "https://yb.valueverse.ai",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
+ "status": "at_risk",
+ "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
+ "evidence": [
+ {
+ "name": "Ecosystem Reserve",
+ "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
+ "urls": [
+ {
+ "name": "Ecosystem Reserve",
+ "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
+ "type": "explorer"
+ },
+ {
+ "name": "Ecosystem Reserve Owner (EOA)",
+ "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
+ "type": "explorer"
+ },
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "status": "positive",
+ "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
+ "evidence": [
+ {
+ "name": "Fee Flow Direction",
+ "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
+ "urls": [
+ {
+ "name": "MigrationFactoryOwner.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
+ "type": "github"
+ },
+ {
+ "name": "Factory.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
+ "urls": [
+ {
+ "name": "vote_for_gauge_weights",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
+ "type": "github"
+ },
+ {
+ "name": "GaugeController Contract",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
+ "tags": ["Reference"],
+ "evidence": []
+ }
+ ]
+ },
+ {
+ "id": "verifiability",
+ "name": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
+ "tags": ["Metric 3"],
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
+ "status": "positive",
+ "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB Token Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "YB.vy Source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
+ "status": "positive",
+ "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
+ "evidence": [
+ {
+ "name": "Verification and Audits",
+ "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
+ "urls": [
+ {
+ "name": "yb-core GitHub Repository",
+ "url": "https://github.com/yield-basis/yb-core",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution",
+ "name": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
+ "tags": ["Metric 4"],
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
+ "status": "warning",
+ "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
+ "evidence": [
+ {
+ "name": "veYB Supply",
+ "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
+ "status": "warning",
+ "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
+ "urls": [
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
+ "tags": ["Reference"],
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify trademark ownership.",
+ "evidence": []
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YieldBasis Website",
+ "url": "https://yieldbasis.com/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
+ "status": "warning",
+ "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
+ "evidence": [
+ {
+ "name": "License Analysis",
+ "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
+ "urls": [
+ {
+ "name": "yb-core contracts directory",
+ "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Curve Licensing Vesting",
+ "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "score": {
+ "tokenId": "yb",
+ "passing": 11,
+ "total": 14,
+ "percentage": 78.57142857142857,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 2,
+ "total": 3,
+ "percentage": 66.66666666666666,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/src/lib/data-fetcher.ts b/src/lib/data-fetcher.ts
deleted file mode 100644
index 2adeb38..0000000
--- a/src/lib/data-fetcher.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * GitHub Data Fetcher
- *
- * Fetches data files from GitHub repository for dynamic data updates
- * without requiring app redeployment.
- */
-
-// Data source configuration
-export const DATA_SOURCES = {
- tokens: {
- owner: "aragon",
- repo: "ownership-token-index-framework",
- branch: "develop",
- path: "data/tokens.json",
- },
- metrics: {
- owner: "aragon",
- repo: "ownership-token-index-framework",
- branch: "develop",
- path: "data/metrics.json",
- },
- framework: {
- owner: "aragon",
- repo: "ownership-token-index-framework",
- branch: "develop",
- path: "data/framework.json",
- },
- faq: {
- owner: "aragon",
- repo: "ownership-token-index-framework",
- branch: "develop",
- path: "data/faq.json",
- },
-} as const
-
-export type DataSourceKey = keyof typeof DATA_SOURCES
-
-// In-memory cache
-const dataCache = new Map()
-
-// Cache duration (5 minutes)
-const CACHE_DURATION_MS = 5 * 60 * 1000
-
-/**
- * Build GitHub raw content URL from data source config
- */
-function buildGitHubRawUrl(
- source: (typeof DATA_SOURCES)[DataSourceKey]
-): string {
- return `https://raw.githubusercontent.com/${source.owner}/${source.repo}/${source.branch}/${source.path}`
-}
-
-/**
- * Check if cached data is still valid
- */
-function isCacheValid(cacheEntry: { timestamp: number } | undefined): boolean {
- if (!cacheEntry) return false
- return Date.now() - cacheEntry.timestamp < CACHE_DURATION_MS
-}
-
-/**
- * Fetch data from GitHub with caching
- *
- * @param sourceKey - The data source key from DATA_SOURCES
- * @param options - Fetch options
- * @returns Parsed JSON data
- *
- * @example
- * const tokens = await fetchGitHubData('tokens')
- * const metrics = await fetchGitHubData('metrics', { cache: 'no-store' })
- */
-export async function fetchGitHubData(
- sourceKey: DataSourceKey,
- options?: {
- /** Bypass cache and force fresh fetch */
- bypassCache?: boolean
- /** Additional fetch options */
- fetchOptions?: RequestInit
- }
-): Promise {
- const source = DATA_SOURCES[sourceKey]
- const url = buildGitHubRawUrl(source)
- const cacheKey = url
-
- // Check cache first (unless bypassed)
- if (!options?.bypassCache) {
- const cached = dataCache.get(cacheKey)
- if (cached && isCacheValid(cached)) {
- return cached.data as T
- }
- }
-
- try {
- // Fetch from GitHub
- const response = await fetch(url, {
- ...options?.fetchOptions,
- headers: {
- Accept: "application/json",
- ...options?.fetchOptions?.headers,
- },
- })
-
- if (!response.ok) {
- throw new Error(
- `Failed to fetch ${sourceKey} from GitHub: ${response.status} ${response.statusText}`
- )
- }
-
- const data = (await response.json()) as T
-
- // Update cache
- dataCache.set(cacheKey, {
- data,
- timestamp: Date.now(),
- })
-
- return data
- } catch (error) {
- // If fetch fails and we have stale cache, return it
- const staleCache = dataCache.get(cacheKey)
- if (staleCache) {
- console.warn(
- `Failed to fetch fresh data for ${sourceKey}, using stale cache`,
- error
- )
- return staleCache.data as T
- }
-
- throw error
- }
-}
-
-/**
- * Clear cache for a specific data source or all sources
- */
-export function clearDataCache(sourceKey?: DataSourceKey): void {
- if (sourceKey) {
- const source = DATA_SOURCES[sourceKey]
- const url = buildGitHubRawUrl(source)
- dataCache.delete(url)
- } else {
- dataCache.clear()
- }
-}
-
-/**
- * Prefetch all data sources (useful for build time or app initialization)
- */
-export async function prefetchAllData(): Promise {
- const keys = Object.keys(DATA_SOURCES) as DataSourceKey[]
- await Promise.all(keys.map((key) => fetchGitHubData(key)))
-}
-
-/**
- * Get cache statistics
- */
-export function getCacheStats() {
- return {
- size: dataCache.size,
- entries: Array.from(dataCache.entries()).map(([url, entry]) => ({
- url,
- age: Date.now() - entry.timestamp,
- valid: isCacheValid(entry),
- })),
- }
-}
diff --git a/src/lib/faq-data.ts b/src/lib/faq-data.ts
index 3579560..207c558 100644
--- a/src/lib/faq-data.ts
+++ b/src/lib/faq-data.ts
@@ -1,19 +1,8 @@
-import faqData from "@/data/faq.json"
+import faqData from "@/data/generated/faq.json"
+import type { FaqQuestion, FaqTopic } from "@/lib/schemas"
-export interface FaqQuestion {
- id: string
- question: string
- answer: string
-}
-
-export interface FaqTopic {
- id: string
- name: string
- about?: string
- questions: FaqQuestion[]
-}
+export type { FaqQuestion, FaqTopic }
export function getFaqTopics(): FaqTopic[] {
- const baseTopics = faqData.topics as FaqTopic[]
- return baseTopics
+ return faqData.topics as FaqTopic[]
}
diff --git a/src/lib/framework.ts b/src/lib/framework.ts
index 3786650..0d9e38a 100644
--- a/src/lib/framework.ts
+++ b/src/lib/framework.ts
@@ -1,37 +1,18 @@
-import frameworkData from "@/data/framework.json"
+import frameworkData from "@/data/generated/framework.json"
+import type { FrameworkDoc } from "@/lib/schemas"
-export interface FrameworkMetric {
- id: string
- name: string
- about: string
- criteria: FrameworkCriteria[]
-}
-
-export interface FrameworkCriteria {
- id: string
- name: string
- about: string
-}
+const framework = frameworkData as FrameworkDoc
-export const FRAMEWORK_BASE_URL =
- "https://github.com/aragon/ownership-token-framework/blob/development/README.md"
+export type FrameworkMetric = FrameworkDoc["metrics"][number]
+export type FrameworkCriteria = FrameworkMetric["criteria"][number]
-/**
- * Map metric IDs to their corresponding README section anchors
- */
-const METRIC_ANCHORS: Record = {
- "onchain-ctrl": "#metric-1-onchain-control",
- "val-accrual": "#metric-2-value-accrual",
- verifiability: "#metric-3-verifiability",
- distribution: "#metric-4-token-distribution",
- offchain: "#offchain-dependencies",
-}
+export const FRAMEWORK_BASE_URL = framework.baseUrl
/**
* Get framework metric definition by ID
*/
export function getFrameworkMetric(metricId: string): FrameworkMetric | null {
- const metric = frameworkData.find((m) => m.id === metricId)
+ const metric = framework.metrics.find((m) => m.id === metricId)
return metric || null
}
@@ -41,7 +22,7 @@ export function getFrameworkMetric(metricId: string): FrameworkMetric | null {
export function getFrameworkCriteria(
criteriaId: string
): FrameworkCriteria | null {
- for (const metric of frameworkData) {
+ for (const metric of framework.metrics) {
const criteria = metric.criteria.find((c) => c.id === criteriaId)
if (criteria) return criteria
}
@@ -52,13 +33,13 @@ export function getFrameworkCriteria(
* Get all framework metrics
*/
export function getAllFrameworkMetrics(): FrameworkMetric[] {
- return frameworkData
+ return framework.metrics
}
/**
* Get the framework URL for a specific metric, with anchor to its section
*/
export function getFrameworkUrl(metricId: string): string {
- const anchor = METRIC_ANCHORS[metricId]
+ const anchor = getFrameworkMetric(metricId)?.anchor
return anchor ? `${FRAMEWORK_BASE_URL}${anchor}` : FRAMEWORK_BASE_URL
}
diff --git a/src/lib/metrics-data.ts b/src/lib/metrics-data.ts
index c399f9a..0fcec29 100644
--- a/src/lib/metrics-data.ts
+++ b/src/lib/metrics-data.ts
@@ -1,21 +1,32 @@
-import metricsData from "@/data/metrics.json"
-import { getFrameworkCriteria, getFrameworkMetric } from "@/lib/framework"
-import type { EvidenceLinkType } from "../components/ui/evidence-link.tsx"
-
-export const CRITERIA_STATUS = {
- POSITIVE: "positive",
- WARNING: "warning",
- AT_RISK: "at_risk",
- UNEVALUATED: "unevaluated",
- REFERENCE: "reference",
-} as const
-
-export type CriteriaStatusValue =
- (typeof CRITERIA_STATUS)[keyof typeof CRITERIA_STATUS]
+import {
+ type ComposedCriterion,
+ type ComposedMetric,
+ CRITERIA_STATUS,
+ type CriteriaStatusValue,
+ type Evidence,
+ type EvidenceUrl,
+ type TokenDoc,
+} from "@/lib/schemas"
+
+export { CRITERIA_STATUS }
+export type { CriteriaStatusValue, Evidence, EvidenceUrl }
+export type Criteria = ComposedCriterion
+export type Metric = ComposedMetric
+
+const tokenDocModules = import.meta.glob<{ default: TokenDoc }>(
+ "../data/generated/tokens/*.json",
+ { eager: true }
+)
+
+const tokenDocs = new Map(
+ Object.values(tokenDocModules).map((mod) => [mod.default.id, mod.default])
+)
+
+export function getTokenDoc(tokenId: string): TokenDoc | null {
+ return tokenDocs.get(tokenId.trim().toLowerCase()) ?? null
+}
-export function normalizeCriteriaStatus(
- status?: string
-): CriteriaStatusValue {
+export function normalizeCriteriaStatus(status?: string): CriteriaStatusValue {
if (
status === CRITERIA_STATUS.POSITIVE ||
status === CRITERIA_STATUS.WARNING ||
@@ -28,44 +39,13 @@ export function normalizeCriteriaStatus(
return CRITERIA_STATUS.REFERENCE
}
-export interface EvidenceUrl {
- name: string
- url: string
- type?: EvidenceLinkType
-}
-
-export interface Evidence {
- name?: string
- summary?: string
- urls: EvidenceUrl[]
-}
-
-export interface Criteria {
- id: string
- name: string
- about: string
- status: string
- notes: string
- tags?: string[]
- evidence: EvidenceUrl[] | Evidence[]
-}
-
-export interface Metric {
- id: string
- name: string
- about: string
- summary: string
- tags?: string[]
- criteria: Criteria[]
-}
-
export function getCriteriaStatus(
tokenId: string,
criteriaId: string
): CriteriaStatusValue {
- const metrics = metricsData[tokenId as keyof typeof metricsData]
- if (!metrics) return CRITERIA_STATUS.REFERENCE
- for (const m of metrics as Metric[]) {
+ const doc = getTokenDoc(tokenId)
+ if (!doc) return CRITERIA_STATUS.REFERENCE
+ for (const m of doc.metrics) {
for (const c of m.criteria) {
if (c.id === criteriaId) return normalizeCriteriaStatus(c.status)
}
@@ -74,23 +54,5 @@ export function getCriteriaStatus(
}
export function getMetricsByTokenId(tokenId: string): Metric[] {
- const metrics = metricsData[tokenId as keyof typeof metricsData]
- if (!metrics) return []
-
- return (metrics as Metric[]).map((metric) => {
- const frameworkMetric = getFrameworkMetric(metric.id)
-
- return {
- ...metric,
- about: frameworkMetric?.about || metric.about,
- criteria: metric.criteria.map((criteria) => {
- const frameworkCriteria = getFrameworkCriteria(criteria.id)
-
- return {
- ...criteria,
- about: frameworkCriteria?.about || criteria.about,
- }
- }),
- }
- })
+ return getTokenDoc(tokenId)?.metrics ?? []
}
diff --git a/src/lib/schemas/atoms.ts b/src/lib/schemas/atoms.ts
new file mode 100644
index 0000000..3ff105b
--- /dev/null
+++ b/src/lib/schemas/atoms.ts
@@ -0,0 +1,121 @@
+/**
+ * Write-model schemas — the editable atoms under `content/`.
+ *
+ * Atoms are research-shaped: small, flat, id-keyed. Anything derivable
+ * (status counts, scores, framework-owned `about` text) is intentionally
+ * absent and produced at composition time (scripts/compose-data.mjs).
+ */
+import { z } from "zod"
+import { evidenceSchema, rawCriteriaStatusSchema } from "./common"
+
+/** content/tokens/.json — registry atom: identity, display, chain data. */
+export const tokenAtomSchema = z.strictObject({
+ id: z.string(),
+ coingeckoId: z.string(),
+ name: z.string(),
+ symbol: z.string(),
+ address: z.string(),
+ icon: z.string(),
+ description: z.string(),
+ infoDescription: z.string(),
+ network: z.string(),
+ links: z.strictObject({
+ website: z.string(),
+ twitter: z.string(),
+ scan: z.string(),
+ }),
+ /** Editorial provenance; future home is Git history (publish pipeline). */
+ lastUpdated: z.number(),
+ updatedBy: z.strictObject({
+ name: z.string(),
+ avatar: z.string(),
+ }),
+})
+
+/** content/evaluations///_metric.json — per-token metric editorial. */
+export const metricEditorialAtomSchema = z.strictObject({
+ summary: z.string(),
+ tags: z.array(z.string()),
+})
+
+/** content/evaluations///.json */
+export const criterionEvaluationAtomSchema = z.strictObject({
+ /** Display-name override; present only where it diverges from framework. */
+ name: z.string().optional(),
+ status: rawCriteriaStatusSchema,
+ notes: z.string(),
+ tags: z.array(z.string()).optional(),
+ evidence: z.array(evidenceSchema).optional(),
+})
+
+/** content/framework/.json — canonical metric definition. */
+export const frameworkCriterionSchema = z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ about: z.string(),
+})
+
+export const frameworkMetricAtomSchema = z.strictObject({
+ id: z.string(),
+ /** Formal framework name (e.g. "Metric 1: Onchain Control"). */
+ name: z.string(),
+ /** Clean display name used in composed token docs (e.g. "Onchain Control"). */
+ displayName: z.string(),
+ about: z.string(),
+ /** README section anchor for getFrameworkUrl; absent → base URL only. */
+ anchor: z.string().optional(),
+ criteria: z.array(frameworkCriterionSchema),
+})
+
+/** content/framework/_meta.json — framework-wide constants. */
+export const frameworkMetaSchema = z.strictObject({
+ baseUrl: z.string(),
+ /** Canonical metric ordering for composed docs. */
+ order: z.array(z.string()),
+})
+
+/** content/faq.json */
+export const faqQuestionSchema = z.strictObject({
+ id: z.string(),
+ question: z.string(),
+ answer: z.string(),
+})
+
+export const faqTopicSchema = z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ about: z.string().optional(),
+ questions: z.array(faqQuestionSchema),
+})
+
+export const faqSchema = z.strictObject({
+ topics: z.array(faqTopicSchema),
+})
+
+/** content/testimonials.json */
+export const testimonialSchema = z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ organization: z.string(),
+ avatar: z.string(),
+ url: z.string(),
+ quote: z.string(),
+})
+
+export const testimonialsSchema = z.strictObject({
+ title: z.string(),
+ testimonials: z.array(testimonialSchema),
+})
+
+export type TokenAtom = z.infer
+export type MetricEditorialAtom = z.infer
+export type CriterionEvaluationAtom = z.infer<
+ typeof criterionEvaluationAtomSchema
+>
+export type FrameworkCriterion = z.infer
+export type FrameworkMetricAtom = z.infer
+export type FrameworkMeta = z.infer
+export type FaqQuestion = z.infer
+export type FaqTopic = z.infer
+export type Testimonial = z.infer
+export type TestimonialsContent = z.infer
diff --git a/src/lib/schemas/common.ts b/src/lib/schemas/common.ts
new file mode 100644
index 0000000..beb00af
--- /dev/null
+++ b/src/lib/schemas/common.ts
@@ -0,0 +1,53 @@
+import { z } from "zod"
+
+/** Canonical criteria workflow statuses. */
+export const CRITERIA_STATUS = {
+ POSITIVE: "positive",
+ WARNING: "warning",
+ AT_RISK: "at_risk",
+ UNEVALUATED: "unevaluated",
+ REFERENCE: "reference",
+} as const
+
+export type CriteriaStatusValue =
+ (typeof CRITERIA_STATUS)[keyof typeof CRITERIA_STATUS]
+
+export const criteriaStatusSchema = z.enum([
+ CRITERIA_STATUS.POSITIVE,
+ CRITERIA_STATUS.WARNING,
+ CRITERIA_STATUS.AT_RISK,
+ CRITERIA_STATUS.UNEVALUATED,
+ CRITERIA_STATUS.REFERENCE,
+])
+
+/**
+ * Statuses as they actually appear in the data, including legacy values
+ * ("fail", "partial") that normalize to "reference" at read time and are
+ * excluded from scoring. Preserved as passthrough pending editorial cleanup.
+ */
+export const rawCriteriaStatusSchema = z.enum([
+ CRITERIA_STATUS.POSITIVE,
+ CRITERIA_STATUS.WARNING,
+ CRITERIA_STATUS.AT_RISK,
+ CRITERIA_STATUS.UNEVALUATED,
+ CRITERIA_STATUS.REFERENCE,
+ "fail",
+ "partial",
+])
+
+export type RawCriteriaStatus = z.infer
+
+export const evidenceUrlSchema = z.strictObject({
+ name: z.string(),
+ url: z.string(),
+ type: z.enum(["docs", "explorer", "github", "vote", "website"]).optional(),
+})
+
+export const evidenceSchema = z.strictObject({
+ name: z.string().optional(),
+ summary: z.string().optional(),
+ urls: z.array(evidenceUrlSchema),
+})
+
+export type EvidenceUrl = z.infer
+export type Evidence = z.infer
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
new file mode 100644
index 0000000..39aa441
--- /dev/null
+++ b/src/lib/schemas/index.ts
@@ -0,0 +1,10 @@
+/**
+ * OTF data contract — Zod schemas for the write model (content/ atoms) and
+ * the read models (src/data/generated/ composed docs).
+ *
+ * This module must not import app code: it is designed to extract cleanly
+ * into a shared package if content moves to a separate repo (otf-cms).
+ */
+export * from "./atoms"
+export * from "./common"
+export * from "./read-models"
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
new file mode 100644
index 0000000..5ebb660
--- /dev/null
+++ b/src/lib/schemas/read-models.ts
@@ -0,0 +1,116 @@
+/**
+ * Read-model schemas — the composed, consumer-shaped output under
+ * `src/data/generated/` (produced by scripts/compose-data.mjs).
+ *
+ * These are the shapes the app renders and that the future publish
+ * pipeline will serve from KV/R2 — transport changes later, shape doesn't.
+ */
+import { z } from "zod"
+import { tokenAtomSchema } from "./atoms"
+import { evidenceSchema, rawCriteriaStatusSchema } from "./common"
+
+/** A criterion as rendered: framework `about` merged, raw status preserved. */
+export const composedCriterionSchema = z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ about: z.string(),
+ status: rawCriteriaStatusSchema,
+ notes: z.string(),
+ tags: z.array(z.string()).optional(),
+ evidence: z.array(evidenceSchema).optional(),
+})
+
+/** A metric as rendered: display name + framework about + editorial summary. */
+export const composedMetricSchema = z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ about: z.string(),
+ summary: z.string(),
+ tags: z.array(z.string()),
+ criteria: z.array(composedCriterionSchema),
+})
+
+export const metricScoreSchema = z.strictObject({
+ metricId: z.string(),
+ metricName: z.string(),
+ passing: z.number(),
+ total: z.number(),
+ percentage: z.number(),
+ evaluated: z.boolean(),
+ reference: z.boolean(),
+})
+
+export const tokenScoreSchema = z.strictObject({
+ tokenId: z.string(),
+ passing: z.number(),
+ total: z.number(),
+ percentage: z.number(),
+ metrics: z.array(metricScoreSchema),
+})
+
+/**
+ * Derived status counts. NOTE: computed from evaluations at compose time —
+ * the hand-maintained counts in the legacy tokens.json were stale for all
+ * 11 tokens and were dropped in the atom migration.
+ */
+export const tokenCountsSchema = z.strictObject({
+ positive: z.number(),
+ neutral: z.number(),
+ atRisk: z.number(),
+ evidenceEntries: z.number(),
+})
+
+/** generated/index.json row — the dashboard-table read model (legacy Token shape). */
+export const indexRowSchema = z.strictObject({
+ ...tokenAtomSchema.shape,
+ positive: z.number(),
+ neutral: z.number(),
+ atRisk: z.number(),
+ evidenceEntries: z.number(),
+ score: z.strictObject({
+ passing: z.number(),
+ total: z.number(),
+ percentage: z.number(),
+ }),
+})
+
+export const indexSchema = z.strictObject({
+ tokens: z.array(indexRowSchema),
+})
+
+/** generated/tokens/.json — the per-token reusable unit. */
+export const tokenDocSchema = z.strictObject({
+ ...indexRowSchema.shape,
+ metrics: z.array(composedMetricSchema),
+ score: tokenScoreSchema,
+})
+
+/** generated/framework.json — definitions + anchors + base URL. */
+export const frameworkDocSchema = z.strictObject({
+ baseUrl: z.string(),
+ metrics: z.array(
+ z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ displayName: z.string(),
+ about: z.string(),
+ anchor: z.string().optional(),
+ criteria: z.array(
+ z.strictObject({
+ id: z.string(),
+ name: z.string(),
+ about: z.string(),
+ })
+ ),
+ })
+ ),
+})
+
+export type ComposedCriterion = z.infer
+export type ComposedMetric = z.infer
+export type MetricScore = z.infer
+export type TokenScore = z.infer
+export type TokenCounts = z.infer
+export type IndexRow = z.infer
+export type TokenDoc = z.infer
+export type FrameworkDoc = z.infer
diff --git a/src/lib/scoring.ts b/src/lib/scoring.ts
index c21dad4..09aae64 100644
--- a/src/lib/scoring.ts
+++ b/src/lib/scoring.ts
@@ -1,22 +1,7 @@
-import { CRITERIA_STATUS, getMetricsByTokenId, type Metric } from "@/lib/metrics-data"
+import { CRITERIA_STATUS, getTokenDoc, type Metric } from "@/lib/metrics-data"
+import type { MetricScore, TokenScore } from "@/lib/schemas"
-export interface MetricScore {
- metricId: string
- metricName: string
- passing: number
- total: number
- percentage: number
- evaluated: boolean
- reference: boolean
-}
-
-export interface TokenScore {
- tokenId: string
- passing: number
- total: number
- percentage: number
- metrics: MetricScore[]
-}
+export type { MetricScore, TokenScore }
export type ScoreStatus = "passing" | "warning" | "not-evaluated"
@@ -28,6 +13,11 @@ export function getScoreStatus(
return percentage >= 75 ? "passing" : "warning"
}
+/**
+ * Pure per-metric scoring, used at render time by metric cards. The same
+ * logic runs at compose time in scripts/compose-data.mjs (the two are pinned
+ * to each other by the golden round-trip tests).
+ */
export function getMetricScore(metric: Metric): MetricScore {
const reference = metric.tags?.includes("Reference") ?? false
const evaluatedCriteria = metric.criteria.filter(
@@ -54,20 +44,9 @@ export function getMetricScore(metric: Metric): MetricScore {
}
}
+/** Token scores are precomputed at compose time and read off the token doc. */
export function getTokenOwnershipScore(tokenId: string): TokenScore {
- const metrics = getMetricsByTokenId(tokenId)
- const metricScores = metrics.map(getMetricScore)
-
- const scoredMetrics = metricScores.filter((m) => m.evaluated && !m.reference)
- const passing = scoredMetrics.reduce((sum, m) => sum + m.passing, 0)
- const total = scoredMetrics.reduce((sum, m) => sum + m.total, 0)
- const percentage = total > 0 ? (passing / total) * 100 : 0
-
- return {
- tokenId,
- passing,
- total,
- percentage,
- metrics: metricScores,
- }
+ const doc = getTokenDoc(tokenId)
+ if (doc) return doc.score
+ return { tokenId, passing: 0, total: 0, percentage: 0, metrics: [] }
}
diff --git a/src/lib/testimonials-data.ts b/src/lib/testimonials-data.ts
index cbe9ad2..107534f 100644
--- a/src/lib/testimonials-data.ts
+++ b/src/lib/testimonials-data.ts
@@ -1,17 +1,6 @@
-import testimonialsData from "@/data/testimonials.json"
+import testimonialsData from "@/data/generated/testimonials.json"
+import type { Testimonial, TestimonialsContent } from "@/lib/schemas"
-export interface Testimonial {
- id: string
- name: string
- organization: string
- avatar: string
- url: string
- quote: string
-}
-
-interface TestimonialsContent {
- title: string
- testimonials: Testimonial[]
-}
+export type { Testimonial }
export const testimonialsContent = testimonialsData as TestimonialsContent
diff --git a/src/lib/token-data-dynamic.ts b/src/lib/token-data-dynamic.ts
deleted file mode 100644
index 5eaff5f..0000000
--- a/src/lib/token-data-dynamic.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * Token Data with Dynamic GitHub Fetching
- *
- * This is an example of how to refactor token-data.ts to use the GitHub fetcher.
- * Replace the existing token-data.ts with this implementation once data is moved to GitHub.
- */
-
-// Import local data as fallback for development
-import tokensDataLocal from "@/data/tokens.json"
-import { fetchGitHubData } from "@/lib/data-fetcher"
-
-export type Token = (typeof tokensDataLocal.tokens)[number]
-
-interface TokensResponse {
- tokens: Token[]
-}
-
-let cachedTokens: Token[] | null = null
-
-/**
- * Fetch tokens from GitHub or use local fallback
- */
-async function fetchTokens(): Promise {
- // If already cached in memory, return immediately
- if (cachedTokens) return cachedTokens
-
- // Try to fetch from GitHub
- try {
- const data = await fetchGitHubData("tokens")
- cachedTokens = data.tokens
- return cachedTokens
- } catch (error) {
- console.warn(
- "Failed to fetch tokens from GitHub, using local fallback",
- error
- )
- // Fallback to local data
- cachedTokens = tokensDataLocal.tokens as Token[]
- return cachedTokens
- }
-}
-
-function normalizeTokenSymbol(value: string): string {
- return value.trim().toUpperCase()
-}
-
-/**
- * Get all tokens with optional symbol filter from env var
- */
-export async function getTokens(): Promise {
- const allTokens = await fetchTokens()
-
- // Apply env var filter if present
- const envSymbolFilter = normalizeTokenSymbol(
- import.meta.env.VITE_TOKEN_SYMBOL ?? ""
- )
-
- if (!envSymbolFilter) return allTokens
-
- const matchingTokens = allTokens.filter(
- (token) => normalizeTokenSymbol(token.symbol) === envSymbolFilter
- )
-
- return matchingTokens.length > 0 ? matchingTokens : allTokens
-}
-
-/**
- * Get a single token by ID
- */
-export async function getTokenById(tokenId: string): Promise {
- const tokens = await getTokens()
- const normalizedId = tokenId.trim().toLowerCase()
- return tokens.find((token) => token.id.toLowerCase() === normalizedId) ?? null
-}
-
-/**
- * Synchronous versions for backwards compatibility
- * Note: These use the local fallback data and should be deprecated
- */
-export function getTokensSync(): Token[] {
- return tokensDataLocal.tokens as Token[]
-}
-
-export function getTokenByIdSync(tokenId: string): Token | null {
- const normalizedId = tokenId.trim().toLowerCase()
- return (
- (tokensDataLocal.tokens as Token[]).find(
- (token) => token.id.toLowerCase() === normalizedId
- ) ?? null
- )
-}
diff --git a/src/lib/token-data.ts b/src/lib/token-data.ts
index 857327d..005a9c6 100644
--- a/src/lib/token-data.ts
+++ b/src/lib/token-data.ts
@@ -1,8 +1,9 @@
-import tokensData from "@/data/tokens.json"
+import indexData from "@/data/generated/index.json"
+import type { IndexRow } from "@/lib/schemas"
-export type Token = (typeof tokensData.tokens)[number]
+export type Token = IndexRow
-const rawTokens = tokensData.tokens as Token[]
+const rawTokens = indexData.tokens as Token[]
function normalizeTokenSymbol(value: string): string {
return value.trim().toUpperCase()
diff --git a/tests/atoms-valid.test.ts b/tests/atoms-valid.test.ts
new file mode 100644
index 0000000..2f9bb84
--- /dev/null
+++ b/tests/atoms-valid.test.ts
@@ -0,0 +1,106 @@
+/**
+ * Schema validation: every atom under content/ and every composed read model
+ * under src/data/generated/ must parse against the shared Zod contract.
+ */
+import { readdirSync, readFileSync } from "node:fs"
+import { join } from "node:path"
+import { describe, expect, it } from "vitest"
+import {
+ criterionEvaluationAtomSchema,
+ faqSchema,
+ frameworkDocSchema,
+ frameworkMetaSchema,
+ frameworkMetricAtomSchema,
+ indexSchema,
+ metricEditorialAtomSchema,
+ testimonialsSchema,
+ tokenAtomSchema,
+ tokenDocSchema,
+} from "@/lib/schemas"
+
+const root = join(__dirname, "..")
+const content = join(root, "content")
+const generated = join(root, "src", "data", "generated")
+
+const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
+const jsonFiles = (dir: string) =>
+ readdirSync(dir).filter((f) => f.endsWith(".json"))
+
+describe("content/ atoms parse against write-model schemas", () => {
+ it("token atoms", () => {
+ for (const f of jsonFiles(join(content, "tokens"))) {
+ expect(
+ () => tokenAtomSchema.parse(readJson(join(content, "tokens", f))),
+ f
+ ).not.toThrow()
+ }
+ })
+
+ it("framework atoms + meta", () => {
+ for (const f of jsonFiles(join(content, "framework"))) {
+ const schema =
+ f === "_meta.json" ? frameworkMetaSchema : frameworkMetricAtomSchema
+ expect(
+ () => schema.parse(readJson(join(content, "framework", f))),
+ f
+ ).not.toThrow()
+ }
+ })
+
+ it("evaluation atoms", () => {
+ const evals = join(content, "evaluations")
+ for (const tokenId of readdirSync(evals)) {
+ for (const metricId of readdirSync(join(evals, tokenId))) {
+ for (const f of jsonFiles(join(evals, tokenId, metricId))) {
+ const schema =
+ f === "_metric.json"
+ ? metricEditorialAtomSchema
+ : criterionEvaluationAtomSchema
+ expect(
+ () => schema.parse(readJson(join(evals, tokenId, metricId, f))),
+ `${tokenId}/${metricId}/${f}`
+ ).not.toThrow()
+ }
+ }
+ }
+ })
+
+ it("faq + testimonials", () => {
+ expect(() => faqSchema.parse(readJson(join(content, "faq.json")))).not.toThrow()
+ expect(() =>
+ testimonialsSchema.parse(readJson(join(content, "testimonials.json")))
+ ).not.toThrow()
+ })
+})
+
+describe("src/data/generated/ parses against read-model schemas", () => {
+ it("index", () => {
+ expect(() =>
+ indexSchema.parse(readJson(join(generated, "index.json")))
+ ).not.toThrow()
+ })
+
+ it("token docs", () => {
+ for (const f of jsonFiles(join(generated, "tokens"))) {
+ expect(
+ () => tokenDocSchema.parse(readJson(join(generated, "tokens", f))),
+ f
+ ).not.toThrow()
+ }
+ })
+
+ it("framework doc", () => {
+ expect(() =>
+ frameworkDocSchema.parse(readJson(join(generated, "framework.json")))
+ ).not.toThrow()
+ })
+
+ it("faq + testimonials passthrough", () => {
+ expect(() =>
+ faqSchema.parse(readJson(join(generated, "faq.json")))
+ ).not.toThrow()
+ expect(() =>
+ testimonialsSchema.parse(readJson(join(generated, "testimonials.json")))
+ ).not.toThrow()
+ })
+})
diff --git a/tests/freshness.test.ts b/tests/freshness.test.ts
new file mode 100644
index 0000000..d3b3a8a
--- /dev/null
+++ b/tests/freshness.test.ts
@@ -0,0 +1,43 @@
+/**
+ * Freshness gate: the committed src/data/generated/ output must equal what
+ * the composer produces from the current content/ atoms. Fails when someone
+ * edits atoms without re-running `node scripts/compose-data.mjs`.
+ */
+import { readFileSync } from "node:fs"
+import { join } from "node:path"
+import { describe, expect, it } from "vitest"
+// @ts-expect-error untyped .mjs module
+import { composeAll } from "../scripts/compose-data.mjs"
+
+const generated = join(__dirname, "..", "src", "data", "generated")
+const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
+
+describe("generated read models are fresh", () => {
+ const composed = composeAll()
+
+ it("index.json", () => {
+ expect(readJson(join(generated, "index.json"))).toEqual(composed.index)
+ })
+
+ it("token docs", () => {
+ for (const doc of composed.tokenDocs) {
+ expect(
+ readJson(join(generated, "tokens", `${doc.id}.json`)),
+ doc.id
+ ).toEqual(doc)
+ }
+ })
+
+ it("framework.json", () => {
+ expect(readJson(join(generated, "framework.json"))).toEqual(
+ composed.frameworkDoc
+ )
+ })
+
+ it("faq + testimonials", () => {
+ expect(readJson(join(generated, "faq.json"))).toEqual(composed.faq)
+ expect(readJson(join(generated, "testimonials.json"))).toEqual(
+ composed.testimonials
+ )
+ })
+})
diff --git a/tests/golden/faq.json b/tests/golden/faq.json
new file mode 100644
index 0000000..dde2743
--- /dev/null
+++ b/tests/golden/faq.json
@@ -0,0 +1,58 @@
+[
+ {
+ "id": "basics",
+ "name": "Basics",
+ "about": "Core definitions and how to use the framework.",
+ "questions": [
+ {
+ "id": "basics__ownership-token",
+ "question": "What is an ownership token?",
+ "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
+ },
+ {
+ "id": "basics__how-to-use",
+ "question": "How can I use the Ownership Token Framework?",
+ "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
+ }
+ ]
+ },
+ {
+ "id": "methodology",
+ "name": "Methodology",
+ "about": "How evaluation, sourcing, and verification work.",
+ "questions": [
+ {
+ "id": "methodology__evaluation",
+ "question": "How do you evaluate tokens?",
+ "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ },
+ {
+ "id": "methodology__evidence",
+ "question": "How do you source and verify evidence?",
+ "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ }
+ ]
+ },
+ {
+ "id": "participation",
+ "name": "Participation",
+ "about": "How tokens are selected and how to get involved.",
+ "questions": [
+ {
+ "id": "participation__selection",
+ "question": "How do you choose which tokens to feature?",
+ "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
+ },
+ {
+ "id": "participation__listing",
+ "question": "How can I get a token listed?",
+ "answer": "Submit a request (or refer a token) using this [here](submit-token)."
+ },
+ {
+ "id": "participation__contribute",
+ "question": "How can I contribute to this initiative?",
+ "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
+ }
+ ]
+ }
+]
diff --git a/src/data/framework.json b/tests/golden/framework.json
similarity index 100%
rename from src/data/framework.json
rename to tests/golden/framework.json
diff --git a/src/data/metrics.json b/tests/golden/metrics.json
similarity index 95%
rename from src/data/metrics.json
rename to tests/golden/metrics.json
index 25f20e5..3e39ee3 100644
--- a/src/data/metrics.json
+++ b/tests/golden/metrics.json
@@ -3,8 +3,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
"criteria": [
{
@@ -233,8 +235,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
"criteria": [
{
@@ -309,7 +313,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
"evidence": [
@@ -334,7 +338,9 @@
{
"id": "val-accrual__offchain",
"name": "Offchain Value Accrual",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
@@ -345,8 +351,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
"criteria": [
{
@@ -395,8 +403,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
"criteria": [
{
@@ -420,7 +430,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
"criteria": [
@@ -475,8 +487,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
"criteria": [
{
@@ -742,8 +756,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
"criteria": [
{
@@ -844,7 +860,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
"evidence": [
@@ -890,8 +906,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
"criteria": [
{
@@ -945,8 +963,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
"criteria": [
{
@@ -970,7 +990,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
"criteria": [
@@ -1025,8 +1047,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
"criteria": [
{
@@ -1242,8 +1266,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
"criteria": [
{
@@ -1309,7 +1335,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
"evidence": [
@@ -1361,8 +1387,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
"criteria": [
{
@@ -1411,8 +1439,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
"criteria": [
{
@@ -1446,7 +1476,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
"criteria": [
@@ -1501,8 +1533,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
"criteria": [
{
@@ -1804,8 +1838,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
"criteria": [
{
@@ -1875,11 +1911,11 @@
"name": "Treasury Ownership",
"about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
"status": "warning",
- "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap \u2192 sUSDe Payout \u2192 StakingRewardsDistributor \u2192 sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
+ "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
"evidence": [
{
"name": "Revenue Flow",
- "summary": "Protocol Operations (delta-neutral strategies)\n\u2192 **Hot Swap Multisig** (receives revenue, converts to USDe)\n\u2192 **sUSDe Payout Multisig**\n\u2192 **StakingRewardsDistributor**\n\u2192 sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
+ "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
"urls": [
{
"name": "Key Addresses Documentation",
@@ -1919,7 +1955,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "warning",
"notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
"evidence": [
@@ -1998,8 +2034,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
"criteria": [
{
@@ -2104,8 +2142,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
"criteria": [
{
@@ -2166,7 +2206,7 @@
"tags": [
"Reference"
],
- "about": "Economically material assets and obligations often sit offchain, outside the custody and direct enforcement of a token, while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
"criteria": [
{
@@ -2235,8 +2275,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
"criteria": [
{
@@ -2553,8 +2595,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
"criteria": [
{
@@ -2640,7 +2684,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
"evidence": [
@@ -2668,8 +2712,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
"criteria": [
{
@@ -2718,8 +2764,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
"criteria": [
{
@@ -2743,7 +2791,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
"criteria": [
@@ -2833,8 +2883,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
"criteria": [
{
@@ -2935,7 +2987,7 @@
{
"id": "onchain-ctrl__access-gating",
"name": "Access Gating",
- "about": "Evaluates whether privileged roles can selectively restrict user access to the protocol.",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
"status": "positive",
"notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
"evidence": [
@@ -2973,8 +3025,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
"criteria": [
{
@@ -3041,7 +3095,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
"evidence": [
@@ -3064,7 +3118,9 @@
{
"id": "val-accrual__offchain",
"name": "Offchain Value Accrual",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
@@ -3075,8 +3131,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
"criteria": [
{
@@ -3130,8 +3188,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
"criteria": [
{
@@ -3170,7 +3230,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
"criteria": [
@@ -3265,8 +3327,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
"criteria": [
{
@@ -3481,8 +3545,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
"criteria": [
{
@@ -3574,7 +3640,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
"evidence": [
@@ -3646,8 +3712,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
"criteria": [
{
@@ -3711,8 +3779,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "",
"criteria": [
{
@@ -3768,7 +3838,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
"criteria": [
@@ -3823,8 +3895,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
"criteria": [
{
@@ -4041,8 +4115,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
"criteria": [
{
@@ -4123,7 +4199,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
"evidence": [
@@ -4164,7 +4240,9 @@
{
"id": "val-accrual__offchain",
"name": "Offchain Value Accrual",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
@@ -4175,8 +4253,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
"criteria": [
{
@@ -4232,8 +4312,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
"criteria": [
{
@@ -4286,7 +4368,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
"criteria": [
@@ -4348,8 +4432,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
"criteria": [
{
@@ -4591,8 +4677,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
"criteria": [
{
@@ -4669,7 +4757,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "positive",
"notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
"evidence": [
@@ -4710,7 +4798,9 @@
{
"id": "val-accrual__offchain",
"name": "Offchain Value Accrual",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
@@ -4733,8 +4823,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
"criteria": [
{
@@ -4792,8 +4884,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not been able to verify the concentration of holdings.",
"criteria": [
{
@@ -4829,7 +4923,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
"criteria": [
@@ -4911,8 +5007,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
"criteria": [
{
@@ -5158,8 +5256,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
"criteria": [
{
@@ -5245,7 +5345,9 @@
{
"id": "val-accrual__offchain",
"name": "Offchain Value Accrual",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
@@ -5256,8 +5358,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
"criteria": [
{
@@ -5309,8 +5413,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
"criteria": [
{
@@ -5361,7 +5467,9 @@
{
"id": "offchain",
"name": "Offchain Dependencies",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
"criteria": [
@@ -5434,8 +5542,10 @@
{
"id": "onchain-ctrl",
"name": "Onchain Control",
- "tags": ["Metric 1"],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit.",
+ "tags": [
+ "Metric 1"
+ ],
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
"criteria": [
{
@@ -5799,8 +5909,10 @@
{
"id": "val-accrual",
"name": "Value Accrual",
- "tags": ["Metric 2"],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations.",
+ "tags": [
+ "Metric 2"
+ ],
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
"criteria": [
{
@@ -5861,7 +5973,7 @@
{
"id": "val-accrual__mechanism",
"name": "Accrual Mechanism Control",
- "about": "Evaluates whether tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
"status": "at_risk",
"notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
"evidence": [
@@ -5968,8 +6080,10 @@
{
"id": "verifiability",
"name": "Verifiability",
- "tags": ["Metric 3"],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances.",
+ "tags": [
+ "Metric 3"
+ ],
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
"criteria": [
{
@@ -6054,8 +6168,10 @@
{
"id": "distribution",
"name": "Token Distribution",
- "tags": ["Metric 4"],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed.",
+ "tags": [
+ "Metric 4"
+ ],
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
"criteria": [
{
@@ -6116,7 +6232,7 @@
"tags": [
"Reference"
],
- "about": "Economically material assets and obligations often sit offchain, outside the custody and direct enforcement of a token, while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
"criteria": [
{
diff --git a/tests/golden/scores.json b/tests/golden/scores.json
new file mode 100644
index 0000000..48a7426
--- /dev/null
+++ b/tests/golden/scores.json
@@ -0,0 +1,585 @@
+{
+ "aave": {
+ "tokenId": "aave",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "aero": {
+ "tokenId": "aero",
+ "passing": 12,
+ "total": 13,
+ "percentage": 92.3076923076923,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 6,
+ "total": 7,
+ "percentage": 85.71428571428571,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "crv": {
+ "tokenId": "crv",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "ena": {
+ "tokenId": "ena",
+ "passing": 2,
+ "total": 15,
+ "percentage": 13.333333333333334,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 0,
+ "total": 7,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "ldo": {
+ "tokenId": "ldo",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "lqty": {
+ "tokenId": "lqty",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "uni": {
+ "tokenId": "uni",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "yb": {
+ "tokenId": "yb",
+ "passing": 11,
+ "total": 14,
+ "percentage": 78.57142857142857,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 2,
+ "total": 3,
+ "percentage": 66.66666666666666,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "sky": {
+ "tokenId": "sky",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "ethfi": {
+ "tokenId": "ethfi",
+ "passing": 3,
+ "total": 14,
+ "percentage": 21.428571428571427,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 1,
+ "total": 7,
+ "percentage": 14.285714285714285,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 1,
+ "total": 3,
+ "percentage": 33.33333333333333,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "ondo": {
+ "tokenId": "ondo",
+ "passing": 4,
+ "total": 15,
+ "percentage": 26.666666666666668,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 2,
+ "total": 7,
+ "percentage": 28.57142857142857,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ }
+}
diff --git a/tests/golden/testimonials.json b/tests/golden/testimonials.json
new file mode 100644
index 0000000..2846926
--- /dev/null
+++ b/tests/golden/testimonials.json
@@ -0,0 +1,21 @@
+{
+ "title": "Evidence-backed due diligence for investors",
+ "testimonials": [
+ {
+ "id": "miles-a16z",
+ "name": "Miles Jennings",
+ "organization": "a16z",
+ "avatar": "/images/testimonials/miles-jennings.png",
+ "url": "https://a16zcrypto.com/",
+ "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
+ },
+ {
+ "id": "f5-crypto",
+ "name": "Paul Otto",
+ "organization": "F5 Crypto",
+ "avatar": "/images/testimonials/paul-otto.png",
+ "url": "https://f5crypto.com/en/",
+ "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
+ }
+ ]
+}
diff --git a/tests/golden/tokens.json b/tests/golden/tokens.json
new file mode 100644
index 0000000..6da7a95
--- /dev/null
+++ b/tests/golden/tokens.json
@@ -0,0 +1,277 @@
+[
+ {
+ "id": "aave",
+ "coingeckoId": "aave",
+ "name": "AAVE",
+ "symbol": "AAVE",
+ "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
+ "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
+ "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 14,
+ "neutral": 3,
+ "atRisk": 1,
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aave.com/",
+ "twitter": "https://twitter.com/aave",
+ "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
+ },
+ "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
+ },
+ {
+ "id": "aero",
+ "coingeckoId": "aerodrome-finance",
+ "name": "AERO",
+ "symbol": "AERO",
+ "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
+ "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
+ "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
+ "network": "base",
+ "evidenceEntries": 22,
+ "positive": 19,
+ "neutral": 2,
+ "atRisk": 1,
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aerodrome.finance/",
+ "twitter": "https://twitter.com/Aerodrome",
+ "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
+ },
+ "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
+ },
+ {
+ "id": "crv",
+ "coingeckoId": "curve-dao-token",
+ "name": "CRV",
+ "symbol": "CRV",
+ "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
+ "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
+ "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
+ "network": "ethereum",
+ "evidenceEntries": 4,
+ "positive": 4,
+ "neutral": 0,
+ "atRisk": 0,
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://curve.finance/",
+ "twitter": "https://twitter.com/curvefinance",
+ "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
+ },
+ "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
+ },
+ {
+ "id": "ena",
+ "coingeckoId": "ethena",
+ "name": "ENA",
+ "symbol": "ENA",
+ "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
+ "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
+ "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 2,
+ "neutral": 0,
+ "atRisk": 16,
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ethena.fi/",
+ "twitter": "https://twitter.com/ethena",
+ "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
+ },
+ "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
+ },
+ {
+ "id": "ldo",
+ "coingeckoId": "lido-dao",
+ "name": "LDO",
+ "symbol": "LDO",
+ "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
+ "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
+ "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
+ "network": "ethereum",
+ "evidenceEntries": 12,
+ "positive": 8,
+ "neutral": 3,
+ "atRisk": 1,
+ "lastUpdated": 1777631939,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://lido.fi/",
+ "twitter": "https://twitter.com/lidofinance",
+ "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
+ },
+ "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
+ },
+ {
+ "id": "lqty",
+ "coingeckoId": "liquity",
+ "name": "LQTY",
+ "symbol": "LQTY",
+ "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
+ "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
+ "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
+ "network": "ethereum",
+ "evidenceEntries": 0,
+ "positive": 0,
+ "neutral": 0,
+ "atRisk": 0,
+ "lastUpdated": 1778064256,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://www.liquity.org/",
+ "twitter": "https://twitter.com/LiquityProtocol",
+ "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
+ },
+ "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
+ },
+ {
+ "id": "uni",
+ "coingeckoId": "uniswap",
+ "name": "UNI",
+ "symbol": "UNI",
+ "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
+ "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
+ "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 13,
+ "neutral": 4,
+ "atRisk": 1,
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://uniswap.org/",
+ "twitter": "https://twitter.com/uniswap",
+ "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
+ },
+ "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
+ },
+ {
+ "id": "yb",
+ "coingeckoId": "yield-basis",
+ "name": "YB",
+ "symbol": "YB",
+ "address": "0x01791F726B4103694969820be083196cC7c045fF",
+ "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
+ "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 11,
+ "neutral": 3,
+ "atRisk": 4,
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://yieldbasis.com/",
+ "twitter": "https://x.com/yieldbasis",
+ "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
+ },
+ "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
+ },
+ {
+ "id": "sky",
+ "coingeckoId": "sky",
+ "name": "SKY",
+ "symbol": "SKY",
+ "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
+ "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
+ "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 13,
+ "neutral": 3,
+ "atRisk": 2,
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://sky.money/",
+ "twitter": "https://twitter.com/SkyEcosystem",
+ "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
+ },
+ "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
+ },
+ {
+ "id": "ethfi",
+ "coingeckoId": "ether-fi",
+ "name": "ETHFI",
+ "symbol": "ETHFI",
+ "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
+ "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
+ "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 3,
+ "neutral": 13,
+ "atRisk": 2,
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ether.fi/",
+ "twitter": "https://twitter.com/ether_fi",
+ "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ },
+ "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
+ },
+ {
+ "id": "ondo",
+ "name": "ONDO",
+ "symbol": "ONDO",
+ "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
+ "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
+ "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
+ "network": "ethereum",
+ "evidenceEntries": 18,
+ "positive": 3,
+ "neutral": 2,
+ "atRisk": 13,
+ "lastUpdated": 1778674909,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ondo.finance/",
+ "twitter": "https://twitter.com/OndoFinance",
+ "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
+ },
+ "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
+ "coingeckoId": "ondo-finance"
+ }
+]
diff --git a/tests/round-trip.test.ts b/tests/round-trip.test.ts
new file mode 100644
index 0000000..244f13b
--- /dev/null
+++ b/tests/round-trip.test.ts
@@ -0,0 +1,120 @@
+/**
+ * Round-trip gate: composed read models must reproduce the golden fixtures
+ * captured from the pre-refactor runtime (tests/golden/, frozen 2026-06-05).
+ *
+ * ONE intentional diff is allowed and asserted explicitly: the token status
+ * counts (positive/neutral/atRisk/evidenceEntries) are now DERIVED from
+ * evaluations at compose time — the legacy hand-maintained counts were stale
+ * for all 11 tokens and are corrected, not preserved.
+ */
+import { describe, expect, it } from "vitest"
+// biome-ignore lint/style/noNamespaceImport: JSON module namespaces
+import goldenFaq from "./golden/faq.json"
+import goldenFramework from "./golden/framework.json"
+import goldenMetrics from "./golden/metrics.json"
+import goldenScores from "./golden/scores.json"
+import goldenTestimonials from "./golden/testimonials.json"
+import goldenTokens from "./golden/tokens.json"
+// @ts-expect-error untyped .mjs module
+import { composeAll } from "../scripts/compose-data.mjs"
+
+const COUNT_FIELDS = ["positive", "neutral", "atRisk", "evidenceEntries"]
+
+const withoutCounts = (obj: Record) =>
+ Object.fromEntries(
+ Object.entries(obj).filter(
+ ([k]) => !COUNT_FIELDS.includes(k) && k !== "score"
+ )
+ )
+
+const composed = composeAll()
+
+describe("round-trip vs golden fixtures", () => {
+ it("covers every golden token, none extra", () => {
+ expect(composed.tokenDocs.map((d: { id: string }) => d.id).sort()).toEqual(
+ goldenTokens.map((t) => t.id).sort()
+ )
+ })
+
+ for (const golden of goldenTokens) {
+ describe(golden.id, () => {
+ const doc = composed.tokenDocs.find(
+ (d: { id: string }) => d.id === golden.id
+ )
+
+ it("composed metrics equal golden merged metrics", () => {
+ expect(doc.metrics).toEqual(
+ goldenMetrics[golden.id as keyof typeof goldenMetrics]
+ )
+ })
+
+ it("composed score equals golden score", () => {
+ expect(doc.score).toEqual(
+ goldenScores[golden.id as keyof typeof goldenScores]
+ )
+ })
+
+ it("registry fields equal golden token (counts excluded)", () => {
+ expect(withoutCounts(doc)).toMatchObject(withoutCounts(golden))
+ })
+
+ it("derived counts equal counts computed from golden metrics (intentional correction of stale legacy values)", () => {
+ const criteria = goldenMetrics[
+ golden.id as keyof typeof goldenMetrics
+ ].flatMap((m) => m.criteria)
+ expect(doc.positive).toBe(
+ criteria.filter((c) => c.status === "positive").length
+ )
+ expect(doc.neutral).toBe(
+ criteria.filter((c) => c.status === "warning").length
+ )
+ expect(doc.atRisk).toBe(
+ criteria.filter((c) => c.status === "at_risk").length
+ )
+ expect(doc.evidenceEntries).toBe(
+ criteria.flatMap((c) => ("evidence" in c ? c.evidence : [])).length
+ )
+ })
+ })
+ }
+
+ it("framework doc projects onto golden framework", () => {
+ expect(
+ composed.frameworkDoc.metrics.map(
+ ({
+ id,
+ name,
+ about,
+ criteria,
+ }: {
+ id: string
+ name: string
+ about: string
+ criteria: unknown
+ }) => ({ id, name, about, criteria })
+ )
+ ).toEqual(goldenFramework)
+ })
+
+ it("faq topics equal golden", () => {
+ expect(composed.faq.topics).toEqual(goldenFaq)
+ })
+
+ it("testimonials equal golden", () => {
+ expect(composed.testimonials).toEqual(goldenTestimonials)
+ })
+
+ it("index rows mirror token docs", () => {
+ for (const row of composed.index.tokens) {
+ const { metrics: _metrics, ...doc } = composed.tokenDocs.find(
+ (d: { id: string }) => d.id === row.id
+ )
+ expect(withoutCounts(row)).toEqual(withoutCounts(doc))
+ expect(row.score).toEqual({
+ passing: doc.score.passing,
+ total: doc.score.total,
+ percentage: doc.score.percentage,
+ })
+ }
+ })
+})
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 0000000..4eacf64
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,14 @@
+import viteTsConfigPaths from "vite-tsconfig-paths"
+import { defineConfig } from "vitest/config"
+
+export default defineConfig({
+ plugins: [
+ viteTsConfigPaths({
+ projects: ["./tsconfig.json"],
+ }),
+ ],
+ test: {
+ environment: "node",
+ include: ["tests/**/*.test.ts"],
+ },
+})
From 49d8b1ae1831efd4e40cf8557a6a08d6f152cb54 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 12:56:59 +0200
Subject: [PATCH 03/38] fix: pin round-trip tests to frozen content fixtures
---
.../aave/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
.../evaluations/aave/offchain/_metric.json | 6 ++
.../aave/offchain/offchain__distribution.json | 15 +++
.../aave/offchain/offchain__licensing.json | 5 +
.../aave/offchain/offchain__trademark.json | 15 +++
.../aave/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 64 +++++++++++++
.../onchain-ctrl__censorship.json | 15 +++
.../onchain-ctrl__governance-workflow.json | 15 +++
.../onchain-ctrl__protocol-upgrade.json | 43 +++++++++
.../onchain-ctrl__role-accountability.json | 21 +++++
.../onchain-ctrl/onchain-ctrl__supply.json | 15 +++
.../onchain-ctrl__token-upgrade.json | 27 ++++++
.../evaluations/aave/val-accrual/_metric.json | 6 ++
.../aave/val-accrual/val-accrual__active.json | 25 +++++
.../val-accrual/val-accrual__mechanism.json | 22 +++++
.../val-accrual/val-accrual__offchain.json | 8 ++
.../val-accrual/val-accrual__treasury.json | 38 ++++++++
.../aave/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 15 +++
.../verifiability__token-source.json | 20 ++++
.../aero/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
.../evaluations/aero/offchain/_metric.json | 6 ++
.../aero/offchain/offchain__distribution.json | 15 +++
.../aero/offchain/offchain__licensing.json | 5 +
.../aero/offchain/offchain__trademark.json | 15 +++
.../aero/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 44 +++++++++
.../onchain-ctrl__censorship.json | 38 ++++++++
.../onchain-ctrl__governance-workflow.json | 43 +++++++++
.../onchain-ctrl__protocol-upgrade.json | 15 +++
.../onchain-ctrl__role-accountability.json | 22 +++++
.../onchain-ctrl/onchain-ctrl__supply.json | 55 +++++++++++
.../onchain-ctrl__token-upgrade.json | 20 ++++
.../evaluations/aero/val-accrual/_metric.json | 6 ++
.../aero/val-accrual/val-accrual__active.json | 84 +++++++++++++++++
.../val-accrual/val-accrual__mechanism.json | 33 +++++++
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 5 +
.../aero/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 20 ++++
.../verifiability__token-source.json | 20 ++++
.../evaluations/crv/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 15 +++
.../evaluations/crv/offchain/_metric.json | 6 ++
.../crv/offchain/offchain__distribution.json | 15 +++
.../crv/offchain/offchain__licensing.json | 5 +
.../crv/offchain/offchain__trademark.json | 15 +++
.../evaluations/crv/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 17 ++++
.../onchain-ctrl__censorship.json | 20 ++++
.../onchain-ctrl__governance-workflow.json | 25 +++++
.../onchain-ctrl__protocol-upgrade.json | 44 +++++++++
.../onchain-ctrl__role-accountability.json | 28 ++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 38 ++++++++
.../onchain-ctrl__token-upgrade.json | 15 +++
.../evaluations/crv/val-accrual/_metric.json | 6 ++
.../crv/val-accrual/val-accrual__active.json | 39 ++++++++
.../val-accrual/val-accrual__mechanism.json | 39 ++++++++
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 15 +++
.../crv/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 15 +++
.../verifiability__token-source.json | 20 ++++
.../evaluations/ena/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 22 +++++
.../distribution__supply-schedule.json | 22 +++++
.../evaluations/ena/offchain/_metric.json | 6 ++
.../ena/offchain/offchain__distribution.json | 15 +++
.../ena/offchain/offchain__licensing.json | 20 ++++
.../ena/offchain/offchain__trademark.json | 15 +++
.../evaluations/ena/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 43 +++++++++
.../onchain-ctrl__censorship.json | 27 ++++++
.../onchain-ctrl__governance-workflow.json | 33 +++++++
.../onchain-ctrl__protocol-upgrade.json | 68 ++++++++++++++
.../onchain-ctrl__role-accountability.json | 58 ++++++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 22 +++++
.../onchain-ctrl__token-upgrade.json | 22 +++++
.../evaluations/ena/val-accrual/_metric.json | 6 ++
.../ena/val-accrual/val-accrual__active.json | 59 ++++++++++++
.../val-accrual/val-accrual__mechanism.json | 38 ++++++++
.../val-accrual/val-accrual__offchain.json | 33 +++++++
.../val-accrual/val-accrual__treasury.json | 43 +++++++++
.../ena/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 71 ++++++++++++++
.../verifiability__token-source.json | 20 ++++
.../ethfi/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 16 ++++
.../distribution__supply-schedule.json | 21 +++++
.../evaluations/ethfi/offchain/_metric.json | 6 ++
.../offchain/offchain__distribution.json | 16 ++++
.../ethfi/offchain/offchain__licensing.json | 21 +++++
.../ethfi/offchain/offchain__trademark.json | 16 ++++
.../ethfi/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 17 ++++
.../onchain-ctrl__censorship.json | 27 ++++++
.../onchain-ctrl__governance-workflow.json | 27 ++++++
.../onchain-ctrl__protocol-upgrade.json | 38 ++++++++
.../onchain-ctrl__role-accountability.json | 43 +++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 22 +++++
.../onchain-ctrl__token-upgrade.json | 43 +++++++++
.../ethfi/val-accrual/_metric.json | 6 ++
.../val-accrual/val-accrual__active.json | 32 +++++++
.../val-accrual/val-accrual__mechanism.json | 17 ++++
.../val-accrual/val-accrual__offchain.json | 8 ++
.../val-accrual/val-accrual__treasury.json | 22 +++++
.../ethfi/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 21 +++++
.../verifiability__token-source.json | 17 ++++
.../evaluations/ldo/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 5 +
.../evaluations/ldo/offchain/_metric.json | 6 ++
.../ldo/offchain/offchain__distribution.json | 25 +++++
.../ldo/offchain/offchain__licensing.json | 25 +++++
.../ldo/offchain/offchain__trademark.json | 20 ++++
.../evaluations/ldo/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 43 +++++++++
.../onchain-ctrl__censorship.json | 33 +++++++
.../onchain-ctrl__governance-workflow.json | 64 +++++++++++++
.../onchain-ctrl__protocol-upgrade.json | 48 ++++++++++
.../onchain-ctrl__role-accountability.json | 50 ++++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 17 ++++
.../onchain-ctrl__token-upgrade.json | 33 +++++++
.../evaluations/ldo/val-accrual/_metric.json | 6 ++
.../ldo/val-accrual/val-accrual__active.json | 46 +++++++++
.../val-accrual/val-accrual__mechanism.json | 15 +++
.../val-accrual/val-accrual__offchain.json | 5 +
.../val-accrual/val-accrual__treasury.json | 28 ++++++
.../ldo/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 15 +++
.../verifiability__token-source.json | 20 ++++
.../lqty/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 20 ++++
.../evaluations/lqty/offchain/_metric.json | 6 ++
.../lqty/offchain/offchain__distribution.json | 25 +++++
.../lqty/offchain/offchain__licensing.json | 25 +++++
.../lqty/offchain/offchain__trademark.json | 25 +++++
.../lqty/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 16 ++++
.../onchain-ctrl__censorship.json | 15 +++
.../onchain-ctrl__governance-workflow.json | 20 ++++
.../onchain-ctrl__protocol-upgrade.json | 15 +++
.../onchain-ctrl__role-accountability.json | 15 +++
.../onchain-ctrl/onchain-ctrl__supply.json | 15 +++
.../onchain-ctrl__token-upgrade.json | 15 +++
.../evaluations/lqty/val-accrual/_metric.json | 6 ++
.../lqty/val-accrual/val-accrual__active.json | 40 ++++++++
.../val-accrual/val-accrual__mechanism.json | 20 ++++
.../val-accrual/val-accrual__offchain.json | 8 ++
.../val-accrual/val-accrual__treasury.json | 15 +++
.../lqty/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 20 ++++
.../verifiability__token-source.json | 20 ++++
.../ondo/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 22 +++++
.../distribution__supply-schedule.json | 22 +++++
.../evaluations/ondo/offchain/_metric.json | 6 ++
.../ondo/offchain/offchain__distribution.json | 17 ++++
.../ondo/offchain/offchain__licensing.json | 27 ++++++
.../ondo/offchain/offchain__trademark.json | 17 ++++
.../ondo/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 43 +++++++++
.../onchain-ctrl__censorship.json | 22 +++++
.../onchain-ctrl__governance-workflow.json | 42 +++++++++
.../onchain-ctrl__protocol-upgrade.json | 63 +++++++++++++
.../onchain-ctrl__role-accountability.json | 94 +++++++++++++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 38 ++++++++
.../onchain-ctrl__token-upgrade.json | 33 +++++++
.../evaluations/ondo/val-accrual/_metric.json | 6 ++
.../ondo/val-accrual/val-accrual__active.json | 32 +++++++
.../val-accrual/val-accrual__mechanism.json | 48 ++++++++++
.../val-accrual/val-accrual__offchain.json | 51 ++++++++++
.../val-accrual/val-accrual__treasury.json | 17 ++++
.../ondo/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 51 ++++++++++
.../verifiability__token-source.json | 20 ++++
.../evaluations/sky/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 17 ++++
.../evaluations/sky/offchain/_metric.json | 6 ++
.../sky/offchain/offchain__distribution.json | 17 ++++
.../sky/offchain/offchain__licensing.json | 17 ++++
.../sky/offchain/offchain__trademark.json | 28 ++++++
.../evaluations/sky/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 27 ++++++
.../onchain-ctrl__censorship.json | 17 ++++
.../onchain-ctrl__governance-workflow.json | 38 ++++++++
.../onchain-ctrl__protocol-upgrade.json | 38 ++++++++
.../onchain-ctrl__role-accountability.json | 43 +++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 33 +++++++
.../onchain-ctrl__token-upgrade.json | 17 ++++
.../evaluations/sky/val-accrual/_metric.json | 6 ++
.../sky/val-accrual/val-accrual__active.json | 48 ++++++++++
.../val-accrual/val-accrual__mechanism.json | 38 ++++++++
.../val-accrual/val-accrual__offchain.json | 20 ++++
.../val-accrual/val-accrual__treasury.json | 17 ++++
.../sky/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 22 +++++
.../verifiability__token-source.json | 22 +++++
.../evaluations/uni/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 5 +
.../distribution__supply-schedule.json | 37 ++++++++
.../evaluations/uni/offchain/_metric.json | 6 ++
.../uni/offchain/offchain__distribution.json | 15 +++
.../uni/offchain/offchain__licensing.json | 5 +
.../uni/offchain/offchain__trademark.json | 15 +++
.../evaluations/uni/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 5 +
.../onchain-ctrl__censorship.json | 15 +++
.../onchain-ctrl__governance-workflow.json | 20 ++++
.../onchain-ctrl__protocol-upgrade.json | 38 ++++++++
.../onchain-ctrl__role-accountability.json | 55 +++++++++++
.../onchain-ctrl/onchain-ctrl__supply.json | 33 +++++++
.../onchain-ctrl__token-upgrade.json | 20 ++++
.../evaluations/uni/val-accrual/_metric.json | 6 ++
.../uni/val-accrual/val-accrual__active.json | 65 +++++++++++++
.../val-accrual/val-accrual__mechanism.json | 49 ++++++++++
.../val-accrual/val-accrual__offchain.json | 15 +++
.../val-accrual/val-accrual__treasury.json | 15 +++
.../uni/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 30 ++++++
.../verifiability__token-source.json | 20 ++++
.../evaluations/yb/distribution/_metric.json | 6 ++
.../distribution__concentration.json | 22 +++++
.../distribution__supply-schedule.json | 17 ++++
.../evaluations/yb/offchain/_metric.json | 6 ++
.../yb/offchain/offchain__distribution.json | 15 +++
.../yb/offchain/offchain__licensing.json | 22 +++++
.../yb/offchain/offchain__trademark.json | 5 +
.../evaluations/yb/onchain-ctrl/_metric.json | 6 ++
.../onchain-ctrl__access-gating.json | 22 +++++
.../onchain-ctrl__censorship.json | 15 +++
.../onchain-ctrl__governance-workflow.json | 32 +++++++
.../onchain-ctrl__protocol-upgrade.json | 27 ++++++
.../onchain-ctrl__role-accountability.json | 43 +++++++++
.../yb/onchain-ctrl/onchain-ctrl__supply.json | 27 ++++++
.../onchain-ctrl__token-upgrade.json | 22 +++++
.../evaluations/yb/val-accrual/_metric.json | 6 ++
.../yb/val-accrual/val-accrual__active.json | 42 +++++++++
.../val-accrual/val-accrual__mechanism.json | 38 ++++++++
.../yb/val-accrual/val-accrual__offchain.json | 8 ++
.../yb/val-accrual/val-accrual__treasury.json | 27 ++++++
.../evaluations/yb/verifiability/_metric.json | 6 ++
.../verifiability__protocol-source.json | 22 +++++
.../verifiability__token-source.json | 20 ++++
tests/fixtures/content-6b17fa7/faq.json | 60 ++++++++++++
.../content-6b17fa7/framework/_meta.json | 10 ++
.../framework/distribution.json | 19 ++++
.../content-6b17fa7/framework/offchain.json | 24 +++++
.../framework/onchain-ctrl.json | 44 +++++++++
.../framework/val-accrual.json | 29 ++++++
.../framework/verifiability.json | 19 ++++
.../content-6b17fa7/testimonials.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/aave.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/aero.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/crv.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/ena.json | 21 +++++
.../content-6b17fa7/tokens/ethfi.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/ldo.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/lqty.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/ondo.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/sky.json | 21 +++++
.../fixtures/content-6b17fa7/tokens/uni.json | 21 +++++
tests/fixtures/content-6b17fa7/tokens/yb.json | 21 +++++
tests/round-trip.test.ts | 16 +++-
273 files changed, 5888 insertions(+), 4 deletions(-)
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
create mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
create mode 100644 tests/fixtures/content-6b17fa7/faq.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/_meta.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/distribution.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/offchain.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/val-accrual.json
create mode 100644 tests/fixtures/content-6b17fa7/framework/verifiability.json
create mode 100644 tests/fixtures/content-6b17fa7/testimonials.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/aave.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/aero.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/crv.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/ena.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/ethfi.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/ldo.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/lqty.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/ondo.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/sky.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/uni.json
create mode 100644 tests/fixtures/content-6b17fa7/tokens/yb.json
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
new file mode 100644
index 0000000..2163fcd
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
new file mode 100644
index 0000000..5e8dfb9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..195571e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
new file mode 100644
index 0000000..3c60448
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
new file mode 100644
index 0000000..729980a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface terms identify Aave Labs as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://aave.com/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
new file mode 100644
index 0000000..5cae96f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
new file mode 100644
index 0000000..46ea782
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Trademark filing",
+ "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..af0a600
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..4a5906e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,64 @@
+{
+ "status": "positive",
+ "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
+ "evidence": [
+ {
+ "name": "Core",
+ "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
+ "urls": [
+ {
+ "name": "Core Protocol Role addresses",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
+ "type": "github"
+ },
+ {
+ "name": "Core Protocol Roles in ACLManager",
+ "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
+ "type": "explorer"
+ },
+ {
+ "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
+ "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
+ "type": "explorer"
+ },
+ {
+ "name": "POOL_ADMIN_ROLE: Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Delegated Steward Roles",
+ "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
+ "urls": [
+ {
+ "name": "Stewards (docs)",
+ "url": "https://aave.com/help/governance/aave-community",
+ "type": "docs"
+ },
+ {
+ "name": "Stewards (addresses)",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Protocol Emergency Guardian",
+ "summary": "A separate multisig that executes limited emergency operations for the protocol.",
+ "urls": [
+ {
+ "name": "Protocol Emergency Guardian",
+ "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
+ "type": "docs"
+ },
+ {
+ "name": "Detailed protocol permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..7ca7f0a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token's implementation code",
+ "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..e0d0466
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://aave.com/docs/ecosystem/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..27b3b55
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "Holders control implementation upgrades for all v3 market deployments.",
+ "evidence": [
+ {
+ "name": "Upgrade Documentation",
+ "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
+ "urls": [
+ {
+ "name": "Upgradability per contract",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Ownership Chain",
+ "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
+ "urls": [
+ {
+ "name": "Pool",
+ "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance",
+ "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..a065c83
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,21 @@
+{
+ "status": "positive",
+ "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
+ "evidence": [
+ {
+ "name": "Governance Emergency Guardian",
+ "urls": [
+ {
+ "name": "Onchain address",
+ "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Detailed Governance Permissions",
+ "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..32d8315
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..1182c67
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "The AAVE token is upgradeable but controlled by token holders.",
+ "evidence": [
+ {
+ "name": "Ownership Chain",
+ "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
+ "urls": [
+ {
+ "name": "AAVE Proxy",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ProxyAdmin",
+ "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
+ "type": "explorer"
+ },
+ {
+ "name": "PayloadsController",
+ "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
new file mode 100644
index 0000000..d5958bb
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..497f899
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Safety Module - Incentives",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Transition",
+ "url": "https://aave.com/help/umbrella/stake",
+ "type": "docs"
+ },
+ {
+ "name": "Umbrella Activation Proposal",
+ "url": "https://vote.onaave.com/proposal/?proposalId=320",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..a0753b1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
+ "evidence": [
+ {
+ "name": "ACL Control",
+ "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
+ "urls": [
+ {
+ "name": "POOL_ADMIN role",
+ "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
+ "type": "docs"
+ },
+ {
+ "name": "ACLManager",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..7d7ee44
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..cb89d8e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "Token holders direct treasury via governance.",
+ "urls": [
+ {
+ "name": "Treasury docs",
+ "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Fee Sources",
+ "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
+ "urls": [
+ {
+ "name": "mintToTreasury (PoolLogic)",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
+ "type": "github"
+ },
+ {
+ "name": "Flashloan premium",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
+ "type": "github"
+ },
+ {
+ "name": "Liquidation fee",
+ "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
new file mode 100644
index 0000000..6bfa4a9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..92845b9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..5f8b629
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AAVE token",
+ "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Aave V3 Origin (GitHub)",
+ "url": "https://github.com/aave-dao/aave-v3-origin",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
new file mode 100644
index 0000000..5ca27bd
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
new file mode 100644
index 0000000..dad8ff0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..ccc8eba
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
new file mode 100644
index 0000000..e86b6c4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
new file mode 100644
index 0000000..bc7fd01
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Legal",
+ "url": "https://aero.drome.eth.link/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
new file mode 100644
index 0000000..e33118a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
new file mode 100644
index 0000000..af8ead8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "USPTO Report",
+ "url": "https://uspto.report/TM/99083103",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..2c8fa4d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..f854e83
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,44 @@
+{
+ "status": "warning",
+ "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
+ "evidence": [
+ {
+ "name": "Fee Manager Role",
+ "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
+ "urls": [
+ {
+ "name": "Safe (Fee Manager)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-SlipStream Fees",
+ "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
+ "urls": [
+ {
+ "name": "PoolFactory: FeeManager",
+ "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "SlipStream Fees",
+ "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
+ "urls": [
+ {
+ "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
+ "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
+ "type": "explorer"
+ },
+ {
+ "name": "SwapFeeModule: setCustomFee",
+ "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..de6f75c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
+ "evidence": [
+ {
+ "name": "Team Rate",
+ "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
+ "urls": [
+ {
+ "name": "Safe (Team)",
+ "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
+ "urls": [
+ {
+ "name": "Governor (Safe)",
+ "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
+ "type": "explorer"
+ },
+ {
+ "name": "Emission Rate Change",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..c6dac94
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
+ "evidence": [
+ {
+ "name": "Voting System",
+ "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "VotingEscrow",
+ "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Voter",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Council",
+ "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
+ "urls": [
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://aerodrome.limited/pages/security.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..3e17d2e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contract Addresses",
+ "url": "https://aerodrome.finance/security",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..2c27da6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
+ "evidence": [
+ {
+ "name": "Emergency Council",
+ "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
+ "urls": [
+ {
+ "name": "Voter: emergencyCouncil",
+ "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyCouncil",
+ "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..0dfcfda
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,55 @@
+{
+ "status": "positive",
+ "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
+ "evidence": [
+ {
+ "name": "Minter Contract",
+ "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
+ "urls": [
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emission Rate",
+ "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
+ "urls": [
+ {
+ "name": "Minter Emission Increase (Epochs 1-14)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
+ "type": "github"
+ },
+ {
+ "name": "Minter Emission Decay",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Growth Emissions",
+ "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
+ "urls": [
+ {
+ "name": "Growth Emissions Formula",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Team Emission Rate",
+ "summary": "Currently set to 0% of total weekly emissions.",
+ "urls": [
+ {
+ "name": "Team Emission Rate",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..f04a477
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Minter",
+ "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
new file mode 100644
index 0000000..98d089b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..09489eb
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
@@ -0,0 +1,84 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
+ "evidence": [
+ {
+ "name": "Growth Emissions",
+ "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
+ "urls": [
+ {
+ "name": "Growth Transfer to RewardDistributor",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
+ "type": "github"
+ },
+ {
+ "name": "RewardsDistributor Claim",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Non-Slipstream Trading Fees",
+ "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Gauge Deposit Logic",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Accrued",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
+ "type": "github"
+ },
+ {
+ "name": "Voter calling Gauge to claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
+ "type": "github"
+ },
+ {
+ "name": "Swap Fee Claimed by Gauge on PoolFees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Slipstream Trading Fees",
+ "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
+ "urls": [
+ {
+ "name": "Fees Split",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees calculated separately",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
+ "type": "github"
+ },
+ {
+ "name": "Non Staked LP Fees collected",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
+ "type": "github"
+ },
+ {
+ "name": "Gauge Fees to feesVotingReward",
+ "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
+ "type": "github"
+ },
+ {
+ "name": "veAERO voters claim fees",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..463eee0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
+ "evidence": [
+ {
+ "name": "Locking Control",
+ "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
+ "urls": [
+ {
+ "name": "VotingEscrow create_lock",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
+ "urls": [
+ {
+ "name": "Voter vote function",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
+ "type": "github"
+ },
+ {
+ "name": "Gauge getReward",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..ee52be6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..3c85ba0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
new file mode 100644
index 0000000..41079e6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..13be4d3
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aerodrome Contracts (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Aerodrome Slipstream (GitHub)",
+ "url": "https://github.com/aerodrome-finance/slipstream",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..a7da64f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "AERO Token (Basescan)",
+ "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Aero.sol Source (GitHub)",
+ "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
new file mode 100644
index 0000000..40ad32e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
new file mode 100644
index 0000000..b5fa2a4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..5f677ee
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
new file mode 100644
index 0000000..74fb5a8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
new file mode 100644
index 0000000..7a6be45
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve Legal",
+ "url": "https://www.curve.finance/dex/ethereum/legal",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
new file mode 100644
index 0000000..a17a25c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
new file mode 100644
index 0000000..a7441b2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Swiss Trademark Registry",
+ "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..5e84784
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..b8d6f95
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
+ "evidence": [
+ {
+ "name": "Add/Kill Gauge",
+ "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
+ "urls": [
+ {
+ "name": "Gauge Kill Implementation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5704953
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Standard Transfer",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
+ "type": "github"
+ },
+ {
+ "name": "ERC20CRV.vy Metadata Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..5617c7a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Aragon Voting Contract",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent Contract",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
+ "type": "explorer"
+ },
+ {
+ "name": "CRV Token: Admin is set to Agent",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..2e50f5a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,44 @@
+{
+ "status": "positive",
+ "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
+ "evidence": [
+ {
+ "name": "Core Contracts",
+ "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
+ "urls": [
+ {
+ "name": "CRV Token (Admin: Agent)",
+ "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
+ "type": "explorer"
+ },
+ {
+ "name": "GaugeController (Admin: Agent)",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent Contract",
+ "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Voting Contract",
+ "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..c84b85c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,28 @@
+{
+ "status": "positive",
+ "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
+ "evidence": [
+ {
+ "name": "Gauge Addition",
+ "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
+ "urls": [
+ {
+ "name": "GaugeController: admin is Agent",
+ "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Pool Factory Ownership",
+ "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
+ "urls": [
+ {
+ "name": "Curve Pool Factory: admin is OwnerProxy",
+ "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..ef408a0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
+ "evidence": [
+ {
+ "name": "Supply Schedule",
+ "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
+ "urls": [
+ {
+ "name": "CRV Emission Schedule (Docs)",
+ "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
+ "type": "docs"
+ },
+ {
+ "name": "ERC20CRV.vy Yearly Epoch Logic",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Access",
+ "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Mint Access",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
+ "type": "github"
+ },
+ {
+ "name": "Minter.vy Gauge Validation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..0f5537c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ERC20CRV.vy Source",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
new file mode 100644
index 0000000..6260c77
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..66103a1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
@@ -0,0 +1,39 @@
+{
+ "status": "positive",
+ "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
+ "evidence": [
+ {
+ "name": "CRV Emissions Rewards",
+ "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
+ "urls": [
+ {
+ "name": "working_balance reward calculation",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Pool Rewards in crvUSD",
+ "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
+ "urls": [
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Borrow Rewards in crvUSD",
+ "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
+ "urls": [
+ {
+ "name": "FeeSplitter",
+ "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..5989d6d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,39 @@
+{
+ "status": "positive",
+ "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
+ "evidence": [
+ {
+ "name": "Pool Fee Control",
+ "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "DAI/USDC/USDT Pool: commit_new_fee",
+ "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burner Attachment",
+ "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
+ "urls": [
+ {
+ "name": "StableSwapProxy: set_burner",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Burn Execution",
+ "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
+ "urls": [
+ {
+ "name": "StableSwapProxy: burn",
+ "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..ed5f6d9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..a1ca859
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "veCRV Revenue Share (Docs)",
+ "url": "https://docs.curve.finance/user/vecrv/revenue",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
new file mode 100644
index 0000000..8a84410
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..dfa266b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Curve DAO protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Curve DAO Contracts (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..88abb06
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "CRV Token (Etherscan)",
+ "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ERC20CRV.vy Source (GitHub)",
+ "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
new file mode 100644
index 0000000..99cf88c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
new file mode 100644
index 0000000..6302a56
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
+ "urls": [
+ {
+ "name": "Tokenomist.ai - ENA",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ },
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..2906392
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
+ "evidence": [
+ {
+ "name": "Vesting Schedules",
+ "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
+ "urls": [
+ {
+ "name": "ENA Tokenomics Documentation",
+ "url": "https://docs.ethena.fi/ena/tokenomics",
+ "type": "docs"
+ },
+ {
+ "name": "Tokenomist.ai - ENA Vesting",
+ "url": "https://tokenomist.ai/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
new file mode 100644
index 0000000..692c514
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
new file mode 100644
index 0000000..09259c1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
new file mode 100644
index 0000000..5df1cf4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
@@ -0,0 +1,20 @@
+{
+ "status": "warning",
+ "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena GitHub License",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
new file mode 100644
index 0000000..3ea8daa
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Ethena Terms of Service",
+ "url": "https://docs.ethena.fi/resources/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..aa732f2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..85c8a35
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
+ "evidence": [
+ {
+ "name": "Privileged Roles (per Multisig Matrix)",
+ "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Gatekeeper Powers",
+ "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
+ "urls": [
+ {
+ "name": "`disableMintRedeem()` (line 278)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
+ "type": "github"
+ },
+ {
+ "name": "`removeMinterRole()` (line 339)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
+ "type": "github"
+ },
+ {
+ "name": "`removeRedeemerRole()` (line 345)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..ea421fc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,27 @@
+{
+ "status": "warning",
+ "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
+ "evidence": [
+ {
+ "name": "sENA/sUSDe Blacklist Capabilities",
+ "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
+ "urls": [
+ {
+ "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
+ "type": "github"
+ },
+ {
+ "name": "`redistributeLockedAmount()` (lines 106-127)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
+ "type": "github"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..f3a9970
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,33 @@
+{
+ "status": "warning",
+ "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
+ "evidence": [
+ {
+ "name": "Snapshot Governance",
+ "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
+ "urls": [
+ {
+ "name": "Snapshot Space",
+ "url": "https://snapshot.org/#/ethenagovernance.eth",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Multisig Execution",
+ "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
+ "urls": [
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..967e44f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,68 @@
+{
+ "status": "warning",
+ "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Contracts",
+ "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Contracts (sENA and rsENA)",
+ "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
+ "urls": [
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Implementation",
+ "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Implementation",
+ "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..b840de7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,58 @@
+{
+ "status": "warning",
+ "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
+ "evidence": [
+ {
+ "name": "Multisig Control Matrix",
+ "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
+ "urls": [
+ {
+ "name": "Multisig Matrix Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ },
+ {
+ "name": "Dev Multisig",
+ "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
+ "type": "explorer"
+ },
+ {
+ "name": "Hot Swap Multisig",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "Trading Operations Multisig",
+ "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
+ "type": "explorer"
+ },
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "EOA Control Points",
+ "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
+ "urls": [
+ {
+ "name": "StakingRewardsDistributor Operator (EOA)",
+ "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
+ "type": "explorer"
+ },
+ {
+ "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
+ "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..ff12bcc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
+ "evidence": [
+ {
+ "name": "Mint Function",
+ "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
+ "urls": [
+ {
+ "name": "ENA.sol `mint()` function (lines 42-49)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token totalSupply",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..6f0354c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
+ "evidence": [
+ {
+ "name": "ENA Non-Upgradeability Verification",
+ "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
+ "urls": [
+ {
+ "name": "ENA.sol Source",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ },
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
new file mode 100644
index 0000000..12be505
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..35bf37b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
@@ -0,0 +1,59 @@
+{
+ "status": "warning",
+ "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
+ "evidence": [
+ {
+ "name": "Fee Switch Status",
+ "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "USDe Token (verify totalSupply)",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Ethena Network Airdrops",
+ "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
+ "urls": [
+ {
+ "name": "Ethena Network Documentation",
+ "url": "https://docs.ethena.fi/ethena-network",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "rsENA (Restaked ENA via Symbiotic)",
+ "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
+ "urls": [
+ {
+ "name": "rsENA Contract",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA Staking Documentation",
+ "url": "https://docs.ethena.fi/ena",
+ "type": "docs"
+ },
+ {
+ "name": "Mellow Finance rsENA Vault",
+ "url": "https://app.mellow.finance/vaults/ethereum-rsena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..1e775e7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "warning",
+ "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
+ "evidence": [
+ {
+ "name": "ENA Value Accrual Controls",
+ "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
+ "urls": [
+ {
+ "name": "Fee Switch Parameters Proposal",
+ "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
+ "type": "docs"
+ },
+ {
+ "name": "sENA ProxyAdmin",
+ "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
+ "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Tokenholder Cannot Force Activation",
+ "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
+ "urls": [
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.ethena.fi/solution-overview/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..dd3c133
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,33 @@
+{
+ "status": "warning",
+ "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
+ "evidence": [
+ {
+ "name": "USDe Yield Sources",
+ "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
+ "urls": [
+ {
+ "name": "Coin Metrics Analysis (USDe Yield Sources)",
+ "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Yield Distribution Flow",
+ "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
+ "urls": [
+ {
+ "name": "`transferInRewards()` (lines 88-94)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
+ "type": "github"
+ },
+ {
+ "name": "DefiLlama - Ethena Fees",
+ "url": "https://defillama.com/protocol/ethena",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..cec61a8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
+ "evidence": [
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
+ "urls": [
+ {
+ "name": "Key Addresses Documentation",
+ "url": "https://docs.ethena.fi/solution-design/key-addresses",
+ "type": "docs"
+ },
+ {
+ "name": "Hot Swap Multisig (revenue receiver)",
+ "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Payout Multisig",
+ "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Reserve Fund (Negative Funding Backup)",
+ "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
+ "urls": [
+ {
+ "name": "Reserve Fund Multisig",
+ "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
new file mode 100644
index 0000000..9ae768f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..f2d5e2d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,71 @@
+{
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
+ "evidence": [
+ {
+ "name": "Verified Contracts",
+ "urls": [
+ {
+ "name": "ENA Token",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sENA Proxy",
+ "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "rsENA Proxy",
+ "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDe Token",
+ "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "sUSDe Token",
+ "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EthenaMinting V2",
+ "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRewardsDistributor",
+ "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "GitHub Repository",
+ "urls": [
+ {
+ "name": "Ethena Public Assets (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Audits",
+ "urls": [
+ {
+ "name": "Code4rena 2023 Audit",
+ "url": "https://github.com/code-423n4/2023-10-ethena",
+ "type": "github"
+ },
+ {
+ "name": "Code4rena 2024 Audit",
+ "url": "https://github.com/code-423n4/2024-11-ethena-labs",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..832ff34
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ENA Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
+ "type": "explorer"
+ },
+ {
+ "name": "ENA.sol Source (GitHub)",
+ "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
new file mode 100644
index 0000000..e97bf51
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
new file mode 100644
index 0000000..a95862d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
+ "evidence": [
+ {
+ "name": "Token Allocation",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..2fbf530
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
@@ -0,0 +1,21 @@
+{
+ "status": "warning",
+ "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "DefiLlama Unlocks",
+ "url": "https://defillama.com/unlocks/ether.fi",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
new file mode 100644
index 0000000..e2152cc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
new file mode 100644
index 0000000..45c898e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
+ "evidence": [
+ {
+ "name": "Legal Entity",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
new file mode 100644
index 0000000..bfa11ce
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
@@ -0,0 +1,21 @@
+{
+ "status": "warning",
+ "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
+ "evidence": [
+ {
+ "name": "License",
+ "urls": [
+ {
+ "name": "GitHub Repository",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Terms of Use (Non-Contract IP)",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
new file mode 100644
index 0000000..c573eef
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
@@ -0,0 +1,16 @@
+{
+ "status": "warning",
+ "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
+ "evidence": [
+ {
+ "name": "Trademark Ownership",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..ca55eb6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..5b3acc3
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
+ "evidence": [
+ {
+ "name": "Pause Authority",
+ "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
+ "urls": [
+ {
+ "name": "EtherFiAdmin Pause Function",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..2c44b78
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,27 @@
+{
+ "status": "warning",
+ "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
+ "evidence": [
+ {
+ "name": "Token Analysis",
+ "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum ETHFI (Upgradeable)",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI (Upgradeable)",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..472575d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,27 @@
+{
+ "status": "at_risk",
+ "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "evidence": [
+ {
+ "name": "Governance Structure",
+ "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
+ "urls": [
+ {
+ "name": "Governance Info",
+ "url": "https://vote.ether.fi/info",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Resources",
+ "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
+ "type": "docs"
+ },
+ {
+ "name": "Governance Roadmap",
+ "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..a68cded
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "warning",
+ "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
+ "urls": [
+ {
+ "name": "RoleRegistry Upgrade Check",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
+ "type": "github"
+ },
+ {
+ "name": "LiquidityPool Upgrade Authorization",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "RoleRegistry Owner",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..0936aa7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
+ "evidence": [
+ {
+ "name": "RoleRegistry Owner (Upgrade Timelock)",
+ "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
+ "urls": [
+ {
+ "name": "RoleRegistry Contract",
+ "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock (72h)",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Two-Timelock System",
+ "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
+ "urls": [
+ {
+ "name": "Upgrade Admin (4-of-7)",
+ "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Timelock (8h)",
+ "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
+ "type": "explorer"
+ },
+ {
+ "name": "Operating Admin (3-of-5)",
+ "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..98f9307
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
+ "evidence": [
+ {
+ "name": "Fixed Supply",
+ "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
+ "urls": [
+ {
+ "name": "ETHFI Allocations",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
+ "type": "docs"
+ },
+ {
+ "name": "Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..4024ae0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,43 @@
+{
+ "status": "warning",
+ "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
+ "evidence": [
+ {
+ "name": "Mainnet Token (Not Upgradeable)",
+ "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
+ "urls": [
+ {
+ "name": "ETHFI Token Contract",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "L2 Tokens (Upgradeable, No Timelock)",
+ "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
+ "urls": [
+ {
+ "name": "Arbitrum ETHFI",
+ "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum Admin (3-of-6)",
+ "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
+ "type": "explorer"
+ },
+ {
+ "name": "Base ETHFI",
+ "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
+ "type": "explorer"
+ },
+ {
+ "name": "Base Admin (3-of-6)",
+ "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
new file mode 100644
index 0000000..aad827f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..84671dc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
@@ -0,0 +1,32 @@
+{
+ "status": "positive",
+ "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
+ "evidence": [
+ {
+ "name": "Buyback Program",
+ "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
+ "urls": [
+ {
+ "name": "ETHFI Buyback Program",
+ "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback History (Dune)",
+ "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
+ "type": "docs"
+ },
+ {
+ "name": "sETHFI Staking",
+ "url": "https://www.ether.fi/app/ethfi",
+ "type": "docs"
+ },
+ {
+ "name": "Buyback Wallet (1-of-5)",
+ "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..0e84742
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
+ "evidence": [
+ {
+ "name": "Fee Configuration",
+ "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
+ "urls": [
+ {
+ "name": "LiquidityPool Fee Functions",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..be71a37
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..1e800d0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
+ "type": "explorer"
+ },
+ {
+ "name": "Upgrade Timelock",
+ "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
new file mode 100644
index 0000000..14c61d2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..17de7d2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,21 @@
+{
+ "status": "positive",
+ "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
+ "evidence": [
+ {
+ "name": "Protocol Source & Audits",
+ "urls": [
+ {
+ "name": "etherfi-protocol/smart-contracts",
+ "url": "https://github.com/etherfi-protocol/smart-contracts",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..04155b4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
+ "evidence": [
+ {
+ "name": "Token Verification",
+ "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
+ "urls": [
+ {
+ "name": "Etherscan Verified Source",
+ "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
new file mode 100644
index 0000000..01ef2fb
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
new file mode 100644
index 0000000..f0ea33e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..b781f77
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
new file mode 100644
index 0000000..4da96c8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
new file mode 100644
index 0000000..0ba589a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
new file mode 100644
index 0000000..0ba589a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
@@ -0,0 +1,25 @@
+{
+ "status": "positive",
+ "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Labs BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Ecosystem BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Alliance BORG Foundation",
+ "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
new file mode 100644
index 0000000..ebae64a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UK IPO Trademark Journal",
+ "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
+ "type": "docs"
+ },
+ {
+ "name": "Lido Logo",
+ "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..5a79c2d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..30793e1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
+ "evidence": [
+ {
+ "name": "Guardian Role",
+ "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
+ "urls": [
+ {
+ "name": "DepositSecurityModule",
+ "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Lido.sol deposit logic",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
+ "type": "github"
+ },
+ {
+ "name": "Guardians use automated software",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Guardian Accountability",
+ "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
+ "urls": [
+ {
+ "name": "Guardian Committee Membership",
+ "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
+ "type": "docs"
+ },
+ {
+ "name": "Guardians cannot control stake allocation",
+ "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..adf749d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
+ "evidence": [
+ {
+ "name": "Burn Capability",
+ "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
+ "urls": [
+ {
+ "name": "MiniMeToken.destroyTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
+ "type": "github"
+ },
+ {
+ "name": "Aragon ACL",
+ "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Transfer Control",
+ "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
+ "urls": [
+ {
+ "name": "MiniMeToken.enableTransfers",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..3b27084
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,64 @@
+{
+ "status": "positive",
+ "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
+ "evidence": [
+ {
+ "name": "Governance 1A",
+ "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ },
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Governance 1B",
+ "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Easy Track",
+ "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
+ "urls": [
+ {
+ "name": "Easy Track Interface",
+ "url": "https://easytrack.lido.fi/",
+ "type": "docs"
+ },
+ {
+ "name": "Easy Track Guide",
+ "url": "https://docs.lido.fi/guides/easy-track-guide",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..a3a5da8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,48 @@
+{
+ "status": "positive",
+ "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
+ "evidence": [
+ {
+ "name": "Upgradeable Contracts",
+ "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Non-upgradeable Contracts",
+ "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
+ "urls": [
+ {
+ "name": "DualGovernance",
+ "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Executor",
+ "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
+ "type": "explorer"
+ },
+ {
+ "name": "EmergencyProtectedTimeLock",
+ "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..deeabc7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,50 @@
+{
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
+ "evidence": [
+ {
+ "name": "Voting",
+ "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
+ "urls": [
+ {
+ "name": "Voting",
+ "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Agent",
+ "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
+ "urls": [
+ {
+ "name": "Agent",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "TokenManager",
+ "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "StakingRouter",
+ "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..a476ae1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
+ "evidence": [
+ {
+ "name": "Minting Path",
+ "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
+ "urls": [
+ {
+ "name": "MiniMeToken.generateTokens",
+ "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..2f65c1e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
+ "evidence": [
+ {
+ "name": "Token Contract",
+ "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
+ "urls": [
+ {
+ "name": "LDO Token",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Controller Upgrade Path",
+ "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
+ "urls": [
+ {
+ "name": "TokenManager (Aragon App V1 proxy)",
+ "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
+ "type": "explorer"
+ },
+ {
+ "name": "Kernel",
+ "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
new file mode 100644
index 0000000..15c6eb7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..558e4a9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
@@ -0,0 +1,46 @@
+{
+ "status": "positive",
+ "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
+ "evidence": [
+ {
+ "name": "Treasury Fee Flow",
+ "urls": [
+ {
+ "name": "StakingRouter (read contract)",
+ "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
+ "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Buyback Program",
+ "urls": [
+ {
+ "name": "stETH/LDO Buyback Proposal",
+ "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
+ "type": "docs"
+ },
+ {
+ "name": "stETH/LDO Buyback Snapshot Vote",
+ "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
+ "type": "vote"
+ },
+ {
+ "name": "NEST",
+ "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
+ "type": "docs"
+ },
+ {
+ "name": "Liquid buybacks research",
+ "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..0b6d587
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "StakingRouter add/update",
+ "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..57a1dff
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..f1662c6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,28 @@
+{
+ "status": "positive",
+ "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
+ "evidence": [
+ {
+ "name": "Treasury Control",
+ "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
+ "urls": [
+ {
+ "name": "Agent (Treasury)",
+ "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
+ "urls": [
+ {
+ "name": "StakingRouter",
+ "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
new file mode 100644
index 0000000..3fa336c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..cefc201
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Lido core protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Lido Core Contracts (GitHub)",
+ "url": "https://github.com/lidofinance/core",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..713a79f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LDO Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
+ "type": "explorer"
+ },
+ {
+ "name": "MiniMeToken Source (GitHub)",
+ "url": "https://github.com/aragon/minime",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
new file mode 100644
index 0000000..18de867
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
new file mode 100644
index 0000000..110aef5
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..836aa8d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LockupContractFactory (Etherscan)",
+ "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
+ "type": "explorer"
+ },
+ {
+ "name": "CommunityIssuance (Etherscan)",
+ "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
new file mode 100644
index 0000000..df30ae9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
new file mode 100644
index 0000000..cad5d6b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
@@ -0,0 +1,25 @@
+{
+ "status": "partial",
+ "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity Runs on Decentralized Frontends - Official Blog",
+ "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
+ "type": "website"
+ },
+ {
+ "name": "Frontend Operators Page",
+ "url": "https://www.liquity.org/frontend-operators",
+ "type": "website"
+ },
+ {
+ "name": "Liquity Launch Details (AG does not run frontend)",
+ "url": "https://www.liquity.org/blog/liquity-launch-details",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
new file mode 100644
index 0000000..782d787
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
@@ -0,0 +1,25 @@
+{
+ "status": "fail",
+ "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Licensing Liquity V2 - Official Blog",
+ "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
+ "type": "website"
+ },
+ {
+ "name": "Liquity V2 Core LICENSE File (GitHub)",
+ "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
+ "type": "github"
+ },
+ {
+ "name": "What's New in Liquity V2 - Bankless",
+ "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
new file mode 100644
index 0000000..c87d208
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
@@ -0,0 +1,25 @@
+{
+ "status": "fail",
+ "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity AG - Crunchbase Company Profile",
+ "url": "https://www.crunchbase.com/organization/liquity-1d3e",
+ "type": "website"
+ },
+ {
+ "name": "Liquity - Tracxn Company Profile",
+ "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
+ "type": "website"
+ },
+ {
+ "name": "Team Page - Liquity.org",
+ "url": "https://www.liquity.org/team",
+ "type": "website"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..1893248
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..8bca964
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,16 @@
+{
+ "name": "Access Gating",
+ "status": "positive",
+ "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..f76566d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY token's implementation code",
+ "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..ff7b2b4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..c6e33ce
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..02906f9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity - Governance-Free",
+ "url": "https://www.liquity.org/features/governance-free",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..eb35281
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
+ "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..9495e41
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token Source",
+ "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
new file mode 100644
index 0000000..9ad32dc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..f67d587
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
@@ -0,0 +1,40 @@
+{
+ "status": "positive",
+ "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
+ "type": "github"
+ },
+ {
+ "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
+ "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
+ "type": "github"
+ },
+ {
+ "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
+ "url": "https://docs.liquity.org/v2-faq/lqty-staking",
+ "type": "docs"
+ },
+ {
+ "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
+ "type": "github"
+ },
+ {
+ "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
+ "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..c9c1666
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity v2 Technical Docs and Audits",
+ "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
+ "type": "docs"
+ },
+ {
+ "name": "Directing Protocol Incentivized Liquidity with LQTY",
+ "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..54f5685
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..40dc2ab
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Docs",
+ "url": "https://www.liquity.org/blog/liquity-v2-is-live",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
new file mode 100644
index 0000000..53b7a50
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..0170fd6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Liquity protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Liquity V2 Core (GitHub)",
+ "url": "https://github.com/liquity/bold",
+ "type": "github"
+ },
+ {
+ "name": "Liquity V2 Governance (GitHub)",
+ "url": "https://github.com/liquity/V2-gov",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..c4daa88
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "LQTY Token (Etherscan)",
+ "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
+ "type": "explorer"
+ },
+ {
+ "name": "LQTYToken.sol Source (GitHub)",
+ "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
new file mode 100644
index 0000000..6ff8f37
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
new file mode 100644
index 0000000..b811b98
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "at_risk",
+ "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
+ "evidence": [
+ {
+ "name": "Team Holdings",
+ "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
+ "urls": [
+ {
+ "name": "Team Multisig holdings",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..dc07df0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
+ "evidence": [
+ {
+ "name": "Documented Schedule",
+ "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
+ "urls": [
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ },
+ {
+ "name": "CoinList - ONDO Community Sale",
+ "url": "https://coinlist.co/ondo",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
new file mode 100644
index 0000000..cdc655c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
new file mode 100644
index 0000000..e5575dc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Interface Services",
+ "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
new file mode 100644
index 0000000..f3632d4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
@@ -0,0 +1,27 @@
+{
+ "status": "unevaluated",
+ "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
+ "evidence": [
+ {
+ "name": "BUSL-1.1 Source Headers",
+ "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
+ "urls": [
+ {
+ "name": "USDY source SPDX header",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "rOUSG source SPDX header",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
+ "type": "github"
+ },
+ {
+ "name": "BUSL-1.1 license text",
+ "url": "https://spdx.org/licenses/BUSL-1.1.html",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
new file mode 100644
index 0000000..d53d771
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
+ "evidence": [
+ {
+ "name": "Ondo Terms of Service - Proprietary Rights",
+ "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
+ "urls": [
+ {
+ "name": "Terms of Service",
+ "url": "https://docs.ondo.finance/legal/terms-of-service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..c2dfc4d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..3a6f103
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,43 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
+ "evidence": [
+ {
+ "name": "OUSG Transfer Restrictions",
+ "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
+ "urls": [
+ {
+ "name": "OUSG Contract (KYC enforcement)",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG KYC check (source)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
+ "type": "github"
+ },
+ {
+ "name": "KYCRegistry",
+ "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "USDY Transfer Restrictions",
+ "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
+ "urls": [
+ {
+ "name": "USDY restrictions (source)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
+ "type": "github"
+ },
+ {
+ "name": "USDY Contract",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..a5dc7f1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
+ "evidence": [
+ {
+ "name": "No Censorship Capability",
+ "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Source code (ondo-v1)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..4c5b928
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,42 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
+ "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (OUSG admin)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin owner",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..1cee348
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,63 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY (Team-Controlled)",
+ "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
+ "urls": [
+ {
+ "name": "OUSG Proxy",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "OUSG ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Proxy",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY ProxyAdmin Owner (Ethereum)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "Polygon OUSG ProxyAdmin Owner",
+ "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
+ "type": "explorer"
+ },
+ {
+ "name": "Mantle USDY ProxyAdmin Owner",
+ "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
+ "type": "explorer"
+ },
+ {
+ "name": "Arbitrum USDY ProxyAdmin Owner",
+ "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Team-Controlled via TimelockController)",
+ "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
+ "urls": [
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..8e32210
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,94 @@
+{
+ "status": "at_risk",
+ "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
+ "evidence": [
+ {
+ "name": "Team-Controlled Roles (ONDO Token)",
+ "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ },
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (OUSG/USDY)",
+ "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
+ "type": "explorer"
+ },
+ {
+ "name": "Management Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
+ "type": "explorer"
+ },
+ {
+ "name": "rOUSG",
+ "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (4-of-7)",
+ "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
+ "type": "explorer"
+ },
+ {
+ "name": "rUSDY",
+ "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Team-Controlled Roles (Global Markets)",
+ "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ },
+ {
+ "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
+ "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
+ "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
+ "type": "explorer"
+ },
+ {
+ "name": "EXECUTOR_ROLE holder (EOA)",
+ "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
+ "type": "explorer"
+ },
+ {
+ "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
+ "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..fb8a3ba
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,38 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
+ "evidence": [
+ {
+ "name": "Current Supply",
+ "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
+ "urls": [
+ {
+ "name": "ONDO Token totalSupply",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Token Documentation",
+ "url": "https://docs.ondo.foundation/ondo-token",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Mint Function Exists",
+ "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
+ "urls": [
+ {
+ "name": "ONDO Token (verified source)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig (MINTER_ROLE holder)",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..578d308
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
+ "evidence": [
+ {
+ "name": "ONDO Token Roles",
+ "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
+ "urls": [
+ {
+ "name": "ONDO Token",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Team Multisig",
+ "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Contract Source Note",
+ "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
+ "urls": [
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
new file mode 100644
index 0000000..f11d02f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..7939a86
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
@@ -0,0 +1,32 @@
+{
+ "status": "at_risk",
+ "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
+ "evidence": [
+ {
+ "name": "Product Economics vs ONDO Holder Accrual",
+ "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..ee2c0ab
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,48 @@
+{
+ "status": "at_risk",
+ "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY Price Oracles (Company-Controlled)",
+ "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
+ "urls": [
+ {
+ "name": "OUSG Oracle",
+ "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY Oracle",
+ "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
+ "type": "explorer"
+ },
+ {
+ "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
+ "type": "github"
+ },
+ {
+ "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
+ "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets (Company-Controlled via TimelockController)",
+ "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
+ "type": "explorer"
+ },
+ {
+ "name": "Global Markets TimelockController",
+ "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..1c5bd2f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,51 @@
+{
+ "status": "warning",
+ "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": [
+ {
+ "name": "Ondo Product Economics",
+ "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
+ "urls": [
+ {
+ "name": "OUSG Fees",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
+ "type": "docs"
+ },
+ {
+ "name": "OUSG Yield",
+ "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Product Economics",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
+ "type": "docs"
+ },
+ {
+ "name": "USDY Issuer / Ondo Finance Relationship",
+ "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
+ "type": "docs"
+ },
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets Revenue",
+ "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
+ "urls": [
+ {
+ "name": "Global Markets Fees",
+ "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..4157d3a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,17 @@
+{
+ "status": "at_risk",
+ "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
+ "evidence": [
+ {
+ "name": "No Treasury Identified",
+ "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
+ "urls": [
+ {
+ "name": "Ondo DAO Proposals",
+ "url": "https://www.tally.xyz/gov/ondo-dao",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
new file mode 100644
index 0000000..9d49936
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..dc042a9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,51 @@
+{
+ "status": "positive",
+ "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
+ "evidence": [
+ {
+ "name": "OUSG/USDY",
+ "urls": [
+ {
+ "name": "OUSG",
+ "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY",
+ "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDY GitHub",
+ "url": "https://github.com/ondoprotocol/usdy",
+ "type": "github"
+ },
+ {
+ "name": "Audit code (Code4rena)",
+ "url": "https://github.com/code-423n4/2024-03-ondo-finance",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Global Markets",
+ "urls": [
+ {
+ "name": "GMTokenManager",
+ "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDon",
+ "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
+ "type": "explorer"
+ },
+ {
+ "name": "USDonManager",
+ "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..69b23f7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "ONDO Token (Etherscan verified)",
+ "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Public ondo-v1 repo (differs from deployed)",
+ "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
new file mode 100644
index 0000000..d46c247
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not been able to verify the concentration of holdings.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
new file mode 100644
index 0000000..14854bc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify the concentration of holdings.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..ea1ed76
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
@@ -0,0 +1,17 @@
+{
+ "status": "unevaluated",
+ "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
+ "evidence": [
+ {
+ "name": "Vesting Contracts",
+ "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
+ "urls": [
+ {
+ "name": "Vest Contract",
+ "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
new file mode 100644
index 0000000..5919811
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
new file mode 100644
index 0000000..ab1dfb9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
@@ -0,0 +1,17 @@
+{
+ "status": "unevaluated",
+ "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
+ "evidence": [
+ {
+ "name": "Open Source Frontends",
+ "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
+ "urls": [
+ {
+ "name": "Governance Portal Source",
+ "url": "https://github.com/sky-ecosystem/governance-portal-v2",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
new file mode 100644
index 0000000..aa47403
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
+ "evidence": [
+ {
+ "name": "AGPL-3.0 License",
+ "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
+ "urls": [
+ {
+ "name": "License File",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
new file mode 100644
index 0000000..7dda59a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
@@ -0,0 +1,28 @@
+{
+ "status": "warning",
+ "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
+ "evidence": [
+ {
+ "name": "Skybase International Terms of Use",
+ "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
+ "urls": [
+ {
+ "name": "Terms of Use",
+ "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "DAI Foundation",
+ "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
+ "urls": [
+ {
+ "name": "Foundation Website",
+ "url": "https://daifoundation.org",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..17b64c3
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..2a8eb2b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
+ "evidence": [
+ {
+ "name": "Emergency Shutdown",
+ "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
+ "urls": [
+ {
+ "name": "ESM source code",
+ "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
+ "type": "github"
+ },
+ {
+ "name": "ESM contract on Etherscan",
+ "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "No Arbitrary Pause",
+ "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
+ "urls": []
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5515ba9
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
+ "evidence": [
+ {
+ "name": "No Censorship Functions",
+ "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
+ "urls": [
+ {
+ "name": "Transfer Functions (L96-135)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..210d15f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
+ "evidence": [
+ {
+ "name": "Governance Workflow",
+ "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
+ "urls": [
+ {
+ "name": "Voting Contract",
+ "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
+ "type": "explorer"
+ },
+ {
+ "name": "plot() delay enforcement (L111-116)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Timelock Contract",
+ "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
+ "urls": [
+ {
+ "name": "Pause Proxy (Etherscan)",
+ "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
+ "type": "explorer"
+ },
+ {
+ "name": "exec() function (L124-136)",
+ "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..b5ad61d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
+ "evidence": [
+ {
+ "name": "Immutable Core",
+ "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
+ "urls": [
+ {
+ "name": "Vat source code",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
+ "type": "github"
+ },
+ {
+ "name": "SKY token source code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Stablecoins",
+ "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
+ "urls": [
+ {
+ "name": "USDS upgrade authorization",
+ "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
+ "type": "github"
+ },
+ {
+ "name": "sUSDS source code",
+ "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..b56bd54
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
+ "evidence": [
+ {
+ "name": "Core Contracts Controlled by Governance",
+ "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
+ "urls": [
+ {
+ "name": "Vat wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Vow wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "SKY wards() — verify Pause Proxy",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Emergency Controls",
+ "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
+ "urls": [
+ {
+ "name": "Mom authority pattern (source)",
+ "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
+ "type": "github"
+ },
+ {
+ "name": "OSM_MOM — verify authority()",
+ "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..2655fba
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
+ "evidence": [
+ {
+ "name": "Minting Restricted to Governance",
+ "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
+ "urls": [
+ {
+ "name": "mint() function (L146-154)",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "MKR Conversion",
+ "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
+ "urls": [
+ {
+ "name": "rate() returns 24000",
+ "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "Immutable rate declaration",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..8678d04
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
+ "evidence": [
+ {
+ "name": "Non-Upgradeable Token",
+ "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
+ "urls": [
+ {
+ "name": "SKY Token Contract",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
new file mode 100644
index 0000000..0d3d99d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..5595264
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
@@ -0,0 +1,48 @@
+{
+ "status": "positive",
+ "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
+ "evidence": [
+ {
+ "name": "Smart Burn Engine",
+ "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
+ "urls": [
+ {
+ "name": "Splitter contract",
+ "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper (buyback executor)",
+ "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Flapper source code",
+ "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
+ "type": "github"
+ },
+ {
+ "name": "Smart Burn Engine Dashboard",
+ "url": "https://info.sky.money/smart-burn-engine",
+ "type": "docs"
+ }
+ ]
+ },
+ {
+ "name": "Revenue Flow",
+ "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
+ "urls": [
+ {
+ "name": "Stability fee accrual",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
+ "type": "github"
+ },
+ {
+ "name": "Surplus routing to flapper",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..bdb8dc4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
+ "evidence": [
+ {
+ "name": "Fee Rate Control",
+ "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
+ "urls": [
+ {
+ "name": "Jug fee configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
+ "type": "github"
+ },
+ {
+ "name": "Jug contract",
+ "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "Surplus Buffer Control",
+ "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
+ "urls": [
+ {
+ "name": "Vow hump configuration",
+ "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
+ "type": "github"
+ },
+ {
+ "name": "Vow contract — read hump",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..a541c0a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,20 @@
+{
+ "status": "unevaluated",
+ "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": [
+ {
+ "name": "Foundation Independence",
+ "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
+ "urls": [
+ {
+ "name": "Foundation Mandate",
+ "url": "https://daifoundation.org/mandate",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..832c737
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,17 @@
+{
+ "status": "positive",
+ "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
+ "evidence": [
+ {
+ "name": "Onchain Treasury",
+ "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
+ "urls": [
+ {
+ "name": "Treasury Contract",
+ "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
new file mode 100644
index 0000000..7655c73
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..648a473
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
+ "evidence": [
+ {
+ "name": "Open Source Repositories",
+ "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
+ "urls": [
+ {
+ "name": "Core Protocol",
+ "url": "https://github.com/sky-ecosystem/dss",
+ "type": "github"
+ },
+ {
+ "name": "Contract Registry",
+ "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..0d71b8d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
+ "evidence": [
+ {
+ "name": "Verified Source",
+ "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
+ "urls": [
+ {
+ "name": "Source Code",
+ "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
+ "type": "github"
+ },
+ {
+ "name": "Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
new file mode 100644
index 0000000..69c4a54
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
new file mode 100644
index 0000000..110aef5
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..aa8e115
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
@@ -0,0 +1,37 @@
+{
+ "status": "positive",
+ "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
+ "evidence": [
+ {
+ "name": "TreasuryVester Contracts",
+ "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
+ "urls": [
+ {
+ "name": "TreasuryVester Code",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
+ "type": "github"
+ },
+ {
+ "name": "TreasuryVester 1",
+ "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 2",
+ "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 3",
+ "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
+ "type": "explorer"
+ },
+ {
+ "name": "TreasuryVester 4",
+ "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
new file mode 100644
index 0000000..32abe85
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
new file mode 100644
index 0000000..83546db
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Terms of Service",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
new file mode 100644
index 0000000..20a3717
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
@@ -0,0 +1,5 @@
+{
+ "status": "warning",
+ "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
new file mode 100644
index 0000000..def920e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap Labs Trademark Guidelines",
+ "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..a1bf5bc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..81720c4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,5 @@
+{
+ "status": "positive",
+ "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..5f6c7c5
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..4ba972f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..d3f6dd6
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
+ "evidence": [
+ {
+ "name": "Non-upgradeable Protocol Contracts",
+ "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
+ "urls": [
+ {
+ "name": "V2 Factory Create2",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
+ "type": "github"
+ },
+ {
+ "name": "V3 Pool Protection",
+ "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
+ "type": "github"
+ },
+ {
+ "name": "V4 PoolManager: Singleton",
+ "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Upgradeable Governance Contract",
+ "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
+ "urls": [
+ {
+ "name": "GovernorBravoDelegator",
+ "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..981f1bb
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,55 @@
+{
+ "status": "positive",
+ "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
+ "evidence": [
+ {
+ "name": "V2 Factory",
+ "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
+ "urls": [
+ {
+ "name": "V2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Factory",
+ "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
+ "urls": [
+ {
+ "name": "V3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V4 PoolManager",
+ "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
+ "urls": [
+ {
+ "name": "V4PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "UNI Token",
+ "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
+ "urls": [
+ {
+ "name": "UNI Token",
+ "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Timelock (deployed minter)",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..2b18768
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,33 @@
+{
+ "status": "positive",
+ "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
+ "evidence": [
+ {
+ "name": "Inflation Cap",
+ "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
+ "urls": [
+ {
+ "name": "Mint once per year logic",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
+ "type": "github"
+ },
+ {
+ "name": "2% mint cap",
+ "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Minting Control",
+ "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..e50c26f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uni.sol Source",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
+ "type": "github"
+ },
+ {
+ "name": "Etherscan",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
new file mode 100644
index 0000000..3c8d23e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..9360e90
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
@@ -0,0 +1,65 @@
+{
+ "status": "positive",
+ "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
+ "evidence": [
+ {
+ "name": "V2 Fees",
+ "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
+ "urls": [
+ {
+ "name": "UniswapV2Pool: feeTo",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Pool: Fee Destination",
+ "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fees",
+ "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
+ "urls": [
+ {
+ "name": "V3FeeAdapter",
+ "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: collectProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fees",
+ "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
+ "urls": [
+ {
+ "name": "V4 PoolManager",
+ "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
+ "type": "explorer"
+ },
+ {
+ "name": "V4 PoolManager: CollectProtocolFees",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Burn Mechanism",
+ "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
+ "urls": [
+ {
+ "name": "FirePit 4000 UNI Requirement",
+ "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..f500fa5
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,49 @@
+{
+ "status": "positive",
+ "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
+ "evidence": [
+ {
+ "name": "V2 Fee Control",
+ "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV2Factory",
+ "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "V3 Fee Control",
+ "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
+ "urls": [
+ {
+ "name": "UniswapV3Factory",
+ "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
+ "type": "explorer"
+ },
+ {
+ "name": "UniswapV3Pool: setFeeProtocol",
+ "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "V4 Fee Control",
+ "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
+ "urls": [
+ {
+ "name": "PoolManager(V4): setProtocolFee",
+ "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..8c00c48
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,15 @@
+{
+ "status": "unevaluated",
+ "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "DUNI Proposal",
+ "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..2afc7f0
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Timelock",
+ "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
new file mode 100644
index 0000000..40ae2ee
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..5d637b5
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,30 @@
+{
+ "status": "positive",
+ "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "Uniswap V2 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v2-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V3 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v3-core",
+ "type": "github"
+ },
+ {
+ "name": "Uniswap V4 Core (GitHub)",
+ "url": "https://github.com/Uniswap/v4-core",
+ "type": "github"
+ },
+ {
+ "name": "UniswapX (GitHub)",
+ "url": "https://github.com/Uniswap/UniswapX",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..33eea24
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "UNI Token (Etherscan)",
+ "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
+ "type": "explorer"
+ },
+ {
+ "name": "Uni.sol Source (GitHub)",
+ "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
new file mode 100644
index 0000000..d1b94bc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
+ "tags": [
+ "Metric 4"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
new file mode 100644
index 0000000..47c4744
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
+ "evidence": [
+ {
+ "name": "veYB Supply",
+ "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
new file mode 100644
index 0000000..9e11843
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
@@ -0,0 +1,17 @@
+{
+ "status": "warning",
+ "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
+ "evidence": [
+ {
+ "name": "Vesting Schedule",
+ "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
+ "urls": [
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
new file mode 100644
index 0000000..6c4bba4
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
+ "tags": [
+ "Reference"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
new file mode 100644
index 0000000..d5547e1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
@@ -0,0 +1,15 @@
+{
+ "status": "warning",
+ "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YieldBasis Website",
+ "url": "https://yieldbasis.com/",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
new file mode 100644
index 0000000..9374e87
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
@@ -0,0 +1,22 @@
+{
+ "status": "warning",
+ "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
+ "evidence": [
+ {
+ "name": "License Analysis",
+ "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
+ "urls": [
+ {
+ "name": "yb-core contracts directory",
+ "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
+ "type": "github"
+ },
+ {
+ "name": "Curve Licensing Vesting",
+ "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
new file mode 100644
index 0000000..00e0821
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
@@ -0,0 +1,5 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify trademark ownership.",
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
new file mode 100644
index 0000000..03c2d81
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
+ "tags": [
+ "Metric 1"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
new file mode 100644
index 0000000..e2feb0c
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
+ "evidence": [
+ {
+ "name": "Exit Paths",
+ "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
+ "urls": [
+ {
+ "name": "VotingEscrow.withdraw",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor.claim",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
new file mode 100644
index 0000000..e76cece
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
@@ -0,0 +1,15 @@
+{
+ "status": "positive",
+ "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB.vy full source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
new file mode 100644
index 0000000..1b7a16e
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
@@ -0,0 +1,32 @@
+{
+ "status": "positive",
+ "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
+ "evidence": [
+ {
+ "name": "Governance System",
+ "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
+ "urls": [
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB (VotingEscrow)",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "TokenVoting Plugin",
+ "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
+ "type": "explorer"
+ },
+ {
+ "name": "Governance Documentation",
+ "url": "https://docs.yieldbasis.com/user/governance",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
new file mode 100644
index 0000000..e0368ef
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
+ "evidence": [
+ {
+ "name": "Upgrade Path",
+ "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
+ "urls": [
+ {
+ "name": "Factory Contract",
+ "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
+ "type": "explorer"
+ },
+ {
+ "name": "Factory.set_implementations",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
+ "type": "github"
+ },
+ {
+ "name": "MigrationFactoryOwner ADMIN immutable",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
new file mode 100644
index 0000000..93f7045
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
@@ -0,0 +1,43 @@
+{
+ "status": "positive",
+ "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
+ "evidence": [
+ {
+ "name": "DAO-Controlled Contracts",
+ "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
+ "urls": [
+ {
+ "name": "GaugeController",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ },
+ {
+ "name": "FeeDistributor",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "MigrationFactoryOwner",
+ "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
+ "type": "explorer"
+ }
+ ]
+ },
+ {
+ "name": "veYB Owner (_yb.eth)",
+ "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
+ "urls": [
+ {
+ "name": "veYB Contract",
+ "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
+ "type": "explorer"
+ },
+ {
+ "name": "set_transfer_clearance_checker",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
new file mode 100644
index 0000000..0203010
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
@@ -0,0 +1,27 @@
+{
+ "status": "positive",
+ "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
+ "evidence": [
+ {
+ "name": "Emission Mechanism",
+ "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
+ "urls": [
+ {
+ "name": "get_adjustment (minting rate)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
+ "type": "github"
+ },
+ {
+ "name": "YB.emit function",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
+ "type": "github"
+ },
+ {
+ "name": "Tokenomics",
+ "url": "https://docs.yieldbasis.com/user/tokenomics",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
new file mode 100644
index 0000000..788c4e7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
+ "evidence": [
+ {
+ "name": "Token Ownership",
+ "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
+ "urls": [
+ {
+ "name": "YB Token Contract",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "renounce_ownership",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
new file mode 100644
index 0000000..689d6be
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
+ "tags": [
+ "Metric 2"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
new file mode 100644
index 0000000..dd9e19d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
@@ -0,0 +1,42 @@
+{
+ "status": "positive",
+ "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
+ "evidence": [
+ {
+ "name": "Fee Flow",
+ "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
+ "urls": [
+ {
+ "name": "LT.withdraw_admin_fees",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
+ "type": "github"
+ },
+ {
+ "name": "Factory.fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
+ "type": "github"
+ },
+ {
+ "name": "FeeDistributor Contract",
+ "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
+ "type": "explorer"
+ },
+ {
+ "name": "veYB Documentation",
+ "url": "https://docs.yieldbasis.com/user/veyb",
+ "type": "docs"
+ },
+ {
+ "name": "Fee Data (ValueVerse)",
+ "url": "https://yb.valueverse.ai",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
new file mode 100644
index 0000000..8b8ce8b
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
@@ -0,0 +1,38 @@
+{
+ "status": "positive",
+ "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
+ "evidence": [
+ {
+ "name": "Fee Flow Direction",
+ "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
+ "urls": [
+ {
+ "name": "MigrationFactoryOwner.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
+ "type": "github"
+ },
+ {
+ "name": "Factory.set_fee_receiver",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
+ "type": "github"
+ }
+ ]
+ },
+ {
+ "name": "Gauge Voting",
+ "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
+ "urls": [
+ {
+ "name": "vote_for_gauge_weights",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
+ "type": "github"
+ },
+ {
+ "name": "GaugeController Contract",
+ "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
new file mode 100644
index 0000000..084ddf2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
@@ -0,0 +1,8 @@
+{
+ "status": "unevaluated",
+ "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
+ "tags": [
+ "Reference"
+ ],
+ "evidence": []
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
new file mode 100644
index 0000000..ed8c75a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
@@ -0,0 +1,27 @@
+{
+ "status": "at_risk",
+ "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
+ "evidence": [
+ {
+ "name": "Ecosystem Reserve",
+ "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
+ "urls": [
+ {
+ "name": "Ecosystem Reserve",
+ "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
+ "type": "explorer"
+ },
+ {
+ "name": "Ecosystem Reserve Owner (EOA)",
+ "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
+ "type": "explorer"
+ },
+ {
+ "name": "DAO Contract",
+ "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
+ "type": "explorer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
new file mode 100644
index 0000000..df29e57
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
@@ -0,0 +1,6 @@
+{
+ "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
+ "tags": [
+ "Metric 3"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
new file mode 100644
index 0000000..57de733
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
@@ -0,0 +1,22 @@
+{
+ "status": "positive",
+ "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
+ "evidence": [
+ {
+ "name": "Verification and Audits",
+ "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
+ "urls": [
+ {
+ "name": "yb-core GitHub Repository",
+ "url": "https://github.com/yield-basis/yb-core",
+ "type": "github"
+ },
+ {
+ "name": "Audit Reports",
+ "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
+ "type": "docs"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
new file mode 100644
index 0000000..fe6d309
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
@@ -0,0 +1,20 @@
+{
+ "status": "positive",
+ "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
+ "evidence": [
+ {
+ "urls": [
+ {
+ "name": "YB Token Verified on Etherscan",
+ "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
+ "type": "explorer"
+ },
+ {
+ "name": "YB.vy Source",
+ "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
+ "type": "github"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/faq.json b/tests/fixtures/content-6b17fa7/faq.json
new file mode 100644
index 0000000..64170db
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/faq.json
@@ -0,0 +1,60 @@
+{
+ "topics": [
+ {
+ "id": "basics",
+ "name": "Basics",
+ "about": "Core definitions and how to use the framework.",
+ "questions": [
+ {
+ "id": "basics__ownership-token",
+ "question": "What is an ownership token?",
+ "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
+ },
+ {
+ "id": "basics__how-to-use",
+ "question": "How can I use the Ownership Token Framework?",
+ "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
+ }
+ ]
+ },
+ {
+ "id": "methodology",
+ "name": "Methodology",
+ "about": "How evaluation, sourcing, and verification work.",
+ "questions": [
+ {
+ "id": "methodology__evaluation",
+ "question": "How do you evaluate tokens?",
+ "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ },
+ {
+ "id": "methodology__evidence",
+ "question": "How do you source and verify evidence?",
+ "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
+ }
+ ]
+ },
+ {
+ "id": "participation",
+ "name": "Participation",
+ "about": "How tokens are selected and how to get involved.",
+ "questions": [
+ {
+ "id": "participation__selection",
+ "question": "How do you choose which tokens to feature?",
+ "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
+ },
+ {
+ "id": "participation__listing",
+ "question": "How can I get a token listed?",
+ "answer": "Submit a request (or refer a token) using this [here](submit-token)."
+ },
+ {
+ "id": "participation__contribute",
+ "question": "How can I contribute to this initiative?",
+ "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/_meta.json b/tests/fixtures/content-6b17fa7/framework/_meta.json
new file mode 100644
index 0000000..2f58a3f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/_meta.json
@@ -0,0 +1,10 @@
+{
+ "baseUrl": "https://github.com/aragon/ownership-token-framework/blob/development/README.md",
+ "order": [
+ "onchain-ctrl",
+ "val-accrual",
+ "verifiability",
+ "distribution",
+ "offchain"
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/distribution.json b/tests/fixtures/content-6b17fa7/framework/distribution.json
new file mode 100644
index 0000000..52be47f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/distribution.json
@@ -0,0 +1,19 @@
+{
+ "id": "distribution",
+ "name": "Metric 4: Token Distribution",
+ "displayName": "Token Distribution",
+ "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
+ "anchor": "#metric-4-token-distribution",
+ "criteria": [
+ {
+ "id": "distribution__concentration",
+ "name": "Ownership Concentration",
+ "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
+ },
+ {
+ "id": "distribution__supply-schedule",
+ "name": "Future Token Unlocks",
+ "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/offchain.json b/tests/fixtures/content-6b17fa7/framework/offchain.json
new file mode 100644
index 0000000..9dc3d8d
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/offchain.json
@@ -0,0 +1,24 @@
+{
+ "id": "offchain",
+ "name": "Offchain Dependencies",
+ "displayName": "Offchain Dependencies",
+ "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
+ "anchor": "#offchain-dependencies",
+ "criteria": [
+ {
+ "id": "offchain__trademark",
+ "name": "Trademark",
+ "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__distribution",
+ "name": "Distribution",
+ "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
+ },
+ {
+ "id": "offchain__licensing",
+ "name": "Licensing",
+ "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json b/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
new file mode 100644
index 0000000..57f816a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
@@ -0,0 +1,44 @@
+{
+ "id": "onchain-ctrl",
+ "name": "Metric 1: Onchain Control",
+ "displayName": "Onchain Control",
+ "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
+ "anchor": "#metric-1-onchain-control",
+ "criteria": [
+ {
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Onchain Governance Workflow",
+ "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
+ },
+ {
+ "id": "onchain-ctrl__role-accountability",
+ "name": "Role Accountability",
+ "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__protocol-upgrade",
+ "name": "Protocol Upgrade Authority",
+ "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
+ },
+ {
+ "id": "onchain-ctrl__token-upgrade",
+ "name": "Token Upgrade Authority",
+ "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
+ },
+ {
+ "id": "onchain-ctrl__supply",
+ "name": "Supply Control",
+ "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
+ },
+ {
+ "id": "onchain-ctrl__access-gating",
+ "name": "Privileged Access Gating",
+ "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
+ },
+ {
+ "id": "onchain-ctrl__censorship",
+ "name": "Token Censorship",
+ "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/val-accrual.json b/tests/fixtures/content-6b17fa7/framework/val-accrual.json
new file mode 100644
index 0000000..676fa1a
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/val-accrual.json
@@ -0,0 +1,29 @@
+{
+ "id": "val-accrual",
+ "name": "Metric 2: Value Accrual",
+ "displayName": "Value Accrual",
+ "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
+ "anchor": "#metric-2-value-accrual",
+ "criteria": [
+ {
+ "id": "val-accrual__active",
+ "name": "Accrual Active",
+ "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
+ },
+ {
+ "id": "val-accrual__treasury",
+ "name": "Treasury Ownership",
+ "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
+ },
+ {
+ "id": "val-accrual__mechanism",
+ "name": "Accrual Mechanism Control",
+ "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
+ },
+ {
+ "id": "val-accrual__offchain",
+ "name": "Offchain Value Accrual",
+ "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/framework/verifiability.json b/tests/fixtures/content-6b17fa7/framework/verifiability.json
new file mode 100644
index 0000000..9e0f5b8
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/framework/verifiability.json
@@ -0,0 +1,19 @@
+{
+ "id": "verifiability",
+ "name": "Metric 3: Verifiability",
+ "displayName": "Verifiability",
+ "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
+ "anchor": "#metric-3-verifiability",
+ "criteria": [
+ {
+ "id": "verifiability__token-source",
+ "name": "Token Contract Source Verification",
+ "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
+ },
+ {
+ "id": "verifiability__protocol-source",
+ "name": "Protocol Component Source Verification",
+ "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/testimonials.json b/tests/fixtures/content-6b17fa7/testimonials.json
new file mode 100644
index 0000000..2846926
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/testimonials.json
@@ -0,0 +1,21 @@
+{
+ "title": "Evidence-backed due diligence for investors",
+ "testimonials": [
+ {
+ "id": "miles-a16z",
+ "name": "Miles Jennings",
+ "organization": "a16z",
+ "avatar": "/images/testimonials/miles-jennings.png",
+ "url": "https://a16zcrypto.com/",
+ "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
+ },
+ {
+ "id": "f5-crypto",
+ "name": "Paul Otto",
+ "organization": "F5 Crypto",
+ "avatar": "/images/testimonials/paul-otto.png",
+ "url": "https://f5crypto.com/en/",
+ "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
+ }
+ ]
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/aave.json b/tests/fixtures/content-6b17fa7/tokens/aave.json
new file mode 100644
index 0000000..96d8e46
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/aave.json
@@ -0,0 +1,21 @@
+{
+ "id": "aave",
+ "coingeckoId": "aave",
+ "name": "AAVE",
+ "symbol": "AAVE",
+ "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
+ "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
+ "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aave.com/",
+ "twitter": "https://twitter.com/aave",
+ "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
+ },
+ "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/aero.json b/tests/fixtures/content-6b17fa7/tokens/aero.json
new file mode 100644
index 0000000..fe193fc
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/aero.json
@@ -0,0 +1,21 @@
+{
+ "id": "aero",
+ "coingeckoId": "aerodrome-finance",
+ "name": "AERO",
+ "symbol": "AERO",
+ "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
+ "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
+ "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
+ "network": "base",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://aerodrome.finance/",
+ "twitter": "https://twitter.com/Aerodrome",
+ "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
+ },
+ "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/crv.json b/tests/fixtures/content-6b17fa7/tokens/crv.json
new file mode 100644
index 0000000..7db7514
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/crv.json
@@ -0,0 +1,21 @@
+{
+ "id": "crv",
+ "coingeckoId": "curve-dao-token",
+ "name": "CRV",
+ "symbol": "CRV",
+ "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
+ "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
+ "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://curve.finance/",
+ "twitter": "https://twitter.com/curvefinance",
+ "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
+ },
+ "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ena.json b/tests/fixtures/content-6b17fa7/tokens/ena.json
new file mode 100644
index 0000000..5b0151f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/ena.json
@@ -0,0 +1,21 @@
+{
+ "id": "ena",
+ "coingeckoId": "ethena",
+ "name": "ENA",
+ "symbol": "ENA",
+ "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
+ "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
+ "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ethena.fi/",
+ "twitter": "https://twitter.com/ethena",
+ "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
+ },
+ "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ethfi.json b/tests/fixtures/content-6b17fa7/tokens/ethfi.json
new file mode 100644
index 0000000..1e86fa1
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/ethfi.json
@@ -0,0 +1,21 @@
+{
+ "id": "ethfi",
+ "coingeckoId": "ether-fi",
+ "name": "ETHFI",
+ "symbol": "ETHFI",
+ "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
+ "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
+ "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ether.fi/",
+ "twitter": "https://twitter.com/ether_fi",
+ "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
+ },
+ "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ldo.json b/tests/fixtures/content-6b17fa7/tokens/ldo.json
new file mode 100644
index 0000000..386c487
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/ldo.json
@@ -0,0 +1,21 @@
+{
+ "id": "ldo",
+ "coingeckoId": "lido-dao",
+ "name": "LDO",
+ "symbol": "LDO",
+ "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
+ "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
+ "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
+ "network": "ethereum",
+ "lastUpdated": 1777631939,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://lido.fi/",
+ "twitter": "https://twitter.com/lidofinance",
+ "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
+ },
+ "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/lqty.json b/tests/fixtures/content-6b17fa7/tokens/lqty.json
new file mode 100644
index 0000000..406fd2f
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/lqty.json
@@ -0,0 +1,21 @@
+{
+ "id": "lqty",
+ "coingeckoId": "liquity",
+ "name": "LQTY",
+ "symbol": "LQTY",
+ "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
+ "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
+ "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
+ "network": "ethereum",
+ "lastUpdated": 1778064256,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://www.liquity.org/",
+ "twitter": "https://twitter.com/LiquityProtocol",
+ "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
+ },
+ "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ondo.json b/tests/fixtures/content-6b17fa7/tokens/ondo.json
new file mode 100644
index 0000000..fa64d38
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/ondo.json
@@ -0,0 +1,21 @@
+{
+ "id": "ondo",
+ "name": "ONDO",
+ "symbol": "ONDO",
+ "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
+ "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
+ "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
+ "network": "ethereum",
+ "lastUpdated": 1778674909,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://ondo.finance/",
+ "twitter": "https://twitter.com/OndoFinance",
+ "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
+ },
+ "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
+ "coingeckoId": "ondo-finance"
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/sky.json b/tests/fixtures/content-6b17fa7/tokens/sky.json
new file mode 100644
index 0000000..bd377b7
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/sky.json
@@ -0,0 +1,21 @@
+{
+ "id": "sky",
+ "coingeckoId": "sky",
+ "name": "SKY",
+ "symbol": "SKY",
+ "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
+ "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
+ "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://sky.money/",
+ "twitter": "https://twitter.com/SkyEcosystem",
+ "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
+ },
+ "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/uni.json b/tests/fixtures/content-6b17fa7/tokens/uni.json
new file mode 100644
index 0000000..f3142e2
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/uni.json
@@ -0,0 +1,21 @@
+{
+ "id": "uni",
+ "coingeckoId": "uniswap",
+ "name": "UNI",
+ "symbol": "UNI",
+ "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
+ "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
+ "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
+ "network": "ethereum",
+ "lastUpdated": 1775651992,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://uniswap.org/",
+ "twitter": "https://twitter.com/uniswap",
+ "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
+ },
+ "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
+}
diff --git a/tests/fixtures/content-6b17fa7/tokens/yb.json b/tests/fixtures/content-6b17fa7/tokens/yb.json
new file mode 100644
index 0000000..7f9c298
--- /dev/null
+++ b/tests/fixtures/content-6b17fa7/tokens/yb.json
@@ -0,0 +1,21 @@
+{
+ "id": "yb",
+ "coingeckoId": "yield-basis",
+ "name": "YB",
+ "symbol": "YB",
+ "address": "0x01791F726B4103694969820be083196cC7c045fF",
+ "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
+ "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
+ "network": "ethereum",
+ "lastUpdated": 1774549304,
+ "updatedBy": {
+ "avatar": "/logo192.png",
+ "name": "Aragon Developers"
+ },
+ "links": {
+ "website": "https://yieldbasis.com/",
+ "twitter": "https://x.com/yieldbasis",
+ "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
+ },
+ "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
+}
diff --git a/tests/round-trip.test.ts b/tests/round-trip.test.ts
index 244f13b..af6f9a3 100644
--- a/tests/round-trip.test.ts
+++ b/tests/round-trip.test.ts
@@ -1,12 +1,20 @@
/**
- * Round-trip gate: composed read models must reproduce the golden fixtures
- * captured from the pre-refactor runtime (tests/golden/, frozen 2026-06-05).
+ * Round-trip gate: the COMPOSER's join/scoring logic must reproduce the
+ * golden fixtures captured from the pre-refactor runtime (tests/golden/,
+ * frozen 2026-06-05) when run over the frozen content snapshot
+ * (tests/fixtures/content-6b17fa7/, the atoms as migrated at commit 6b17fa7).
+ *
+ * Both inputs and expectations are frozen: this permanently regression-tests
+ * the composition logic without breaking when live content/ legitimately
+ * evolves (editorial edits, CI timestamp updates). Live content is covered
+ * by atoms-valid.test.ts (schemas) and freshness.test.ts (generated parity).
*
* ONE intentional diff is allowed and asserted explicitly: the token status
- * counts (positive/neutral/atRisk/evidenceEntries) are now DERIVED from
+ * counts (positive/neutral/atRisk/evidenceEntries) are DERIVED from
* evaluations at compose time — the legacy hand-maintained counts were stale
* for all 11 tokens and are corrected, not preserved.
*/
+import { join } from "node:path"
import { describe, expect, it } from "vitest"
// biome-ignore lint/style/noNamespaceImport: JSON module namespaces
import goldenFaq from "./golden/faq.json"
@@ -27,7 +35,7 @@ const withoutCounts = (obj: Record) =>
)
)
-const composed = composeAll()
+const composed = composeAll(join(__dirname, "fixtures", "content-6b17fa7"))
describe("round-trip vs golden fixtures", () => {
it("covers every golden token, none extra", () => {
From d2fce63e8ad42bd6434a5005847a9de85f80cb77 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 13:02:17 +0200
Subject: [PATCH 04/38] feat: add canonical token JSON endpoints with
provenance envelope
---
scripts/compose-data.mjs | 27 ++++++++--
src/data/generated/manifest.json | 16 ++++++
src/lib/schemas/read-models.ts | 28 +++++++++++
src/lib/server/published-data.ts | 57 +++++++++++++++++++++
src/lib/server/token-api.ts | 54 ++++++++++++++++++++
src/routeTree.gen.ts | 63 +++++++++++++++++++++--
src/routes/api.tokens.$tokenId.ts | 10 ++++
src/routes/api.tokens.ts | 10 ++++
tests/api-endpoints.test.ts | 83 +++++++++++++++++++++++++++++++
tests/freshness.test.ts | 6 +++
10 files changed, 347 insertions(+), 7 deletions(-)
create mode 100644 src/data/generated/manifest.json
create mode 100644 src/lib/server/published-data.ts
create mode 100644 src/lib/server/token-api.ts
create mode 100644 src/routes/api.tokens.$tokenId.ts
create mode 100644 src/routes/api.tokens.ts
create mode 100644 tests/api-endpoints.test.ts
diff --git a/scripts/compose-data.mjs b/scripts/compose-data.mjs
index 49b22fe..74c6fb6 100644
--- a/scripts/compose-data.mjs
+++ b/scripts/compose-data.mjs
@@ -14,6 +14,7 @@
*
* Exports composeAll() for tests; run directly to write src/data/generated/.
*/
+import { createHash } from "node:crypto"
import {
mkdirSync,
readdirSync,
@@ -140,18 +141,35 @@ export function composeAll(dir = contentDir) {
}
const frameworkDoc = { baseUrl: meta.baseUrl, metrics: framework }
+ const faq = readJson(join(dir, "faq.json"))
+ const testimonials = readJson(join(dir, "testimonials.json"))
+
+ // Deterministic snapshot identity: a content hash over the composed output.
+ // Stable across recompositions of identical content (keeps the freshness
+ // gate meaningful); changes exactly when published data changes. The future
+ // publish pipeline reuses this as the R2 snapshot key component.
+ const snapshotId = createHash("sha256")
+ .update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
+ .digest("hex")
+ .slice(0, 16)
+ const manifest = {
+ snapshot_id: snapshotId,
+ tokens: tokenDocs.map((d) => d.id),
+ }
return {
index,
tokenDocs,
frameworkDoc,
- faq: readJson(join(dir, "faq.json")),
- testimonials: readJson(join(dir, "testimonials.json")),
+ faq,
+ testimonials,
+ manifest,
}
}
function main() {
- const { index, tokenDocs, frameworkDoc, faq, testimonials } = composeAll()
+ const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
+ composeAll()
rmSync(generatedDir, { recursive: true, force: true })
const writeJson = (p, data) => {
@@ -166,9 +184,10 @@ function main() {
writeJson(join(generatedDir, "framework.json"), frameworkDoc)
writeJson(join(generatedDir, "faq.json"), faq)
writeJson(join(generatedDir, "testimonials.json"), testimonials)
+ writeJson(join(generatedDir, "manifest.json"), manifest)
console.log(
- `composed: index (${index.tokens.length} rows), ${tokenDocs.length} token docs, framework, faq, testimonials`
+ `composed: index (${index.tokens.length} rows), ${tokenDocs.length} token docs, framework, faq, testimonials (snapshot ${manifest.snapshot_id})`
)
}
diff --git a/src/data/generated/manifest.json b/src/data/generated/manifest.json
new file mode 100644
index 0000000..854d06e
--- /dev/null
+++ b/src/data/generated/manifest.json
@@ -0,0 +1,16 @@
+{
+ "snapshot_id": "1daba5411687dfd1",
+ "tokens": [
+ "aave",
+ "aero",
+ "crv",
+ "ena",
+ "ethfi",
+ "ldo",
+ "lqty",
+ "ondo",
+ "sky",
+ "uni",
+ "yb"
+ ]
+}
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
index 5ebb660..d946f6c 100644
--- a/src/lib/schemas/read-models.ts
+++ b/src/lib/schemas/read-models.ts
@@ -106,6 +106,31 @@ export const frameworkDocSchema = z.strictObject({
),
})
+/** generated/manifest.json — deterministic snapshot identity for the composed set. */
+export const manifestSchema = z.strictObject({
+ /** Content hash over the composed output; future R2 snapshot key component. */
+ snapshot_id: z.string(),
+ tokens: z.array(z.string()),
+})
+
+/**
+ * Provenance envelope wrapped around every API response.
+ * published_at stays null until the publish pipeline stamps real publishes.
+ */
+export const provenanceSchema = z.strictObject({
+ snapshot_id: z.string(),
+ commit_ref: z.string(),
+ published_at: z.string().nullable(),
+ source: z.enum(["generated", "kv"]),
+})
+
+export const apiErrorSchema = z.strictObject({
+ error: z.strictObject({
+ code: z.string(),
+ message: z.string(),
+ }),
+})
+
export type ComposedCriterion = z.infer
export type ComposedMetric = z.infer
export type MetricScore = z.infer
@@ -114,3 +139,6 @@ export type TokenCounts = z.infer
export type IndexRow = z.infer
export type TokenDoc = z.infer
export type FrameworkDoc = z.infer
+export type Manifest = z.infer
+export type Provenance = z.infer
+export type ApiError = z.infer
diff --git a/src/lib/server/published-data.ts b/src/lib/server/published-data.ts
new file mode 100644
index 0000000..e9cca4d
--- /dev/null
+++ b/src/lib/server/published-data.ts
@@ -0,0 +1,57 @@
+/**
+ * Published-data source for the canonical API endpoints.
+ *
+ * This is the transport seam: today it reads the committed composed read
+ * models (src/data/generated/); when the publish pipeline lands, a KV-backed
+ * implementation replaces the internals without any response-shape change —
+ * consumers depend only on this module's interface.
+ */
+import indexData from "@/data/generated/index.json"
+import manifestData from "@/data/generated/manifest.json"
+import type { IndexRow, Manifest, Provenance, TokenDoc } from "@/lib/schemas"
+
+const manifest = manifestData as Manifest
+
+const tokenDocModules = import.meta.glob<{ default: TokenDoc }>(
+ "../../data/generated/tokens/*.json",
+ { eager: true }
+)
+
+const tokenDocs = new Map(
+ Object.values(tokenDocModules).map((mod) => [mod.default.id, mod.default])
+)
+
+/**
+ * Commit ref resolved from the deployment environment at request time.
+ * Falls back to "dev" outside CI/deploy contexts so the field is never null.
+ */
+function resolveCommitRef(): string {
+ return (
+ process.env.VERCEL_GIT_COMMIT_SHA ??
+ process.env.CF_PAGES_COMMIT_SHA ??
+ process.env.GITHUB_SHA ??
+ "dev"
+ )
+}
+
+export function getProvenance(): Provenance {
+ return {
+ snapshot_id: manifest.snapshot_id,
+ commit_ref: resolveCommitRef(),
+ // Stamped by the publish pipeline once snapshots are actually published.
+ published_at: null,
+ source: "generated",
+ }
+}
+
+export function getPublishedIndex(): { tokens: IndexRow[] } {
+ return indexData as { tokens: IndexRow[] }
+}
+
+export function getPublishedTokenDoc(tokenId: string): TokenDoc | null {
+ return tokenDocs.get(tokenId.trim().toLowerCase()) ?? null
+}
+
+export function listPublishedTokenIds(): string[] {
+ return manifest.tokens
+}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
new file mode 100644
index 0000000..db1f228
--- /dev/null
+++ b/src/lib/server/token-api.ts
@@ -0,0 +1,54 @@
+/**
+ * Handlers for the canonical token JSON API. Kept separate from the route
+ * files so they are directly unit-testable; routes are thin wrappers.
+ *
+ * Response contract (consumed by the app, future APP-796 agents, and
+ * external partners):
+ * { data: , provenance: { snapshot_id, commit_ref, published_at, source } }
+ *
+ * NOTE: the route parameter is the token `id` (lowercase, e.g. "ldo") —
+ * matching generated/tokens/.json and the existing /tokens/$tokenId page
+ * route. APP-796's "{symbol}" wording resolves to this id (symbols lowercase
+ * to ids for all current tokens).
+ */
+import {
+ getProvenance,
+ getPublishedIndex,
+ getPublishedTokenDoc,
+} from "@/lib/server/published-data"
+
+function jsonResponse(body: unknown, status = 200): Response {
+ return new Response(JSON.stringify(body), {
+ status,
+ headers: {
+ "Content-Type": "application/json",
+ // Canonical published data: cacheable, must revalidate on new deploys.
+ "Cache-Control": "public, max-age=60, stale-while-revalidate=300",
+ },
+ })
+}
+
+/** GET /api/tokens — the published index (discovery + cross-token queries). */
+export function handleGetTokens(): Response {
+ return jsonResponse({
+ data: getPublishedIndex(),
+ provenance: getProvenance(),
+ })
+}
+
+/** GET /api/tokens/{id} — one composed token doc (the per-token reusable unit). */
+export function handleGetToken(tokenId: string): Response {
+ const doc = getPublishedTokenDoc(tokenId)
+ if (!doc) {
+ return jsonResponse(
+ {
+ error: {
+ code: "TOKEN_NOT_FOUND",
+ message: `No published token with id "${tokenId.trim().toLowerCase()}"`,
+ },
+ },
+ 404
+ )
+ }
+ return jsonResponse({ data: doc, provenance: getProvenance() })
+}
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 94bc6f0..32ef9cc 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -12,6 +12,8 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as FaqRouteImport } from './routes/faq'
import { Route as IndexRouteImport } from './routes/index'
import { Route as TokensTokenIdRouteImport } from './routes/tokens/$tokenId'
+import { Route as ApiTokensRouteImport } from './routes/api.tokens'
+import { Route as ApiTokensTokenIdRouteImport } from './routes/api.tokens.$tokenId'
const FaqRoute = FaqRouteImport.update({
id: '/faq',
@@ -28,34 +30,62 @@ const TokensTokenIdRoute = TokensTokenIdRouteImport.update({
path: '/tokens/$tokenId',
getParentRoute: () => rootRouteImport,
} as any)
+const ApiTokensRoute = ApiTokensRouteImport.update({
+ id: '/api/tokens',
+ path: '/api/tokens',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const ApiTokensTokenIdRoute = ApiTokensTokenIdRouteImport.update({
+ id: '/$tokenId',
+ path: '/$tokenId',
+ getParentRoute: () => ApiTokensRoute,
+} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
+ '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
+ '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
+ '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/faq' | '/tokens/$tokenId'
+ fullPaths:
+ | '/'
+ | '/faq'
+ | '/api/tokens'
+ | '/tokens/$tokenId'
+ | '/api/tokens/$tokenId'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '/faq' | '/tokens/$tokenId'
- id: '__root__' | '/' | '/faq' | '/tokens/$tokenId'
+ to: '/' | '/faq' | '/api/tokens' | '/tokens/$tokenId' | '/api/tokens/$tokenId'
+ id:
+ | '__root__'
+ | '/'
+ | '/faq'
+ | '/api/tokens'
+ | '/tokens/$tokenId'
+ | '/api/tokens/$tokenId'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
FaqRoute: typeof FaqRoute
+ ApiTokensRoute: typeof ApiTokensRouteWithChildren
TokensTokenIdRoute: typeof TokensTokenIdRoute
}
@@ -82,12 +112,39 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof TokensTokenIdRouteImport
parentRoute: typeof rootRouteImport
}
+ '/api/tokens': {
+ id: '/api/tokens'
+ path: '/api/tokens'
+ fullPath: '/api/tokens'
+ preLoaderRoute: typeof ApiTokensRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/api/tokens/$tokenId': {
+ id: '/api/tokens/$tokenId'
+ path: '/$tokenId'
+ fullPath: '/api/tokens/$tokenId'
+ preLoaderRoute: typeof ApiTokensTokenIdRouteImport
+ parentRoute: typeof ApiTokensRoute
+ }
}
}
+interface ApiTokensRouteChildren {
+ ApiTokensTokenIdRoute: typeof ApiTokensTokenIdRoute
+}
+
+const ApiTokensRouteChildren: ApiTokensRouteChildren = {
+ ApiTokensTokenIdRoute: ApiTokensTokenIdRoute,
+}
+
+const ApiTokensRouteWithChildren = ApiTokensRoute._addFileChildren(
+ ApiTokensRouteChildren,
+)
+
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
FaqRoute: FaqRoute,
+ ApiTokensRoute: ApiTokensRouteWithChildren,
TokensTokenIdRoute: TokensTokenIdRoute,
}
export const routeTree = rootRouteImport
diff --git a/src/routes/api.tokens.$tokenId.ts b/src/routes/api.tokens.$tokenId.ts
new file mode 100644
index 0000000..ca367ca
--- /dev/null
+++ b/src/routes/api.tokens.$tokenId.ts
@@ -0,0 +1,10 @@
+import { createFileRoute } from "@tanstack/react-router"
+import { handleGetToken } from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/tokens/$tokenId")({
+ server: {
+ handlers: {
+ GET: ({ params }) => handleGetToken(params.tokenId),
+ },
+ },
+})
diff --git a/src/routes/api.tokens.ts b/src/routes/api.tokens.ts
new file mode 100644
index 0000000..5cf9189
--- /dev/null
+++ b/src/routes/api.tokens.ts
@@ -0,0 +1,10 @@
+import { createFileRoute } from "@tanstack/react-router"
+import { handleGetTokens } from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/tokens")({
+ server: {
+ handlers: {
+ GET: () => handleGetTokens(),
+ },
+ },
+})
diff --git a/tests/api-endpoints.test.ts b/tests/api-endpoints.test.ts
new file mode 100644
index 0000000..5b43cad
--- /dev/null
+++ b/tests/api-endpoints.test.ts
@@ -0,0 +1,83 @@
+/**
+ * Canonical token API handlers: envelope contract, payload parity with the
+ * generated read models, and structured 404s.
+ */
+import { readFileSync } from "node:fs"
+import { join } from "node:path"
+import { describe, expect, it } from "vitest"
+import {
+ apiErrorSchema,
+ indexSchema,
+ provenanceSchema,
+ tokenDocSchema,
+} from "@/lib/schemas"
+import { handleGetToken, handleGetTokens } from "@/lib/server/token-api"
+
+const generated = join(__dirname, "..", "src", "data", "generated")
+const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
+
+const TOKEN_IDS = readJson(join(generated, "manifest.json")).tokens as string[]
+
+async function body(res: Response) {
+ return JSON.parse(await res.text())
+}
+
+describe("GET /api/tokens", () => {
+ it("returns the published index wrapped in a provenance envelope", async () => {
+ const res = handleGetTokens()
+ expect(res.status).toBe(200)
+ expect(res.headers.get("Content-Type")).toBe("application/json")
+
+ const payload = await body(res)
+ expect(() => provenanceSchema.parse(payload.provenance)).not.toThrow()
+ expect(() => indexSchema.parse(payload.data)).not.toThrow()
+ })
+
+ it("data payload is identical to generated/index.json", async () => {
+ const payload = await body(handleGetTokens())
+ expect(payload.data).toEqual(readJson(join(generated, "index.json")))
+ })
+
+ it("envelope: commit_ref non-null, published_at null pre-pipeline, snapshot_id matches manifest", async () => {
+ const { provenance } = await body(handleGetTokens())
+ expect(provenance.commit_ref).toBeTruthy()
+ expect(provenance.published_at).toBeNull()
+ expect(provenance.source).toBe("generated")
+ expect(provenance.snapshot_id).toBe(
+ readJson(join(generated, "manifest.json")).snapshot_id
+ )
+ })
+})
+
+describe("GET /api/tokens/{id}", () => {
+ it("returns every published token doc identical to its generated file", async () => {
+ for (const id of TOKEN_IDS) {
+ const res = handleGetToken(id)
+ expect(res.status, id).toBe(200)
+ const payload = await body(res)
+ expect(() => tokenDocSchema.parse(payload.data), id).not.toThrow()
+ expect(payload.data, id).toEqual(
+ readJson(join(generated, "tokens", `${id}.json`))
+ )
+ expect(() => provenanceSchema.parse(payload.provenance), id).not.toThrow()
+ }
+ })
+
+ it("normalizes id casing and whitespace", async () => {
+ const res = handleGetToken(" LDO ")
+ expect(res.status).toBe(200)
+ const payload = await body(res)
+ expect(payload.data.id).toBe("ldo")
+ })
+
+ it.each(["doge", "not-a-token"])(
+ "returns structured 404 for unknown id %s",
+ async (id) => {
+ const res = handleGetToken(id)
+ expect(res.status).toBe(404)
+ const payload = await body(res)
+ expect(() => apiErrorSchema.parse(payload)).not.toThrow()
+ expect(payload.error.code).toBe("TOKEN_NOT_FOUND")
+ }
+ )
+})
diff --git a/tests/freshness.test.ts b/tests/freshness.test.ts
index d3b3a8a..1598d93 100644
--- a/tests/freshness.test.ts
+++ b/tests/freshness.test.ts
@@ -40,4 +40,10 @@ describe("generated read models are fresh", () => {
composed.testimonials
)
})
+
+ it("manifest.json (snapshot identity)", () => {
+ expect(readJson(join(generated, "manifest.json"))).toEqual(
+ composed.manifest
+ )
+ })
})
From 040f992a155f454229923f898976ee98b9a7212d Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 13:03:29 +0200
Subject: [PATCH 05/38] chore: exclude composer-owned generated data from biome
formatting
---
biome.json | 3 ++-
src/data/generated/tokens/aave.json | 24 ++++++++++++++++++------
src/data/generated/tokens/aero.json | 20 +++++++++++++++-----
src/data/generated/tokens/crv.json | 20 +++++++++++++++-----
src/data/generated/tokens/ena.json | 20 +++++++++++++++-----
src/data/generated/tokens/ethfi.json | 24 ++++++++++++++++++------
src/data/generated/tokens/ldo.json | 20 +++++++++++++++-----
src/data/generated/tokens/lqty.json | 24 ++++++++++++++++++------
src/data/generated/tokens/ondo.json | 24 ++++++++++++++++++------
src/data/generated/tokens/sky.json | 24 ++++++++++++++++++------
src/data/generated/tokens/uni.json | 20 +++++++++++++++-----
src/data/generated/tokens/yb.json | 24 ++++++++++++++++++------
12 files changed, 185 insertions(+), 62 deletions(-)
diff --git a/biome.json b/biome.json
index 5923c75..f76376b 100644
--- a/biome.json
+++ b/biome.json
@@ -13,7 +13,8 @@
"**/index.html",
"**/vite.config.js",
"!**/src/routeTree.gen.ts",
- "!**/src/styles.css"
+ "!**/src/styles.css",
+ "!**/src/data/generated"
]
},
"formatter": {
diff --git a/src/data/generated/tokens/aave.json b/src/data/generated/tokens/aave.json
index 755dae2..cf01ffb 100644
--- a/src/data/generated/tokens/aave.json
+++ b/src/data/generated/tokens/aave.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -258,7 +260,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -360,7 +364,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": []
}
]
@@ -370,7 +376,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -420,7 +428,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -445,7 +455,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/aero.json b/src/data/generated/tokens/aero.json
index b87f946..b535d56 100644
--- a/src/data/generated/tokens/aero.json
+++ b/src/data/generated/tokens/aero.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -295,7 +297,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -443,7 +447,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -498,7 +504,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -523,7 +531,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/crv.json b/src/data/generated/tokens/crv.json
index a912564..1c6aecb 100644
--- a/src/data/generated/tokens/crv.json
+++ b/src/data/generated/tokens/crv.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -245,7 +247,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -364,7 +368,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -414,7 +420,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -449,7 +457,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/ena.json b/src/data/generated/tokens/ena.json
index c354999..5de4649 100644
--- a/src/data/generated/tokens/ena.json
+++ b/src/data/generated/tokens/ena.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -331,7 +333,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -525,7 +529,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -631,7 +637,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -690,7 +698,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/ethfi.json b/src/data/generated/tokens/ethfi.json
index 94b51bf..3bfd4d9 100644
--- a/src/data/generated/tokens/ethfi.json
+++ b/src/data/generated/tokens/ethfi.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -275,7 +277,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -363,7 +367,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": []
}
]
@@ -373,7 +379,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -426,7 +434,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -478,7 +488,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/ldo.json b/src/data/generated/tokens/ldo.json
index 44dc585..7502741 100644
--- a/src/data/generated/tokens/ldo.json
+++ b/src/data/generated/tokens/ldo.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -346,7 +348,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -461,7 +465,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -511,7 +517,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -536,7 +544,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/lqty.json b/src/data/generated/tokens/lqty.json
index d8f302c..1604ecc 100644
--- a/src/data/generated/tokens/lqty.json
+++ b/src/data/generated/tokens/lqty.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -168,7 +170,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -260,7 +264,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": []
}
]
@@ -270,7 +276,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -325,7 +333,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -365,7 +375,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/ondo.json b/src/data/generated/tokens/ondo.json
index a241ebc..500b04f 100644
--- a/src/data/generated/tokens/ondo.json
+++ b/src/data/generated/tokens/ondo.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -393,7 +395,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -507,7 +511,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "warning",
"notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": [
{
"name": "Ondo Product Economics",
@@ -560,7 +566,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -646,7 +654,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -705,7 +715,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/sky.json b/src/data/generated/tokens/sky.json
index c1a3c8e..881f27c 100644
--- a/src/data/generated/tokens/sky.json
+++ b/src/data/generated/tokens/sky.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -271,7 +273,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -391,7 +395,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": [
{
"name": "Foundation Independence",
@@ -413,7 +419,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -472,7 +480,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "Aragon has not been able to verify the concentration of holdings.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -509,7 +519,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/uni.json b/src/data/generated/tokens/uni.json
index dc27c22..56262ef 100644
--- a/src/data/generated/tokens/uni.json
+++ b/src/data/generated/tokens/uni.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -244,7 +246,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -409,7 +413,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -474,7 +480,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -531,7 +539,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
diff --git a/src/data/generated/tokens/yb.json b/src/data/generated/tokens/yb.json
index 530ab94..e3631e0 100644
--- a/src/data/generated/tokens/yb.json
+++ b/src/data/generated/tokens/yb.json
@@ -28,7 +28,9 @@
"name": "Onchain Control",
"about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
"summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
- "tags": ["Metric 1"],
+ "tags": [
+ "Metric 1"
+ ],
"criteria": [
{
"id": "onchain-ctrl__governance-workflow",
@@ -246,7 +248,9 @@
"name": "Value Accrual",
"about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
"summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
- "tags": ["Metric 2"],
+ "tags": [
+ "Metric 2"
+ ],
"criteria": [
{
"id": "val-accrual__active",
@@ -370,7 +374,9 @@
"about": "Are there additional offchain value accrual flows that benefit tokenholders?",
"status": "unevaluated",
"notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"evidence": []
}
]
@@ -380,7 +386,9 @@
"name": "Verifiability",
"about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
"summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
- "tags": ["Metric 3"],
+ "tags": [
+ "Metric 3"
+ ],
"criteria": [
{
"id": "verifiability__token-source",
@@ -437,7 +445,9 @@
"name": "Token Distribution",
"about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
"summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
- "tags": ["Metric 4"],
+ "tags": [
+ "Metric 4"
+ ],
"criteria": [
{
"id": "distribution__concentration",
@@ -491,7 +501,9 @@
"name": "Offchain Dependencies",
"about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
"summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
- "tags": ["Reference"],
+ "tags": [
+ "Reference"
+ ],
"criteria": [
{
"id": "offchain__trademark",
From 0aa34d24114051e13692300d909a16d9331b0c71 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 16:50:11 +0200
Subject: [PATCH 06/38] refactor: retire per-token deployment filtering
---
.../check-development-to-clients.yml | 26 ------------------
src/lib/token-data.ts | 27 +++----------------
vite.config.ts | 10 ++-----
3 files changed, 6 insertions(+), 57 deletions(-)
delete mode 100644 .github/workflows/check-development-to-clients.yml
diff --git a/.github/workflows/check-development-to-clients.yml b/.github/workflows/check-development-to-clients.yml
deleted file mode 100644
index b2a359b..0000000
--- a/.github/workflows/check-development-to-clients.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Enforce Merge Policy
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- check-source-branch:
- runs-on: ubuntu-latest
- steps:
- - name: Validate source branch
- run: |
- SOURCE_BRANCH="${{ github.head_ref }}"
- TARGET_BRANCH="${{ github.base_ref }}"
-
- PROTECTED_BRANCHES="ldo crv aero uni"
- ALLOWED_SOURCE="development"
-
- if echo "$PROTECTED_BRANCHES" | grep -qw "$TARGET_BRANCH"; then
- if [ "$SOURCE_BRANCH" != "$ALLOWED_SOURCE" ]; then
- echo "::error::Merge denied. Branch '$TARGET_BRANCH' only accepts merges from '$ALLOWED_SOURCE'."
- exit 1
- fi
- fi
-
- echo "✅ Check passed"
diff --git a/src/lib/token-data.ts b/src/lib/token-data.ts
index 005a9c6..0130266 100644
--- a/src/lib/token-data.ts
+++ b/src/lib/token-data.ts
@@ -3,34 +3,15 @@ import type { IndexRow } from "@/lib/schemas"
export type Token = IndexRow
-const rawTokens = indexData.tokens as Token[]
-
-function normalizeTokenSymbol(value: string): string {
- return value.trim().toUpperCase()
-}
-
-const envSymbolFilter = normalizeTokenSymbol(
- import.meta.env.VITE_TOKEN_SYMBOL ?? ""
-)
-
-const matchingTokens = envSymbolFilter
- ? rawTokens.filter(
- (token) => normalizeTokenSymbol(token.symbol) === envSymbolFilter
- )
- : []
-
-const filteredTokens = matchingTokens.length > 0 ? matchingTokens : rawTokens
+const tokens = indexData.tokens as Token[]
function getTokens(): Token[] {
- return filteredTokens
+ return tokens
}
function getTokenById(tokenId: string): Token | null {
const normalizedId = tokenId.trim().toLowerCase()
- return (
- filteredTokens.find((token) => token.id.toLowerCase() === normalizedId) ??
- null
- )
+ return tokens.find((token) => token.id.toLowerCase() === normalizedId) ?? null
}
-export { envSymbolFilter, getTokenById, getTokens }
+export { getTokenById, getTokens }
diff --git a/vite.config.ts b/vite.config.ts
index b966265..49991f6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,4 +1,4 @@
-import { defineConfig, loadEnv } from 'vite'
+import { defineConfig } from 'vite'
import { devtools } from '@tanstack/devtools-vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
@@ -6,14 +6,8 @@ import viteTsConfigPaths from 'vite-tsconfig-paths'
import tailwindcss from '@tailwindcss/vite'
import { nitro } from 'nitro/vite'
-const config = defineConfig(({ mode }) => {
- const env = loadEnv(mode, process.cwd(), '')
- const tokenSymbolEnv = env.VERCEL_GIT_COMMIT_REF ?? ''
-
+const config = defineConfig(() => {
return {
- define: {
- 'import.meta.env.VITE_TOKEN_SYMBOL': JSON.stringify(tokenSymbolEnv),
- },
plugins: [
devtools(),
nitro(),
From 072fc66f15cb248a8c877707d70f59f9743d6dc7 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 17:13:01 +0200
Subject: [PATCH 07/38] fix: enforce canonical evaluation status vocabulary
---
.../lqty/offchain/offchain__distribution.json | 2 +-
.../lqty/offchain/offchain__licensing.json | 2 +-
.../lqty/offchain/offchain__trademark.json | 2 +-
src/components/metric-card.tsx | 16 ++++++++-----
src/components/token-detail.tsx | 6 +----
src/data/generated/index.json | 4 ++--
src/data/generated/manifest.json | 2 +-
src/data/generated/tokens/lqty.json | 12 +++++-----
src/lib/metrics-data.ts | 17 +++-----------
src/lib/schemas/atoms.ts | 4 ++--
src/lib/schemas/common.ts | 23 ++++---------------
src/lib/schemas/read-models.ts | 6 ++---
12 files changed, 36 insertions(+), 60 deletions(-)
diff --git a/content/evaluations/lqty/offchain/offchain__distribution.json b/content/evaluations/lqty/offchain/offchain__distribution.json
index cad5d6b..e8a8be0 100644
--- a/content/evaluations/lqty/offchain/offchain__distribution.json
+++ b/content/evaluations/lqty/offchain/offchain__distribution.json
@@ -1,5 +1,5 @@
{
- "status": "partial",
+ "status": "warning",
"notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
"evidence": [
{
diff --git a/content/evaluations/lqty/offchain/offchain__licensing.json b/content/evaluations/lqty/offchain/offchain__licensing.json
index 782d787..be0df5c 100644
--- a/content/evaluations/lqty/offchain/offchain__licensing.json
+++ b/content/evaluations/lqty/offchain/offchain__licensing.json
@@ -1,5 +1,5 @@
{
- "status": "fail",
+ "status": "at_risk",
"notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
"evidence": [
{
diff --git a/content/evaluations/lqty/offchain/offchain__trademark.json b/content/evaluations/lqty/offchain/offchain__trademark.json
index c87d208..877957e 100644
--- a/content/evaluations/lqty/offchain/offchain__trademark.json
+++ b/content/evaluations/lqty/offchain/offchain__trademark.json
@@ -1,5 +1,5 @@
{
- "status": "fail",
+ "status": "at_risk",
"notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
"evidence": [
{
diff --git a/src/components/metric-card.tsx b/src/components/metric-card.tsx
index 85f0eb8..bdc08ca 100644
--- a/src/components/metric-card.tsx
+++ b/src/components/metric-card.tsx
@@ -18,7 +18,7 @@ import type { Evidence, Metric } from "@/lib/metrics-data"
import { getMetricScore, getScoreStatus } from "@/lib/scoring"
import { cn } from "../lib/utils.ts"
import { EvidenceCard, isFullEvidence } from "./evidence-card.tsx"
-import { type CriteriaStatus, mapStatus } from "./token-detail"
+import type { CriteriaStatus } from "./token-detail"
import { BadgeEvaluation } from "./ui/badge-evaluation.tsx"
import { TitlePopover } from "./ui/title-popover.tsx"
@@ -164,7 +164,10 @@ export default function MetricCard(props: MetricCardProps) {
colors.summaryColor
)}
>
-
+
{metric.summary}
@@ -195,9 +198,7 @@ export default function MetricCard(props: MetricCardProps) {
variant="h4"
/>
- {!score.reference && (
-
- )}
+ {!score.reference && }
@@ -210,7 +211,10 @@ export default function MetricCard(props: MetricCardProps) {
"prose pr-0 max-w-none md:pr-8"
)}
>
-
+
{notes}
diff --git a/src/components/token-detail.tsx b/src/components/token-detail.tsx
index 9fff248..1d2cc12 100644
--- a/src/components/token-detail.tsx
+++ b/src/components/token-detail.tsx
@@ -23,11 +23,7 @@ import { NewsletterSignup } from "./newsletter-signup.tsx"
import { OwnershipScoreCard } from "./ownership-score-card"
// Types
-export type {
- CriteriaStatusValue as CriteriaStatus,
-} from "@/lib/metrics-data"
-
-export { normalizeCriteriaStatus as mapStatus } from "@/lib/metrics-data"
+export type { CriteriaStatusValue as CriteriaStatus } from "@/lib/metrics-data"
export interface TokenInfo {
id: string
diff --git a/src/data/generated/index.json b/src/data/generated/index.json
index 801c790..e549c92 100644
--- a/src/data/generated/index.json
+++ b/src/data/generated/index.json
@@ -201,8 +201,8 @@
},
"infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters.",
"positive": 13,
- "neutral": 0,
- "atRisk": 0,
+ "neutral": 1,
+ "atRisk": 2,
"evidenceEntries": 16,
"score": {
"passing": 13,
diff --git a/src/data/generated/manifest.json b/src/data/generated/manifest.json
index 854d06e..c81aa57 100644
--- a/src/data/generated/manifest.json
+++ b/src/data/generated/manifest.json
@@ -1,5 +1,5 @@
{
- "snapshot_id": "1daba5411687dfd1",
+ "snapshot_id": "73799b5c622c6fe2",
"tokens": [
"aave",
"aero",
diff --git a/src/data/generated/tokens/lqty.json b/src/data/generated/tokens/lqty.json
index 1604ecc..8c83c09 100644
--- a/src/data/generated/tokens/lqty.json
+++ b/src/data/generated/tokens/lqty.json
@@ -19,8 +19,8 @@
},
"infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters.",
"positive": 13,
- "neutral": 0,
- "atRisk": 0,
+ "neutral": 1,
+ "atRisk": 2,
"evidenceEntries": 16,
"metrics": [
{
@@ -383,7 +383,7 @@
"id": "offchain__trademark",
"name": "Trademark",
"about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "fail",
+ "status": "at_risk",
"notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
"evidence": [
{
@@ -411,7 +411,7 @@
"id": "offchain__distribution",
"name": "Distribution",
"about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "partial",
+ "status": "warning",
"notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
"evidence": [
{
@@ -439,7 +439,7 @@
"id": "offchain__licensing",
"name": "Licensing",
"about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "fail",
+ "status": "at_risk",
"notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
"evidence": [
{
@@ -512,7 +512,7 @@
"metricId": "offchain",
"metricName": "Offchain Dependencies",
"passing": 0,
- "total": 0,
+ "total": 3,
"percentage": 0,
"evaluated": false,
"reference": true
diff --git a/src/lib/metrics-data.ts b/src/lib/metrics-data.ts
index 0fcec29..4e79adc 100644
--- a/src/lib/metrics-data.ts
+++ b/src/lib/metrics-data.ts
@@ -26,19 +26,6 @@ export function getTokenDoc(tokenId: string): TokenDoc | null {
return tokenDocs.get(tokenId.trim().toLowerCase()) ?? null
}
-export function normalizeCriteriaStatus(status?: string): CriteriaStatusValue {
- if (
- status === CRITERIA_STATUS.POSITIVE ||
- status === CRITERIA_STATUS.WARNING ||
- status === CRITERIA_STATUS.AT_RISK ||
- status === CRITERIA_STATUS.UNEVALUATED ||
- status === CRITERIA_STATUS.REFERENCE
- ) {
- return status
- }
- return CRITERIA_STATUS.REFERENCE
-}
-
export function getCriteriaStatus(
tokenId: string,
criteriaId: string
@@ -47,7 +34,9 @@ export function getCriteriaStatus(
if (!doc) return CRITERIA_STATUS.REFERENCE
for (const m of doc.metrics) {
for (const c of m.criteria) {
- if (c.id === criteriaId) return normalizeCriteriaStatus(c.status)
+ // Statuses are schema-validated canonical values (ADR 0002) —
+ // no runtime normalization layer exists by design.
+ if (c.id === criteriaId) return c.status
}
}
return CRITERIA_STATUS.REFERENCE
diff --git a/src/lib/schemas/atoms.ts b/src/lib/schemas/atoms.ts
index 3ff105b..c2d20ea 100644
--- a/src/lib/schemas/atoms.ts
+++ b/src/lib/schemas/atoms.ts
@@ -6,7 +6,7 @@
* absent and produced at composition time (scripts/compose-data.mjs).
*/
import { z } from "zod"
-import { evidenceSchema, rawCriteriaStatusSchema } from "./common"
+import { criteriaStatusSchema, evidenceSchema } from "./common"
/** content/tokens/.json — registry atom: identity, display, chain data. */
export const tokenAtomSchema = z.strictObject({
@@ -42,7 +42,7 @@ export const metricEditorialAtomSchema = z.strictObject({
export const criterionEvaluationAtomSchema = z.strictObject({
/** Display-name override; present only where it diverges from framework. */
name: z.string().optional(),
- status: rawCriteriaStatusSchema,
+ status: criteriaStatusSchema,
notes: z.string(),
tags: z.array(z.string()).optional(),
evidence: z.array(evidenceSchema).optional(),
diff --git a/src/lib/schemas/common.ts b/src/lib/schemas/common.ts
index beb00af..3415fda 100644
--- a/src/lib/schemas/common.ts
+++ b/src/lib/schemas/common.ts
@@ -1,6 +1,10 @@
import { z } from "zod"
-/** Canonical criteria workflow statuses. */
+/**
+ * Canonical criteria workflow statuses — the ONLY valid vocabulary.
+ * Non-canonical values are a validation failure by design (ADR 0002):
+ * there is no runtime mapping/normalization layer for dialect statuses.
+ */
export const CRITERIA_STATUS = {
POSITIVE: "positive",
WARNING: "warning",
@@ -20,23 +24,6 @@ export const criteriaStatusSchema = z.enum([
CRITERIA_STATUS.REFERENCE,
])
-/**
- * Statuses as they actually appear in the data, including legacy values
- * ("fail", "partial") that normalize to "reference" at read time and are
- * excluded from scoring. Preserved as passthrough pending editorial cleanup.
- */
-export const rawCriteriaStatusSchema = z.enum([
- CRITERIA_STATUS.POSITIVE,
- CRITERIA_STATUS.WARNING,
- CRITERIA_STATUS.AT_RISK,
- CRITERIA_STATUS.UNEVALUATED,
- CRITERIA_STATUS.REFERENCE,
- "fail",
- "partial",
-])
-
-export type RawCriteriaStatus = z.infer
-
export const evidenceUrlSchema = z.strictObject({
name: z.string(),
url: z.string(),
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
index d946f6c..c6ba255 100644
--- a/src/lib/schemas/read-models.ts
+++ b/src/lib/schemas/read-models.ts
@@ -7,14 +7,14 @@
*/
import { z } from "zod"
import { tokenAtomSchema } from "./atoms"
-import { evidenceSchema, rawCriteriaStatusSchema } from "./common"
+import { criteriaStatusSchema, evidenceSchema } from "./common"
-/** A criterion as rendered: framework `about` merged, raw status preserved. */
+/** A criterion as rendered: framework `about` merged, canonical status. */
export const composedCriterionSchema = z.strictObject({
id: z.string(),
name: z.string(),
about: z.string(),
- status: rawCriteriaStatusSchema,
+ status: criteriaStatusSchema,
notes: z.string(),
tags: z.array(z.string()).optional(),
evidence: z.array(evidenceSchema).optional(),
From 30174a5a08dba25af0093911dfa6582e5965b43e Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 17:47:24 +0200
Subject: [PATCH 08/38] chore: apply formatter to remaining unformatted
components
---
src/components/evidence-card.tsx | 5 ++++-
src/components/token-ownership-analytics.tsx | 10 +++++-----
src/components/ui/title-popover.tsx | 4 +---
src/components/user-faq.tsx | 7 +++++--
src/hooks/use-market-data.ts | 2 +-
src/routes/api.market-data.ts | 2 +-
6 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/src/components/evidence-card.tsx b/src/components/evidence-card.tsx
index b3fcdfc..ce010f5 100644
--- a/src/components/evidence-card.tsx
+++ b/src/components/evidence-card.tsx
@@ -43,7 +43,10 @@ export const EvidenceCard: React.FC = (props) => {
)}
{evidence.summary && (
-
+
{evidence.summary}
diff --git a/src/components/token-ownership-analytics.tsx b/src/components/token-ownership-analytics.tsx
index 2ddf207..c3b2e00 100644
--- a/src/components/token-ownership-analytics.tsx
+++ b/src/components/token-ownership-analytics.tsx
@@ -1,5 +1,10 @@
"use client"
+import {
+ IconCircleCheckFilled,
+ IconCircleX,
+ // @ts-expect-error by default it imports from cjs build and triggers server-side error
+} from "@tabler/icons-react/dist/esm/tabler-icons-react.mjs"
import { Link, useNavigate } from "@tanstack/react-router"
import {
type ColumnDef,
@@ -11,11 +16,6 @@ import {
type SortingState,
useReactTable,
} from "@tanstack/react-table"
-import {
- IconCircleCheckFilled,
- IconCircleX,
- // @ts-expect-error by default it imports from cjs build and triggers server-side error
-} from "@tabler/icons-react/dist/esm/tabler-icons-react.mjs"
import {
ArrowRightIcon,
ChevronLeftIcon,
diff --git a/src/components/ui/title-popover.tsx b/src/components/ui/title-popover.tsx
index 45a7810..c114e96 100644
--- a/src/components/ui/title-popover.tsx
+++ b/src/components/ui/title-popover.tsx
@@ -41,9 +41,7 @@ const TitlePopover: React.FC = (props) => {
)}
{...otherProps}
>
-
+
-
+
{item.answer}
diff --git a/src/hooks/use-market-data.ts b/src/hooks/use-market-data.ts
index 7f46bcd..38b1efe 100644
--- a/src/hooks/use-market-data.ts
+++ b/src/hooks/use-market-data.ts
@@ -1,6 +1,6 @@
import { useQuery } from "@tanstack/react-query"
-import { fetchMarketDataFn } from "@/routes/api.market-data"
import type { Token } from "@/lib/token-data"
+import { fetchMarketDataFn } from "@/routes/api.market-data"
export interface EnrichedToken extends Token {
marketCap?: number
diff --git a/src/routes/api.market-data.ts b/src/routes/api.market-data.ts
index 2e4b662..1d949d6 100644
--- a/src/routes/api.market-data.ts
+++ b/src/routes/api.market-data.ts
@@ -1,5 +1,5 @@
import { createServerFn } from "@tanstack/react-start"
-import { type MarketData, fetchMarketData } from "@/lib/coingecko"
+import { fetchMarketData, type MarketData } from "@/lib/coingecko"
type MarketDataInput = {
coingeckoIds: string[]
From d4a0b2ca6b01212a5fb7391e2dd8f2a55df4d4e9 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 17:47:24 +0200
Subject: [PATCH 09/38] fix: prevent nested paragraph hydration mismatch in
metric summaries
---
src/components/metric-card.tsx | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/components/metric-card.tsx b/src/components/metric-card.tsx
index bdc08ca..60ecc24 100644
--- a/src/components/metric-card.tsx
+++ b/src/components/metric-card.tsx
@@ -158,7 +158,9 @@ export default function MetricCard(props: MetricCardProps) {
/>
{metric.summary && (
- and nested
+ // paragraphs are invalid HTML (causes hydration mismatches)
+
{metric.summary}
-
+
)}
From e8974817f49123fbf1ba7081a7d3bd973f398cb8 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 5 Jun 2026 17:47:25 +0200
Subject: [PATCH 10/38] feat: serve app data from published API with SSR query
hydration
---
scripts/compose-data.mjs | 18 +-
src/components/site-header.tsx | 6 +-
src/data/generated/index.json | 770 ++++++++++++++++++++++++++-
src/data/generated/manifest.json | 2 +-
src/data/generated/tokens/aave.json | 128 +++--
src/data/generated/tokens/aero.json | 128 +++--
src/data/generated/tokens/crv.json | 128 +++--
src/data/generated/tokens/ena.json | 128 +++--
src/data/generated/tokens/ethfi.json | 128 +++--
src/data/generated/tokens/ldo.json | 128 +++--
src/data/generated/tokens/lqty.json | 128 +++--
src/data/generated/tokens/ondo.json | 128 +++--
src/data/generated/tokens/sky.json | 128 +++--
src/data/generated/tokens/uni.json | 128 +++--
src/data/generated/tokens/yb.json | 128 +++--
src/lib/framework.ts | 36 +-
src/lib/metrics-data.ts | 44 +-
src/lib/published-queries.ts | 78 +++
src/lib/query-client.ts | 15 +
src/lib/schemas/read-models.ts | 17 +-
src/lib/scoring.ts | 13 +-
src/lib/server/published-data.ts | 13 +-
src/lib/server/token-api.ts | 9 +
src/lib/token-data.ts | 25 +-
src/routeTree.gen.ts | 28 +-
src/router.tsx | 38 +-
src/routes/__root.tsx | 33 +-
src/routes/api.framework.ts | 10 +
src/routes/tokens/$tokenId.tsx | 7 +
tests/api-endpoints.test.ts | 18 +-
tests/round-trip.test.ts | 9 +-
31 files changed, 1905 insertions(+), 692 deletions(-)
create mode 100644 src/lib/published-queries.ts
create mode 100644 src/lib/query-client.ts
create mode 100644 src/routes/api.framework.ts
diff --git a/scripts/compose-data.mjs b/scripts/compose-data.mjs
index 74c6fb6..f9eb240 100644
--- a/scripts/compose-data.mjs
+++ b/scripts/compose-data.mjs
@@ -124,20 +124,20 @@ export function composeAll(dir = contentDir) {
neutral: countBy("warning"),
atRisk: countBy("at_risk"),
evidenceEntries: allCriteria.flatMap((c) => c.evidence ?? []).length,
- metrics,
score,
+ criteriaStatuses: Object.fromEntries(
+ allCriteria.map((c) => [c.id, c.status])
+ ),
+ metrics,
})
}
+ // Index rows are the dashboard read model: full score (the score hover
+ // shows the per-metric breakdown) and a flat criterion-status map (the
+ // table renders single-criterion columns across all tokens) — so the
+ // dashboard needs exactly one fetch and never loads per-token docs.
const index = {
- tokens: tokenDocs.map(({ metrics: _m, score, ...row }) => ({
- ...row,
- score: {
- passing: score.passing,
- total: score.total,
- percentage: score.percentage,
- },
- })),
+ tokens: tokenDocs.map(({ metrics: _metrics, ...row }) => row),
}
const frameworkDoc = { baseUrl: meta.baseUrl, metrics: framework }
diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx
index 8a8eade..a14b205 100644
--- a/src/components/site-header.tsx
+++ b/src/components/site-header.tsx
@@ -23,7 +23,7 @@ import {
NavigationMenuList,
} from "@/components/ui/navigation-menu"
import { useTokenSearch } from "@/hooks/use-token-search"
-import { FRAMEWORK_BASE_URL } from "@/lib/framework"
+import { getFrameworkBaseUrl } from "@/lib/framework"
import { cn } from "@/lib/utils"
export function SiteHeader() {
@@ -115,7 +115,7 @@ export function SiteHeader() {
}
+ render={ }
>
Framework
@@ -216,7 +216,7 @@ export function SiteHeader() {
Framework
diff --git a/src/data/generated/index.json b/src/data/generated/index.json
index e549c92..d4b359e 100644
--- a/src/data/generated/index.json
+++ b/src/data/generated/index.json
@@ -25,9 +25,77 @@
"atRisk": 0,
"evidenceEntries": 18,
"score": {
+ "tokenId": "aave",
"passing": 12,
"total": 12,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
}
},
{
@@ -55,9 +123,77 @@
"atRisk": 0,
"evidenceEntries": 23,
"score": {
+ "tokenId": "aero",
"passing": 12,
"total": 13,
- "percentage": 92.3076923076923
+ "percentage": 92.3076923076923,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 6,
+ "total": 7,
+ "percentage": 85.71428571428571,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
}
},
{
@@ -85,9 +221,77 @@
"atRisk": 0,
"evidenceEntries": 23,
"score": {
+ "tokenId": "crv",
"passing": 13,
"total": 13,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
}
},
{
@@ -115,9 +319,77 @@
"atRisk": 0,
"evidenceEntries": 29,
"score": {
+ "tokenId": "ena",
"passing": 2,
"total": 15,
- "percentage": 13.333333333333334
+ "percentage": 13.333333333333334,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 0,
+ "total": 7,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "warning",
+ "onchain-ctrl__role-accountability": "warning",
+ "onchain-ctrl__protocol-upgrade": "warning",
+ "onchain-ctrl__token-upgrade": "warning",
+ "onchain-ctrl__supply": "warning",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "warning",
+ "val-accrual__active": "warning",
+ "val-accrual__treasury": "warning",
+ "val-accrual__mechanism": "warning",
+ "val-accrual__offchain": "warning",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
}
},
{
@@ -145,9 +417,77 @@
"atRisk": 1,
"evidenceEntries": 20,
"score": {
+ "tokenId": "ethfi",
"passing": 3,
"total": 14,
- "percentage": 21.428571428571427
+ "percentage": 21.428571428571427,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 1,
+ "total": 7,
+ "percentage": 14.285714285714285,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 1,
+ "total": 3,
+ "percentage": 33.33333333333333,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "at_risk",
+ "onchain-ctrl__role-accountability": "warning",
+ "onchain-ctrl__protocol-upgrade": "warning",
+ "onchain-ctrl__token-upgrade": "warning",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "warning",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "warning",
+ "val-accrual__mechanism": "warning",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "warning",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
}
},
{
@@ -175,9 +515,77 @@
"atRisk": 0,
"evidenceEntries": 26,
"score": {
+ "tokenId": "ldo",
"passing": 12,
"total": 12,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "positive",
+ "offchain__distribution": "positive",
+ "offchain__licensing": "positive"
}
},
{
@@ -205,9 +613,77 @@
"atRisk": 2,
"evidenceEntries": 16,
"score": {
+ "tokenId": "lqty",
"passing": 13,
"total": 13,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "at_risk",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "at_risk"
}
},
{
@@ -235,9 +711,77 @@
"atRisk": 9,
"evidenceEntries": 27,
"score": {
+ "tokenId": "ondo",
"passing": 4,
"total": 15,
- "percentage": 26.666666666666668
+ "percentage": 26.666666666666668,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 2,
+ "total": 7,
+ "percentage": 28.57142857142857,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "at_risk",
+ "onchain-ctrl__role-accountability": "at_risk",
+ "onchain-ctrl__protocol-upgrade": "at_risk",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "at_risk",
+ "onchain-ctrl__access-gating": "at_risk",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "at_risk",
+ "val-accrual__treasury": "at_risk",
+ "val-accrual__mechanism": "at_risk",
+ "val-accrual__offchain": "warning",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "at_risk",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
}
},
{
@@ -265,9 +809,77 @@
"atRisk": 0,
"evidenceEntries": 25,
"score": {
+ "tokenId": "sky",
"passing": 12,
"total": 12,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "unevaluated",
+ "offchain__licensing": "positive"
}
},
{
@@ -295,9 +907,77 @@
"atRisk": 0,
"evidenceEntries": 25,
"score": {
+ "tokenId": "uni",
"passing": 13,
"total": 13,
- "percentage": 100
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
}
},
{
@@ -325,9 +1005,77 @@
"atRisk": 1,
"evidenceEntries": 18,
"score": {
+ "tokenId": "yb",
"passing": 11,
"total": 14,
- "percentage": 78.57142857142857
+ "percentage": 78.57142857142857,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 2,
+ "total": 3,
+ "percentage": 66.66666666666666,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "at_risk",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "unevaluated",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
}
}
]
diff --git a/src/data/generated/manifest.json b/src/data/generated/manifest.json
index c81aa57..5f2706b 100644
--- a/src/data/generated/manifest.json
+++ b/src/data/generated/manifest.json
@@ -1,5 +1,5 @@
{
- "snapshot_id": "73799b5c622c6fe2",
+ "snapshot_id": "364589340247aa7f",
"tokens": [
"aave",
"aero",
diff --git a/src/data/generated/tokens/aave.json b/src/data/generated/tokens/aave.json
index cf01ffb..67deb76 100644
--- a/src/data/generated/tokens/aave.json
+++ b/src/data/generated/tokens/aave.json
@@ -22,6 +22,79 @@
"neutral": 2,
"atRisk": 0,
"evidenceEntries": 18,
+ "score": {
+ "tokenId": "aave",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -505,58 +578,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "aave",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/aero.json b/src/data/generated/tokens/aero.json
index b535d56..640852d 100644
--- a/src/data/generated/tokens/aero.json
+++ b/src/data/generated/tokens/aero.json
@@ -22,6 +22,79 @@
"neutral": 3,
"atRisk": 0,
"evidenceEntries": 23,
+ "score": {
+ "tokenId": "aero",
+ "passing": 12,
+ "total": 13,
+ "percentage": 92.3076923076923,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 6,
+ "total": 7,
+ "percentage": 85.71428571428571,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -581,58 +654,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "aero",
- "passing": 12,
- "total": 13,
- "percentage": 92.3076923076923,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 6,
- "total": 7,
- "percentage": 85.71428571428571,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/crv.json b/src/data/generated/tokens/crv.json
index 1c6aecb..af77c8f 100644
--- a/src/data/generated/tokens/crv.json
+++ b/src/data/generated/tokens/crv.json
@@ -22,6 +22,79 @@
"neutral": 2,
"atRisk": 0,
"evidenceEntries": 23,
+ "score": {
+ "tokenId": "crv",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -507,58 +580,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "crv",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/ena.json b/src/data/generated/tokens/ena.json
index 5de4649..1b44d42 100644
--- a/src/data/generated/tokens/ena.json
+++ b/src/data/generated/tokens/ena.json
@@ -22,6 +22,79 @@
"neutral": 16,
"atRisk": 0,
"evidenceEntries": 29,
+ "score": {
+ "tokenId": "ena",
+ "passing": 2,
+ "total": 15,
+ "percentage": 13.333333333333334,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 0,
+ "total": 7,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "warning",
+ "onchain-ctrl__role-accountability": "warning",
+ "onchain-ctrl__protocol-upgrade": "warning",
+ "onchain-ctrl__token-upgrade": "warning",
+ "onchain-ctrl__supply": "warning",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "warning",
+ "val-accrual__active": "warning",
+ "val-accrual__treasury": "warning",
+ "val-accrual__mechanism": "warning",
+ "val-accrual__offchain": "warning",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -763,58 +836,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "ena",
- "passing": 2,
- "total": 15,
- "percentage": 13.333333333333334,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 0,
- "total": 7,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 0,
- "total": 4,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/ethfi.json b/src/data/generated/tokens/ethfi.json
index 3bfd4d9..35971fb 100644
--- a/src/data/generated/tokens/ethfi.json
+++ b/src/data/generated/tokens/ethfi.json
@@ -22,6 +22,79 @@
"neutral": 13,
"atRisk": 1,
"evidenceEntries": 20,
+ "score": {
+ "tokenId": "ethfi",
+ "passing": 3,
+ "total": 14,
+ "percentage": 21.428571428571427,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 1,
+ "total": 7,
+ "percentage": 14.285714285714285,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 1,
+ "total": 3,
+ "percentage": 33.33333333333333,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "at_risk",
+ "onchain-ctrl__role-accountability": "warning",
+ "onchain-ctrl__protocol-upgrade": "warning",
+ "onchain-ctrl__token-upgrade": "warning",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "warning",
+ "onchain-ctrl__censorship": "warning",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "warning",
+ "val-accrual__mechanism": "warning",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "warning",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -556,58 +629,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "ethfi",
- "passing": 3,
- "total": 14,
- "percentage": 21.428571428571427,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 1,
- "total": 7,
- "percentage": 14.285714285714285,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 1,
- "total": 3,
- "percentage": 33.33333333333333,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 1,
- "total": 2,
- "percentage": 50,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/ldo.json b/src/data/generated/tokens/ldo.json
index 7502741..8f4e73f 100644
--- a/src/data/generated/tokens/ldo.json
+++ b/src/data/generated/tokens/ldo.json
@@ -22,6 +22,79 @@
"neutral": 0,
"atRisk": 0,
"evidenceEntries": 26,
+ "score": {
+ "tokenId": "ldo",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "positive",
+ "offchain__distribution": "positive",
+ "offchain__licensing": "positive"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -629,58 +702,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "ldo",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/lqty.json b/src/data/generated/tokens/lqty.json
index 8c83c09..8ee0b6a 100644
--- a/src/data/generated/tokens/lqty.json
+++ b/src/data/generated/tokens/lqty.json
@@ -22,6 +22,79 @@
"neutral": 1,
"atRisk": 2,
"evidenceEntries": 16,
+ "score": {
+ "tokenId": "lqty",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "at_risk",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "at_risk"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -465,58 +538,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "lqty",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/ondo.json b/src/data/generated/tokens/ondo.json
index 500b04f..5c29366 100644
--- a/src/data/generated/tokens/ondo.json
+++ b/src/data/generated/tokens/ondo.json
@@ -22,6 +22,79 @@
"neutral": 4,
"atRisk": 9,
"evidenceEntries": 27,
+ "score": {
+ "tokenId": "ondo",
+ "passing": 4,
+ "total": 15,
+ "percentage": 26.666666666666668,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 2,
+ "total": 7,
+ "percentage": 28.57142857142857,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 0,
+ "total": 4,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "at_risk",
+ "onchain-ctrl__role-accountability": "at_risk",
+ "onchain-ctrl__protocol-upgrade": "at_risk",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "at_risk",
+ "onchain-ctrl__access-gating": "at_risk",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "at_risk",
+ "val-accrual__treasury": "at_risk",
+ "val-accrual__mechanism": "at_risk",
+ "val-accrual__offchain": "warning",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "at_risk",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "unevaluated"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -791,58 +864,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "ondo",
- "passing": 4,
- "total": 15,
- "percentage": 26.666666666666668,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 2,
- "total": 7,
- "percentage": 28.57142857142857,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 0,
- "total": 4,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/sky.json b/src/data/generated/tokens/sky.json
index 881f27c..2177339 100644
--- a/src/data/generated/tokens/sky.json
+++ b/src/data/generated/tokens/sky.json
@@ -22,6 +22,79 @@
"neutral": 1,
"atRisk": 0,
"evidenceEntries": 25,
+ "score": {
+ "tokenId": "sky",
+ "passing": 12,
+ "total": 12,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 0,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 1,
+ "total": 2,
+ "percentage": 50,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "unevaluated",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "unevaluated",
+ "offchain__licensing": "positive"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -596,58 +669,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "sky",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 1,
- "total": 2,
- "percentage": 50,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/uni.json b/src/data/generated/tokens/uni.json
index 56262ef..c940a76 100644
--- a/src/data/generated/tokens/uni.json
+++ b/src/data/generated/tokens/uni.json
@@ -22,6 +22,79 @@
"neutral": 3,
"atRisk": 0,
"evidenceEntries": 25,
+ "score": {
+ "tokenId": "uni",
+ "passing": 13,
+ "total": 13,
+ "percentage": 100,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 3,
+ "total": 3,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 1,
+ "total": 1,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 3,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "positive",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "unevaluated",
+ "distribution__supply-schedule": "positive",
+ "offchain__trademark": "warning",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -589,58 +662,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "uni",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/data/generated/tokens/yb.json b/src/data/generated/tokens/yb.json
index e3631e0..9ae11be 100644
--- a/src/data/generated/tokens/yb.json
+++ b/src/data/generated/tokens/yb.json
@@ -22,6 +22,79 @@
"neutral": 4,
"atRisk": 1,
"evidenceEntries": 18,
+ "score": {
+ "tokenId": "yb",
+ "passing": 11,
+ "total": 14,
+ "percentage": 78.57142857142857,
+ "metrics": [
+ {
+ "metricId": "onchain-ctrl",
+ "metricName": "Onchain Control",
+ "passing": 7,
+ "total": 7,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "val-accrual",
+ "metricName": "Value Accrual",
+ "passing": 2,
+ "total": 3,
+ "percentage": 66.66666666666666,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "verifiability",
+ "metricName": "Verifiability",
+ "passing": 2,
+ "total": 2,
+ "percentage": 100,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "distribution",
+ "metricName": "Token Distribution",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": true,
+ "reference": false
+ },
+ {
+ "metricId": "offchain",
+ "metricName": "Offchain Dependencies",
+ "passing": 0,
+ "total": 2,
+ "percentage": 0,
+ "evaluated": false,
+ "reference": true
+ }
+ ]
+ },
+ "criteriaStatuses": {
+ "onchain-ctrl__governance-workflow": "positive",
+ "onchain-ctrl__role-accountability": "positive",
+ "onchain-ctrl__protocol-upgrade": "positive",
+ "onchain-ctrl__token-upgrade": "positive",
+ "onchain-ctrl__supply": "positive",
+ "onchain-ctrl__access-gating": "positive",
+ "onchain-ctrl__censorship": "positive",
+ "val-accrual__active": "positive",
+ "val-accrual__treasury": "at_risk",
+ "val-accrual__mechanism": "positive",
+ "val-accrual__offchain": "unevaluated",
+ "verifiability__token-source": "positive",
+ "verifiability__protocol-source": "positive",
+ "distribution__concentration": "warning",
+ "distribution__supply-schedule": "warning",
+ "offchain__trademark": "unevaluated",
+ "offchain__distribution": "warning",
+ "offchain__licensing": "warning"
+ },
"metrics": [
{
"id": "onchain-ctrl",
@@ -558,58 +631,5 @@
}
]
}
- ],
- "score": {
- "tokenId": "yb",
- "passing": 11,
- "total": 14,
- "percentage": 78.57142857142857,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 2,
- "total": 3,
- "percentage": 66.66666666666666,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
+ ]
}
diff --git a/src/lib/framework.ts b/src/lib/framework.ts
index 0d9e38a..4ba011d 100644
--- a/src/lib/framework.ts
+++ b/src/lib/framework.ts
@@ -1,18 +1,37 @@
-import frameworkData from "@/data/generated/framework.json"
+import { publishedFrameworkQuery } from "@/lib/published-queries"
+import { queryClient } from "@/lib/query-client"
import type { FrameworkDoc } from "@/lib/schemas"
-const framework = frameworkData as FrameworkDoc
-
export type FrameworkMetric = FrameworkDoc["metrics"][number]
export type FrameworkCriteria = FrameworkMetric["criteria"][number]
-export const FRAMEWORK_BASE_URL = framework.baseUrl
+/**
+ * Synchronous read over the hydrated query cache; the root route loader
+ * ensures the framework doc on every page. Fails loudly on a cache miss.
+ */
+function readFramework(): FrameworkDoc {
+ const data = queryClient.getQueryData(publishedFrameworkQuery.queryKey)
+ if (!data) {
+ throw new Error(
+ "Published framework doc is not in the query cache — a route loader must ensure publishedFrameworkQuery before render"
+ )
+ }
+ return data
+}
+
+/**
+ * Base URL of the framework README. Data-owned (content/framework/_meta.json),
+ * so it is a render-time read, not a module constant.
+ */
+export function getFrameworkBaseUrl(): string {
+ return readFramework().baseUrl
+}
/**
* Get framework metric definition by ID
*/
export function getFrameworkMetric(metricId: string): FrameworkMetric | null {
- const metric = framework.metrics.find((m) => m.id === metricId)
+ const metric = readFramework().metrics.find((m) => m.id === metricId)
return metric || null
}
@@ -22,7 +41,7 @@ export function getFrameworkMetric(metricId: string): FrameworkMetric | null {
export function getFrameworkCriteria(
criteriaId: string
): FrameworkCriteria | null {
- for (const metric of framework.metrics) {
+ for (const metric of readFramework().metrics) {
const criteria = metric.criteria.find((c) => c.id === criteriaId)
if (criteria) return criteria
}
@@ -33,7 +52,7 @@ export function getFrameworkCriteria(
* Get all framework metrics
*/
export function getAllFrameworkMetrics(): FrameworkMetric[] {
- return framework.metrics
+ return readFramework().metrics
}
/**
@@ -41,5 +60,6 @@ export function getAllFrameworkMetrics(): FrameworkMetric[] {
*/
export function getFrameworkUrl(metricId: string): string {
const anchor = getFrameworkMetric(metricId)?.anchor
- return anchor ? `${FRAMEWORK_BASE_URL}${anchor}` : FRAMEWORK_BASE_URL
+ const baseUrl = getFrameworkBaseUrl()
+ return anchor ? `${baseUrl}${anchor}` : baseUrl
}
diff --git a/src/lib/metrics-data.ts b/src/lib/metrics-data.ts
index 4e79adc..45b2579 100644
--- a/src/lib/metrics-data.ts
+++ b/src/lib/metrics-data.ts
@@ -1,3 +1,5 @@
+import { publishedTokenDocQuery } from "@/lib/published-queries"
+import { queryClient } from "@/lib/query-client"
import {
type ComposedCriterion,
type ComposedMetric,
@@ -7,39 +9,41 @@ import {
type EvidenceUrl,
type TokenDoc,
} from "@/lib/schemas"
+import { getTokenById } from "@/lib/token-data"
export { CRITERIA_STATUS }
export type { CriteriaStatusValue, Evidence, EvidenceUrl }
export type Criteria = ComposedCriterion
export type Metric = ComposedMetric
-const tokenDocModules = import.meta.glob<{ default: TokenDoc }>(
- "../data/generated/tokens/*.json",
- { eager: true }
-)
-
-const tokenDocs = new Map(
- Object.values(tokenDocModules).map((mod) => [mod.default.id, mod.default])
-)
-
+/**
+ * Synchronous read over the hydrated query cache. The token detail route
+ * loader ensures the doc; an unensured read fails loudly by design.
+ * A cached `null` means the token does not exist (valid, returns null).
+ */
export function getTokenDoc(tokenId: string): TokenDoc | null {
- return tokenDocs.get(tokenId.trim().toLowerCase()) ?? null
+ const { queryKey } = publishedTokenDocQuery(tokenId)
+ const doc = queryClient.getQueryData(queryKey)
+ if (doc === undefined) {
+ throw new Error(
+ `Token doc "${tokenId}" is not in the query cache — the route loader must ensure publishedTokenDocQuery`
+ )
+ }
+ return doc
}
+/**
+ * Cross-token criterion status, served from the index read model (the
+ * dashboard renders single-criterion columns across all tokens without
+ * loading per-token docs). Statuses are schema-validated canonical values
+ * (ADR 0002) — no runtime normalization layer exists by design.
+ */
export function getCriteriaStatus(
tokenId: string,
criteriaId: string
): CriteriaStatusValue {
- const doc = getTokenDoc(tokenId)
- if (!doc) return CRITERIA_STATUS.REFERENCE
- for (const m of doc.metrics) {
- for (const c of m.criteria) {
- // Statuses are schema-validated canonical values (ADR 0002) —
- // no runtime normalization layer exists by design.
- if (c.id === criteriaId) return c.status
- }
- }
- return CRITERIA_STATUS.REFERENCE
+ const row = getTokenById(tokenId)
+ return row?.criteriaStatuses[criteriaId] ?? CRITERIA_STATUS.REFERENCE
}
export function getMetricsByTokenId(tokenId: string): Metric[] {
diff --git a/src/lib/published-queries.ts b/src/lib/published-queries.ts
new file mode 100644
index 0000000..62e60f5
--- /dev/null
+++ b/src/lib/published-queries.ts
@@ -0,0 +1,78 @@
+/**
+ * Query definitions for the published read models.
+ *
+ * Server side (`import.meta.env.SSR` is statically true), queryFns read the
+ * published data source directly — no self-HTTP, and Vite's static
+ * replacement guarantees the dynamic import (and the data behind it) is
+ * dropped from the client build entirely.
+ *
+ * Client side, queryFns fetch the canonical JSON endpoints — the app is the
+ * first consumer of its own published API (/api/tokens*).
+ *
+ * Published data is immutable per snapshot (~90-day editorial cadence), so
+ * staleTime/gcTime are Infinity: a new snapshot arrives as a new deployment
+ * (later: a new Edge Config pointer), never as a background refetch.
+ */
+import { queryOptions } from "@tanstack/react-query"
+import type { FrameworkDoc, IndexRow, TokenDoc } from "@/lib/schemas"
+
+async function fetchEnvelopeData(url: string): Promise {
+ const res = await fetch(url)
+ if (!res.ok) {
+ throw new Error(`Published data fetch failed: ${res.status} ${url}`)
+ }
+ const payload = (await res.json()) as { data: T }
+ return payload.data
+}
+
+export const publishedIndexQuery = queryOptions({
+ queryKey: ["published", "index"],
+ queryFn: async (): Promise<{ tokens: IndexRow[] }> => {
+ if (import.meta.env.SSR) {
+ const { getPublishedIndex } = await import("@/lib/server/published-data")
+ return getPublishedIndex()
+ }
+ return fetchEnvelopeData("/api/tokens")
+ },
+ staleTime: Number.POSITIVE_INFINITY,
+ gcTime: Number.POSITIVE_INFINITY,
+})
+
+export const publishedFrameworkQuery = queryOptions({
+ queryKey: ["published", "framework"],
+ queryFn: async (): Promise => {
+ if (import.meta.env.SSR) {
+ const { getPublishedFramework } = await import(
+ "@/lib/server/published-data"
+ )
+ return getPublishedFramework()
+ }
+ return fetchEnvelopeData("/api/framework")
+ },
+ staleTime: Number.POSITIVE_INFINITY,
+ gcTime: Number.POSITIVE_INFINITY,
+})
+
+export const publishedTokenDocQuery = (tokenId: string) => {
+ const normalizedId = tokenId.trim().toLowerCase()
+ return queryOptions({
+ queryKey: ["published", "token-doc", normalizedId],
+ queryFn: async (): Promise => {
+ if (import.meta.env.SSR) {
+ const { getPublishedTokenDoc } = await import(
+ "@/lib/server/published-data"
+ )
+ return getPublishedTokenDoc(normalizedId)
+ }
+ const res = await fetch(`/api/tokens/${normalizedId}`)
+ if (res.status === 404) return null
+ if (!res.ok) {
+ throw new Error(`Published data fetch failed: ${res.status}`)
+ }
+ const payload = (await res.json()) as { data: TokenDoc }
+ return payload.data
+ },
+ staleTime: Number.POSITIVE_INFINITY,
+ gcTime: Number.POSITIVE_INFINITY,
+ })
+}
diff --git a/src/lib/query-client.ts b/src/lib/query-client.ts
new file mode 100644
index 0000000..73eb738
--- /dev/null
+++ b/src/lib/query-client.ts
@@ -0,0 +1,15 @@
+import { QueryClient } from "@tanstack/react-query"
+
+/**
+ * Shared QueryClient singleton.
+ *
+ * Client: the app-wide cache, hydrated from SSR via the router ssr-query
+ * integration (src/router.tsx).
+ * Server: shared across requests by design — the published data it caches is
+ * immutable per deployment snapshot (~90-day update cadence), so cross-request
+ * sharing is correct and saves rereads.
+ *
+ * Lives in its own module (not router.tsx) so data libs can import it without
+ * creating an import cycle through the route tree.
+ */
+export const queryClient = new QueryClient()
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
index c6ba255..ecbfda1 100644
--- a/src/lib/schemas/read-models.ts
+++ b/src/lib/schemas/read-models.ts
@@ -60,29 +60,30 @@ export const tokenCountsSchema = z.strictObject({
evidenceEntries: z.number(),
})
-/** generated/index.json row — the dashboard-table read model (legacy Token shape). */
+/**
+ * generated/index.json row — the dashboard-table read model (legacy Token
+ * shape). Carries the FULL token score (per-metric breakdown feeds the score
+ * hover) and a flat criterion-status map (single-criterion columns across all
+ * tokens) so the dashboard needs only this one read model.
+ */
export const indexRowSchema = z.strictObject({
...tokenAtomSchema.shape,
positive: z.number(),
neutral: z.number(),
atRisk: z.number(),
evidenceEntries: z.number(),
- score: z.strictObject({
- passing: z.number(),
- total: z.number(),
- percentage: z.number(),
- }),
+ score: tokenScoreSchema,
+ criteriaStatuses: z.record(z.string(), criteriaStatusSchema),
})
export const indexSchema = z.strictObject({
tokens: z.array(indexRowSchema),
})
-/** generated/tokens/.json — the per-token reusable unit. */
+/** generated/tokens/.json — the per-token reusable unit (index row + full metrics). */
export const tokenDocSchema = z.strictObject({
...indexRowSchema.shape,
metrics: z.array(composedMetricSchema),
- score: tokenScoreSchema,
})
/** generated/framework.json — definitions + anchors + base URL. */
diff --git a/src/lib/scoring.ts b/src/lib/scoring.ts
index 09aae64..71f4412 100644
--- a/src/lib/scoring.ts
+++ b/src/lib/scoring.ts
@@ -1,5 +1,6 @@
-import { CRITERIA_STATUS, getTokenDoc, type Metric } from "@/lib/metrics-data"
+import { CRITERIA_STATUS, type Metric } from "@/lib/metrics-data"
import type { MetricScore, TokenScore } from "@/lib/schemas"
+import { getTokenById } from "@/lib/token-data"
export type { MetricScore, TokenScore }
@@ -44,9 +45,13 @@ export function getMetricScore(metric: Metric): MetricScore {
}
}
-/** Token scores are precomputed at compose time and read off the token doc. */
+/**
+ * Token scores are precomputed at compose time and carried on index rows
+ * (full per-metric breakdown — the dashboard score hover needs it), so this
+ * works on every page from the index read model alone.
+ */
export function getTokenOwnershipScore(tokenId: string): TokenScore {
- const doc = getTokenDoc(tokenId)
- if (doc) return doc.score
+ const row = getTokenById(tokenId)
+ if (row) return row.score
return { tokenId, passing: 0, total: 0, percentage: 0, metrics: [] }
}
diff --git a/src/lib/server/published-data.ts b/src/lib/server/published-data.ts
index e9cca4d..b0f93dc 100644
--- a/src/lib/server/published-data.ts
+++ b/src/lib/server/published-data.ts
@@ -6,9 +6,16 @@
* implementation replaces the internals without any response-shape change —
* consumers depend only on this module's interface.
*/
+import frameworkData from "@/data/generated/framework.json"
import indexData from "@/data/generated/index.json"
import manifestData from "@/data/generated/manifest.json"
-import type { IndexRow, Manifest, Provenance, TokenDoc } from "@/lib/schemas"
+import type {
+ FrameworkDoc,
+ IndexRow,
+ Manifest,
+ Provenance,
+ TokenDoc,
+} from "@/lib/schemas"
const manifest = manifestData as Manifest
@@ -52,6 +59,10 @@ export function getPublishedTokenDoc(tokenId: string): TokenDoc | null {
return tokenDocs.get(tokenId.trim().toLowerCase()) ?? null
}
+export function getPublishedFramework(): FrameworkDoc {
+ return frameworkData as FrameworkDoc
+}
+
export function listPublishedTokenIds(): string[] {
return manifest.tokens
}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index db1f228..e42a255 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -13,6 +13,7 @@
*/
import {
getProvenance,
+ getPublishedFramework,
getPublishedIndex,
getPublishedTokenDoc,
} from "@/lib/server/published-data"
@@ -36,6 +37,14 @@ export function handleGetTokens(): Response {
})
}
+/** GET /api/framework — canonical metric/criteria definitions + anchors. */
+export function handleGetFramework(): Response {
+ return jsonResponse({
+ data: getPublishedFramework(),
+ provenance: getProvenance(),
+ })
+}
+
/** GET /api/tokens/{id} — one composed token doc (the per-token reusable unit). */
export function handleGetToken(tokenId: string): Response {
const doc = getPublishedTokenDoc(tokenId)
diff --git a/src/lib/token-data.ts b/src/lib/token-data.ts
index 0130266..042fb8b 100644
--- a/src/lib/token-data.ts
+++ b/src/lib/token-data.ts
@@ -1,17 +1,34 @@
-import indexData from "@/data/generated/index.json"
+import { publishedIndexQuery } from "@/lib/published-queries"
+import { queryClient } from "@/lib/query-client"
import type { IndexRow } from "@/lib/schemas"
export type Token = IndexRow
-const tokens = indexData.tokens as Token[]
+/**
+ * Synchronous read over the hydrated query cache. Route loaders are
+ * responsible for ensuring the published index before render (the root
+ * route loader does this for every page). A cache miss is a programming
+ * error and fails loudly by design — no silent fallbacks (ADR 0002 spirit).
+ */
+function readPublishedIndex(): { tokens: Token[] } {
+ const data = queryClient.getQueryData(publishedIndexQuery.queryKey)
+ if (!data) {
+ throw new Error(
+ "Published token index is not in the query cache — a route loader must ensure publishedIndexQuery before render"
+ )
+ }
+ return data
+}
function getTokens(): Token[] {
- return tokens
+ return readPublishedIndex().tokens
}
function getTokenById(tokenId: string): Token | null {
const normalizedId = tokenId.trim().toLowerCase()
- return tokens.find((token) => token.id.toLowerCase() === normalizedId) ?? null
+ return (
+ getTokens().find((token) => token.id.toLowerCase() === normalizedId) ?? null
+ )
}
export { getTokenById, getTokens }
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 32ef9cc..f2100d3 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -13,6 +13,7 @@ import { Route as FaqRouteImport } from './routes/faq'
import { Route as IndexRouteImport } from './routes/index'
import { Route as TokensTokenIdRouteImport } from './routes/tokens/$tokenId'
import { Route as ApiTokensRouteImport } from './routes/api.tokens'
+import { Route as ApiFrameworkRouteImport } from './routes/api.framework'
import { Route as ApiTokensTokenIdRouteImport } from './routes/api.tokens.$tokenId'
const FaqRoute = FaqRouteImport.update({
@@ -35,6 +36,11 @@ const ApiTokensRoute = ApiTokensRouteImport.update({
path: '/api/tokens',
getParentRoute: () => rootRouteImport,
} as any)
+const ApiFrameworkRoute = ApiFrameworkRouteImport.update({
+ id: '/api/framework',
+ path: '/api/framework',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ApiTokensTokenIdRoute = ApiTokensTokenIdRouteImport.update({
id: '/$tokenId',
path: '/$tokenId',
@@ -44,6 +50,7 @@ const ApiTokensTokenIdRoute = ApiTokensTokenIdRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/framework': typeof ApiFrameworkRoute
'/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
@@ -51,6 +58,7 @@ export interface FileRoutesByFullPath {
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/framework': typeof ApiFrameworkRoute
'/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
@@ -59,6 +67,7 @@ export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/faq': typeof FaqRoute
+ '/api/framework': typeof ApiFrameworkRoute
'/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
@@ -68,15 +77,23 @@ export interface FileRouteTypes {
fullPaths:
| '/'
| '/faq'
+ | '/api/framework'
| '/api/tokens'
| '/tokens/$tokenId'
| '/api/tokens/$tokenId'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '/faq' | '/api/tokens' | '/tokens/$tokenId' | '/api/tokens/$tokenId'
+ to:
+ | '/'
+ | '/faq'
+ | '/api/framework'
+ | '/api/tokens'
+ | '/tokens/$tokenId'
+ | '/api/tokens/$tokenId'
id:
| '__root__'
| '/'
| '/faq'
+ | '/api/framework'
| '/api/tokens'
| '/tokens/$tokenId'
| '/api/tokens/$tokenId'
@@ -85,6 +102,7 @@ export interface FileRouteTypes {
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
FaqRoute: typeof FaqRoute
+ ApiFrameworkRoute: typeof ApiFrameworkRoute
ApiTokensRoute: typeof ApiTokensRouteWithChildren
TokensTokenIdRoute: typeof TokensTokenIdRoute
}
@@ -119,6 +137,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiTokensRouteImport
parentRoute: typeof rootRouteImport
}
+ '/api/framework': {
+ id: '/api/framework'
+ path: '/api/framework'
+ fullPath: '/api/framework'
+ preLoaderRoute: typeof ApiFrameworkRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/api/tokens/$tokenId': {
id: '/api/tokens/$tokenId'
path: '/$tokenId'
@@ -144,6 +169,7 @@ const ApiTokensRouteWithChildren = ApiTokensRoute._addFileChildren(
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
FaqRoute: FaqRoute,
+ ApiFrameworkRoute: ApiFrameworkRoute,
ApiTokensRoute: ApiTokensRouteWithChildren,
TokensTokenIdRoute: TokensTokenIdRoute,
}
diff --git a/src/router.tsx b/src/router.tsx
index 8c42ff2..d4d224b 100644
--- a/src/router.tsx
+++ b/src/router.tsx
@@ -1,15 +1,35 @@
import { createRouter } from "@tanstack/react-router"
+import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"
+import { queryClient } from "./lib/query-client"
// Import the generated route tree
import { routeTree } from "./routeTree.gen"
-// Create a new router instance
-export const router = createRouter({
- routeTree,
- scrollRestoration: true,
- defaultPreloadStaleTime: 0,
- trailingSlash: "preserve",
-})
+/**
+ * Router factory — TanStack Start calls this per SSR request (and once on the
+ * client). The router MUST be fresh per request: SSR streaming state lives on
+ * the router instance, and a shared router carries request A's consumed
+ * stream into request B ("ReadableStream is locked").
+ *
+ * The QueryClient stays a shared singleton (src/lib/query-client.ts): the
+ * published data it caches is immutable per deployment snapshot, so
+ * cross-request sharing is correct — and the data libs read it synchronously.
+ */
+export function getRouter() {
+ const router = createRouter({
+ routeTree,
+ scrollRestoration: true,
+ defaultPreloadStaleTime: 0,
+ trailingSlash: "preserve",
+ })
-// Legacy function export for backward compatibility
-export const getRouter = () => router
+ // Dehydrates the query cache into the SSR stream and hydrates it on the
+ // client, so loader-ensured published data is synchronously readable on
+ // first client render. Also wraps the app in a QueryClientProvider.
+ setupRouterSsrQueryIntegration({
+ router,
+ queryClient,
+ })
+
+ return router
+}
diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx
index 54f4b38..b38cd18 100644
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -1,5 +1,4 @@
import { TanStackDevtools } from "@tanstack/react-devtools"
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import {
createRootRoute,
HeadContent,
@@ -14,9 +13,23 @@ import { SiteFooter } from "@/components/site-footer"
import { SiteHeader } from "@/components/site-header"
import { GA_MEASUREMENT_ID } from "@/lib/analytics"
import { generateOpenGraphMetadata } from "@/lib/metadata"
+import {
+ publishedFrameworkQuery,
+ publishedIndexQuery,
+} from "@/lib/published-queries"
+import { queryClient } from "@/lib/query-client"
import appCss from "../styles.css?url"
export const Route = createRootRoute({
+ // Every page reads the published index (header search, dashboard) and the
+ // framework doc (header link, metric cards) synchronously from the query
+ // cache — ensure them before render, on server and client alike.
+ loader: async () => {
+ await Promise.all([
+ queryClient.ensureQueryData(publishedIndexQuery),
+ queryClient.ensureQueryData(publishedFrameworkQuery),
+ ])
+ },
head: () => ({
meta: [
{
@@ -40,19 +53,15 @@ export const Route = createRootRoute({
notFoundComponent: () => ,
})
-const queryClient = new QueryClient()
-
function RootComponent() {
return (
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
)
}
diff --git a/src/routes/api.framework.ts b/src/routes/api.framework.ts
new file mode 100644
index 0000000..08f8084
--- /dev/null
+++ b/src/routes/api.framework.ts
@@ -0,0 +1,10 @@
+import { createFileRoute } from "@tanstack/react-router"
+import { handleGetFramework } from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/framework")({
+ server: {
+ handlers: {
+ GET: () => handleGetFramework(),
+ },
+ },
+})
diff --git a/src/routes/tokens/$tokenId.tsx b/src/routes/tokens/$tokenId.tsx
index d9f3825..e029097 100644
--- a/src/routes/tokens/$tokenId.tsx
+++ b/src/routes/tokens/$tokenId.tsx
@@ -1,9 +1,16 @@
import { createFileRoute } from "@tanstack/react-router"
import TokenDetail from "@/components/token-detail"
import { generateOpenGraphMetadata } from "@/lib/metadata"
+import { publishedTokenDocQuery } from "@/lib/published-queries"
+import { queryClient } from "@/lib/query-client"
import { getTokenById } from "@/lib/token-data"
export const Route = createFileRoute("/tokens/$tokenId")({
+ // The detail page reads the full composed token doc (metrics, criteria,
+ // evidence) synchronously from the query cache — ensure it before render.
+ loader: async ({ params }) => {
+ await queryClient.ensureQueryData(publishedTokenDocQuery(params.tokenId))
+ },
component: TokenDetailPage,
head: ({ params }) => {
const token = getTokenById(params.tokenId)
diff --git a/tests/api-endpoints.test.ts b/tests/api-endpoints.test.ts
index 5b43cad..c817889 100644
--- a/tests/api-endpoints.test.ts
+++ b/tests/api-endpoints.test.ts
@@ -7,11 +7,16 @@ import { join } from "node:path"
import { describe, expect, it } from "vitest"
import {
apiErrorSchema,
+ frameworkDocSchema,
indexSchema,
provenanceSchema,
tokenDocSchema,
} from "@/lib/schemas"
-import { handleGetToken, handleGetTokens } from "@/lib/server/token-api"
+import {
+ handleGetFramework,
+ handleGetToken,
+ handleGetTokens,
+} from "@/lib/server/token-api"
const generated = join(__dirname, "..", "src", "data", "generated")
const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
@@ -49,6 +54,17 @@ describe("GET /api/tokens", () => {
})
})
+describe("GET /api/framework", () => {
+ it("returns the framework doc with provenance, identical to generated", async () => {
+ const res = handleGetFramework()
+ expect(res.status).toBe(200)
+ const payload = await body(res)
+ expect(() => frameworkDocSchema.parse(payload.data)).not.toThrow()
+ expect(() => provenanceSchema.parse(payload.provenance)).not.toThrow()
+ expect(payload.data).toEqual(readJson(join(generated, "framework.json")))
+ })
+})
+
describe("GET /api/tokens/{id}", () => {
it("returns every published token doc identical to its generated file", async () => {
for (const id of TOKEN_IDS) {
diff --git a/tests/round-trip.test.ts b/tests/round-trip.test.ts
index af6f9a3..4246d2d 100644
--- a/tests/round-trip.test.ts
+++ b/tests/round-trip.test.ts
@@ -117,12 +117,9 @@ describe("round-trip vs golden fixtures", () => {
const { metrics: _metrics, ...doc } = composed.tokenDocs.find(
(d: { id: string }) => d.id === row.id
)
- expect(withoutCounts(row)).toEqual(withoutCounts(doc))
- expect(row.score).toEqual({
- passing: doc.score.passing,
- total: doc.score.total,
- percentage: doc.score.percentage,
- })
+ // Index rows ARE the doc minus metrics (full score + criterion-status
+ // map included) — the dashboard read model needs no per-token docs.
+ expect(row).toEqual(doc)
}
})
})
From aa26ed5aac054a0c308c1dddbc1cc01244c577cd Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Sat, 6 Jun 2026 19:57:49 +0200
Subject: [PATCH 11/38] refactor: source published content from otf-cms
---
.github/workflows/update-token-timestamps.yml | 79 -
.../aave/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
.../evaluations/aave/offchain/_metric.json | 6 -
.../aave/offchain/offchain__distribution.json | 15 -
.../aave/offchain/offchain__licensing.json | 5 -
.../aave/offchain/offchain__trademark.json | 15 -
.../aave/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 64 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 15 -
.../onchain-ctrl__protocol-upgrade.json | 43 -
.../onchain-ctrl__role-accountability.json | 21 -
.../onchain-ctrl/onchain-ctrl__supply.json | 15 -
.../onchain-ctrl__token-upgrade.json | 27 -
.../evaluations/aave/val-accrual/_metric.json | 6 -
.../aave/val-accrual/val-accrual__active.json | 25 -
.../val-accrual/val-accrual__mechanism.json | 22 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 38 -
.../aave/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../aero/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
.../evaluations/aero/offchain/_metric.json | 6 -
.../aero/offchain/offchain__distribution.json | 15 -
.../aero/offchain/offchain__licensing.json | 5 -
.../aero/offchain/offchain__trademark.json | 15 -
.../aero/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 44 -
.../onchain-ctrl__censorship.json | 38 -
.../onchain-ctrl__governance-workflow.json | 43 -
.../onchain-ctrl__protocol-upgrade.json | 15 -
.../onchain-ctrl__role-accountability.json | 22 -
.../onchain-ctrl/onchain-ctrl__supply.json | 55 -
.../onchain-ctrl__token-upgrade.json | 20 -
.../evaluations/aero/val-accrual/_metric.json | 6 -
.../aero/val-accrual/val-accrual__active.json | 84 -
.../val-accrual/val-accrual__mechanism.json | 33 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 5 -
.../aero/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 20 -
.../verifiability__token-source.json | 20 -
.../evaluations/crv/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 15 -
content/evaluations/crv/offchain/_metric.json | 6 -
.../crv/offchain/offchain__distribution.json | 15 -
.../crv/offchain/offchain__licensing.json | 5 -
.../crv/offchain/offchain__trademark.json | 15 -
.../evaluations/crv/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 17 -
.../onchain-ctrl__censorship.json | 20 -
.../onchain-ctrl__governance-workflow.json | 25 -
.../onchain-ctrl__protocol-upgrade.json | 44 -
.../onchain-ctrl__role-accountability.json | 28 -
.../onchain-ctrl/onchain-ctrl__supply.json | 38 -
.../onchain-ctrl__token-upgrade.json | 15 -
.../evaluations/crv/val-accrual/_metric.json | 6 -
.../crv/val-accrual/val-accrual__active.json | 39 -
.../val-accrual/val-accrual__mechanism.json | 39 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../crv/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../evaluations/ena/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 22 -
content/evaluations/ena/offchain/_metric.json | 6 -
.../ena/offchain/offchain__distribution.json | 15 -
.../ena/offchain/offchain__licensing.json | 20 -
.../ena/offchain/offchain__trademark.json | 15 -
.../evaluations/ena/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 27 -
.../onchain-ctrl__governance-workflow.json | 33 -
.../onchain-ctrl__protocol-upgrade.json | 68 -
.../onchain-ctrl__role-accountability.json | 58 -
.../onchain-ctrl/onchain-ctrl__supply.json | 22 -
.../onchain-ctrl__token-upgrade.json | 22 -
.../evaluations/ena/val-accrual/_metric.json | 6 -
.../ena/val-accrual/val-accrual__active.json | 59 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../val-accrual/val-accrual__offchain.json | 33 -
.../val-accrual/val-accrual__treasury.json | 43 -
.../ena/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 71 -
.../verifiability__token-source.json | 20 -
.../ethfi/distribution/_metric.json | 6 -
.../distribution__concentration.json | 16 -
.../distribution__supply-schedule.json | 21 -
.../evaluations/ethfi/offchain/_metric.json | 6 -
.../offchain/offchain__distribution.json | 16 -
.../ethfi/offchain/offchain__licensing.json | 21 -
.../ethfi/offchain/offchain__trademark.json | 16 -
.../ethfi/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 17 -
.../onchain-ctrl__censorship.json | 27 -
.../onchain-ctrl__governance-workflow.json | 27 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 43 -
.../onchain-ctrl/onchain-ctrl__supply.json | 22 -
.../onchain-ctrl__token-upgrade.json | 43 -
.../ethfi/val-accrual/_metric.json | 6 -
.../val-accrual/val-accrual__active.json | 32 -
.../val-accrual/val-accrual__mechanism.json | 17 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 22 -
.../ethfi/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 21 -
.../verifiability__token-source.json | 17 -
.../evaluations/ldo/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
content/evaluations/ldo/offchain/_metric.json | 6 -
.../ldo/offchain/offchain__distribution.json | 25 -
.../ldo/offchain/offchain__licensing.json | 25 -
.../ldo/offchain/offchain__trademark.json | 20 -
.../evaluations/ldo/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 33 -
.../onchain-ctrl__governance-workflow.json | 64 -
.../onchain-ctrl__protocol-upgrade.json | 48 -
.../onchain-ctrl__role-accountability.json | 50 -
.../onchain-ctrl/onchain-ctrl__supply.json | 17 -
.../onchain-ctrl__token-upgrade.json | 33 -
.../evaluations/ldo/val-accrual/_metric.json | 6 -
.../ldo/val-accrual/val-accrual__active.json | 46 -
.../val-accrual/val-accrual__mechanism.json | 15 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 28 -
.../ldo/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../lqty/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 20 -
.../evaluations/lqty/offchain/_metric.json | 6 -
.../lqty/offchain/offchain__distribution.json | 25 -
.../lqty/offchain/offchain__licensing.json | 25 -
.../lqty/offchain/offchain__trademark.json | 25 -
.../lqty/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 16 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 20 -
.../onchain-ctrl__protocol-upgrade.json | 15 -
.../onchain-ctrl__role-accountability.json | 15 -
.../onchain-ctrl/onchain-ctrl__supply.json | 15 -
.../onchain-ctrl__token-upgrade.json | 15 -
.../evaluations/lqty/val-accrual/_metric.json | 6 -
.../lqty/val-accrual/val-accrual__active.json | 40 -
.../val-accrual/val-accrual__mechanism.json | 20 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../lqty/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 20 -
.../verifiability__token-source.json | 20 -
.../ondo/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 22 -
.../evaluations/ondo/offchain/_metric.json | 6 -
.../ondo/offchain/offchain__distribution.json | 17 -
.../ondo/offchain/offchain__licensing.json | 27 -
.../ondo/offchain/offchain__trademark.json | 17 -
.../ondo/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 22 -
.../onchain-ctrl__governance-workflow.json | 42 -
.../onchain-ctrl__protocol-upgrade.json | 63 -
.../onchain-ctrl__role-accountability.json | 94 -
.../onchain-ctrl/onchain-ctrl__supply.json | 38 -
.../onchain-ctrl__token-upgrade.json | 33 -
.../evaluations/ondo/val-accrual/_metric.json | 6 -
.../ondo/val-accrual/val-accrual__active.json | 32 -
.../val-accrual/val-accrual__mechanism.json | 48 -
.../val-accrual/val-accrual__offchain.json | 51 -
.../val-accrual/val-accrual__treasury.json | 17 -
.../ondo/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 51 -
.../verifiability__token-source.json | 20 -
.../evaluations/sky/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 17 -
content/evaluations/sky/offchain/_metric.json | 6 -
.../sky/offchain/offchain__distribution.json | 17 -
.../sky/offchain/offchain__licensing.json | 17 -
.../sky/offchain/offchain__trademark.json | 28 -
.../evaluations/sky/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 27 -
.../onchain-ctrl__censorship.json | 17 -
.../onchain-ctrl__governance-workflow.json | 38 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 43 -
.../onchain-ctrl/onchain-ctrl__supply.json | 33 -
.../onchain-ctrl__token-upgrade.json | 17 -
.../evaluations/sky/val-accrual/_metric.json | 6 -
.../sky/val-accrual/val-accrual__active.json | 48 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../val-accrual/val-accrual__offchain.json | 20 -
.../val-accrual/val-accrual__treasury.json | 17 -
.../sky/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 22 -
.../verifiability__token-source.json | 22 -
.../evaluations/uni/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 37 -
content/evaluations/uni/offchain/_metric.json | 6 -
.../uni/offchain/offchain__distribution.json | 15 -
.../uni/offchain/offchain__licensing.json | 5 -
.../uni/offchain/offchain__trademark.json | 15 -
.../evaluations/uni/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 5 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 20 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 55 -
.../onchain-ctrl/onchain-ctrl__supply.json | 33 -
.../onchain-ctrl__token-upgrade.json | 20 -
.../evaluations/uni/val-accrual/_metric.json | 6 -
.../uni/val-accrual/val-accrual__active.json | 65 -
.../val-accrual/val-accrual__mechanism.json | 49 -
.../val-accrual/val-accrual__offchain.json | 15 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../uni/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 30 -
.../verifiability__token-source.json | 20 -
.../evaluations/yb/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 17 -
content/evaluations/yb/offchain/_metric.json | 6 -
.../yb/offchain/offchain__distribution.json | 15 -
.../yb/offchain/offchain__licensing.json | 22 -
.../yb/offchain/offchain__trademark.json | 5 -
.../evaluations/yb/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 22 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 32 -
.../onchain-ctrl__protocol-upgrade.json | 27 -
.../onchain-ctrl__role-accountability.json | 43 -
.../yb/onchain-ctrl/onchain-ctrl__supply.json | 27 -
.../onchain-ctrl__token-upgrade.json | 22 -
.../evaluations/yb/val-accrual/_metric.json | 6 -
.../yb/val-accrual/val-accrual__active.json | 42 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../yb/val-accrual/val-accrual__offchain.json | 8 -
.../yb/val-accrual/val-accrual__treasury.json | 27 -
.../evaluations/yb/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 22 -
.../verifiability__token-source.json | 20 -
content/faq.json | 60 -
content/framework/_meta.json | 10 -
content/framework/distribution.json | 19 -
content/framework/offchain.json | 24 -
content/framework/onchain-ctrl.json | 44 -
content/framework/val-accrual.json | 29 -
content/framework/verifiability.json | 19 -
content/testimonials.json | 21 -
content/tokens/aave.json | 21 -
content/tokens/aero.json | 21 -
content/tokens/crv.json | 21 -
content/tokens/ena.json | 21 -
content/tokens/ethfi.json | 21 -
content/tokens/ldo.json | 21 -
content/tokens/lqty.json | 21 -
content/tokens/ondo.json | 21 -
content/tokens/sky.json | 21 -
content/tokens/uni.json | 21 -
content/tokens/yb.json | 21 -
package.json | 5 +-
scripts/compose-data.mjs | 196 -
scripts/get-changed-token-ids.mjs | 70 -
scripts/migrate-to-atoms.mjs | 127 -
scripts/sync-coingecko-ids.mjs | 138 -
scripts/update-token-timestamps.mjs | 62 -
src/lib/schemas/index.ts | 12 +-
tests/atoms-valid.test.ts | 106 -
.../aave/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
.../evaluations/aave/offchain/_metric.json | 6 -
.../aave/offchain/offchain__distribution.json | 15 -
.../aave/offchain/offchain__licensing.json | 5 -
.../aave/offchain/offchain__trademark.json | 15 -
.../aave/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 64 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 15 -
.../onchain-ctrl__protocol-upgrade.json | 43 -
.../onchain-ctrl__role-accountability.json | 21 -
.../onchain-ctrl/onchain-ctrl__supply.json | 15 -
.../onchain-ctrl__token-upgrade.json | 27 -
.../evaluations/aave/val-accrual/_metric.json | 6 -
.../aave/val-accrual/val-accrual__active.json | 25 -
.../val-accrual/val-accrual__mechanism.json | 22 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 38 -
.../aave/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../aero/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
.../evaluations/aero/offchain/_metric.json | 6 -
.../aero/offchain/offchain__distribution.json | 15 -
.../aero/offchain/offchain__licensing.json | 5 -
.../aero/offchain/offchain__trademark.json | 15 -
.../aero/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 44 -
.../onchain-ctrl__censorship.json | 38 -
.../onchain-ctrl__governance-workflow.json | 43 -
.../onchain-ctrl__protocol-upgrade.json | 15 -
.../onchain-ctrl__role-accountability.json | 22 -
.../onchain-ctrl/onchain-ctrl__supply.json | 55 -
.../onchain-ctrl__token-upgrade.json | 20 -
.../evaluations/aero/val-accrual/_metric.json | 6 -
.../aero/val-accrual/val-accrual__active.json | 84 -
.../val-accrual/val-accrual__mechanism.json | 33 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 5 -
.../aero/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 20 -
.../verifiability__token-source.json | 20 -
.../evaluations/crv/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 15 -
.../evaluations/crv/offchain/_metric.json | 6 -
.../crv/offchain/offchain__distribution.json | 15 -
.../crv/offchain/offchain__licensing.json | 5 -
.../crv/offchain/offchain__trademark.json | 15 -
.../evaluations/crv/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 17 -
.../onchain-ctrl__censorship.json | 20 -
.../onchain-ctrl__governance-workflow.json | 25 -
.../onchain-ctrl__protocol-upgrade.json | 44 -
.../onchain-ctrl__role-accountability.json | 28 -
.../onchain-ctrl/onchain-ctrl__supply.json | 38 -
.../onchain-ctrl__token-upgrade.json | 15 -
.../evaluations/crv/val-accrual/_metric.json | 6 -
.../crv/val-accrual/val-accrual__active.json | 39 -
.../val-accrual/val-accrual__mechanism.json | 39 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../crv/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../evaluations/ena/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 22 -
.../evaluations/ena/offchain/_metric.json | 6 -
.../ena/offchain/offchain__distribution.json | 15 -
.../ena/offchain/offchain__licensing.json | 20 -
.../ena/offchain/offchain__trademark.json | 15 -
.../evaluations/ena/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 27 -
.../onchain-ctrl__governance-workflow.json | 33 -
.../onchain-ctrl__protocol-upgrade.json | 68 -
.../onchain-ctrl__role-accountability.json | 58 -
.../onchain-ctrl/onchain-ctrl__supply.json | 22 -
.../onchain-ctrl__token-upgrade.json | 22 -
.../evaluations/ena/val-accrual/_metric.json | 6 -
.../ena/val-accrual/val-accrual__active.json | 59 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../val-accrual/val-accrual__offchain.json | 33 -
.../val-accrual/val-accrual__treasury.json | 43 -
.../ena/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 71 -
.../verifiability__token-source.json | 20 -
.../ethfi/distribution/_metric.json | 6 -
.../distribution__concentration.json | 16 -
.../distribution__supply-schedule.json | 21 -
.../evaluations/ethfi/offchain/_metric.json | 6 -
.../offchain/offchain__distribution.json | 16 -
.../ethfi/offchain/offchain__licensing.json | 21 -
.../ethfi/offchain/offchain__trademark.json | 16 -
.../ethfi/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 17 -
.../onchain-ctrl__censorship.json | 27 -
.../onchain-ctrl__governance-workflow.json | 27 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 43 -
.../onchain-ctrl/onchain-ctrl__supply.json | 22 -
.../onchain-ctrl__token-upgrade.json | 43 -
.../ethfi/val-accrual/_metric.json | 6 -
.../val-accrual/val-accrual__active.json | 32 -
.../val-accrual/val-accrual__mechanism.json | 17 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 22 -
.../ethfi/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 21 -
.../verifiability__token-source.json | 17 -
.../evaluations/ldo/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 5 -
.../evaluations/ldo/offchain/_metric.json | 6 -
.../ldo/offchain/offchain__distribution.json | 25 -
.../ldo/offchain/offchain__licensing.json | 25 -
.../ldo/offchain/offchain__trademark.json | 20 -
.../evaluations/ldo/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 33 -
.../onchain-ctrl__governance-workflow.json | 64 -
.../onchain-ctrl__protocol-upgrade.json | 48 -
.../onchain-ctrl__role-accountability.json | 50 -
.../onchain-ctrl/onchain-ctrl__supply.json | 17 -
.../onchain-ctrl__token-upgrade.json | 33 -
.../evaluations/ldo/val-accrual/_metric.json | 6 -
.../ldo/val-accrual/val-accrual__active.json | 46 -
.../val-accrual/val-accrual__mechanism.json | 15 -
.../val-accrual/val-accrual__offchain.json | 5 -
.../val-accrual/val-accrual__treasury.json | 28 -
.../ldo/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 15 -
.../verifiability__token-source.json | 20 -
.../lqty/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 20 -
.../evaluations/lqty/offchain/_metric.json | 6 -
.../lqty/offchain/offchain__distribution.json | 25 -
.../lqty/offchain/offchain__licensing.json | 25 -
.../lqty/offchain/offchain__trademark.json | 25 -
.../lqty/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 16 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 20 -
.../onchain-ctrl__protocol-upgrade.json | 15 -
.../onchain-ctrl__role-accountability.json | 15 -
.../onchain-ctrl/onchain-ctrl__supply.json | 15 -
.../onchain-ctrl__token-upgrade.json | 15 -
.../evaluations/lqty/val-accrual/_metric.json | 6 -
.../lqty/val-accrual/val-accrual__active.json | 40 -
.../val-accrual/val-accrual__mechanism.json | 20 -
.../val-accrual/val-accrual__offchain.json | 8 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../lqty/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 20 -
.../verifiability__token-source.json | 20 -
.../ondo/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 22 -
.../evaluations/ondo/offchain/_metric.json | 6 -
.../ondo/offchain/offchain__distribution.json | 17 -
.../ondo/offchain/offchain__licensing.json | 27 -
.../ondo/offchain/offchain__trademark.json | 17 -
.../ondo/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 43 -
.../onchain-ctrl__censorship.json | 22 -
.../onchain-ctrl__governance-workflow.json | 42 -
.../onchain-ctrl__protocol-upgrade.json | 63 -
.../onchain-ctrl__role-accountability.json | 94 -
.../onchain-ctrl/onchain-ctrl__supply.json | 38 -
.../onchain-ctrl__token-upgrade.json | 33 -
.../evaluations/ondo/val-accrual/_metric.json | 6 -
.../ondo/val-accrual/val-accrual__active.json | 32 -
.../val-accrual/val-accrual__mechanism.json | 48 -
.../val-accrual/val-accrual__offchain.json | 51 -
.../val-accrual/val-accrual__treasury.json | 17 -
.../ondo/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 51 -
.../verifiability__token-source.json | 20 -
.../evaluations/sky/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 17 -
.../evaluations/sky/offchain/_metric.json | 6 -
.../sky/offchain/offchain__distribution.json | 17 -
.../sky/offchain/offchain__licensing.json | 17 -
.../sky/offchain/offchain__trademark.json | 28 -
.../evaluations/sky/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 27 -
.../onchain-ctrl__censorship.json | 17 -
.../onchain-ctrl__governance-workflow.json | 38 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 43 -
.../onchain-ctrl/onchain-ctrl__supply.json | 33 -
.../onchain-ctrl__token-upgrade.json | 17 -
.../evaluations/sky/val-accrual/_metric.json | 6 -
.../sky/val-accrual/val-accrual__active.json | 48 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../val-accrual/val-accrual__offchain.json | 20 -
.../val-accrual/val-accrual__treasury.json | 17 -
.../sky/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 22 -
.../verifiability__token-source.json | 22 -
.../evaluations/uni/distribution/_metric.json | 6 -
.../distribution__concentration.json | 5 -
.../distribution__supply-schedule.json | 37 -
.../evaluations/uni/offchain/_metric.json | 6 -
.../uni/offchain/offchain__distribution.json | 15 -
.../uni/offchain/offchain__licensing.json | 5 -
.../uni/offchain/offchain__trademark.json | 15 -
.../evaluations/uni/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 5 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 20 -
.../onchain-ctrl__protocol-upgrade.json | 38 -
.../onchain-ctrl__role-accountability.json | 55 -
.../onchain-ctrl/onchain-ctrl__supply.json | 33 -
.../onchain-ctrl__token-upgrade.json | 20 -
.../evaluations/uni/val-accrual/_metric.json | 6 -
.../uni/val-accrual/val-accrual__active.json | 65 -
.../val-accrual/val-accrual__mechanism.json | 49 -
.../val-accrual/val-accrual__offchain.json | 15 -
.../val-accrual/val-accrual__treasury.json | 15 -
.../uni/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 30 -
.../verifiability__token-source.json | 20 -
.../evaluations/yb/distribution/_metric.json | 6 -
.../distribution__concentration.json | 22 -
.../distribution__supply-schedule.json | 17 -
.../evaluations/yb/offchain/_metric.json | 6 -
.../yb/offchain/offchain__distribution.json | 15 -
.../yb/offchain/offchain__licensing.json | 22 -
.../yb/offchain/offchain__trademark.json | 5 -
.../evaluations/yb/onchain-ctrl/_metric.json | 6 -
.../onchain-ctrl__access-gating.json | 22 -
.../onchain-ctrl__censorship.json | 15 -
.../onchain-ctrl__governance-workflow.json | 32 -
.../onchain-ctrl__protocol-upgrade.json | 27 -
.../onchain-ctrl__role-accountability.json | 43 -
.../yb/onchain-ctrl/onchain-ctrl__supply.json | 27 -
.../onchain-ctrl__token-upgrade.json | 22 -
.../evaluations/yb/val-accrual/_metric.json | 6 -
.../yb/val-accrual/val-accrual__active.json | 42 -
.../val-accrual/val-accrual__mechanism.json | 38 -
.../yb/val-accrual/val-accrual__offchain.json | 8 -
.../yb/val-accrual/val-accrual__treasury.json | 27 -
.../evaluations/yb/verifiability/_metric.json | 6 -
.../verifiability__protocol-source.json | 22 -
.../verifiability__token-source.json | 20 -
tests/fixtures/content-6b17fa7/faq.json | 60 -
.../content-6b17fa7/framework/_meta.json | 10 -
.../framework/distribution.json | 19 -
.../content-6b17fa7/framework/offchain.json | 24 -
.../framework/onchain-ctrl.json | 44 -
.../framework/val-accrual.json | 29 -
.../framework/verifiability.json | 19 -
.../content-6b17fa7/testimonials.json | 21 -
.../fixtures/content-6b17fa7/tokens/aave.json | 21 -
.../fixtures/content-6b17fa7/tokens/aero.json | 21 -
.../fixtures/content-6b17fa7/tokens/crv.json | 21 -
.../fixtures/content-6b17fa7/tokens/ena.json | 21 -
.../content-6b17fa7/tokens/ethfi.json | 21 -
.../fixtures/content-6b17fa7/tokens/ldo.json | 21 -
.../fixtures/content-6b17fa7/tokens/lqty.json | 21 -
.../fixtures/content-6b17fa7/tokens/ondo.json | 21 -
.../fixtures/content-6b17fa7/tokens/sky.json | 21 -
.../fixtures/content-6b17fa7/tokens/uni.json | 21 -
tests/fixtures/content-6b17fa7/tokens/yb.json | 21 -
tests/freshness.test.ts | 49 -
tests/generated-valid.test.ts | 55 +
tests/golden/faq.json | 58 -
tests/golden/framework.json | 127 -
tests/golden/metrics.json | 6311 -----------------
tests/golden/scores.json | 585 --
tests/golden/testimonials.json | 21 -
tests/golden/tokens.json | 277 -
tests/round-trip.test.ts | 125 -
562 files changed, 65 insertions(+), 20090 deletions(-)
delete mode 100644 .github/workflows/update-token-timestamps.yml
delete mode 100644 content/evaluations/aave/distribution/_metric.json
delete mode 100644 content/evaluations/aave/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/aave/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/aave/offchain/_metric.json
delete mode 100644 content/evaluations/aave/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/aave/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/aave/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/aave/val-accrual/_metric.json
delete mode 100644 content/evaluations/aave/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/aave/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/aave/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/aave/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/aave/verifiability/_metric.json
delete mode 100644 content/evaluations/aave/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/aave/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/aero/distribution/_metric.json
delete mode 100644 content/evaluations/aero/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/aero/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/aero/offchain/_metric.json
delete mode 100644 content/evaluations/aero/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/aero/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/aero/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/aero/val-accrual/_metric.json
delete mode 100644 content/evaluations/aero/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/aero/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/aero/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/aero/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/aero/verifiability/_metric.json
delete mode 100644 content/evaluations/aero/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/aero/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/crv/distribution/_metric.json
delete mode 100644 content/evaluations/crv/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/crv/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/crv/offchain/_metric.json
delete mode 100644 content/evaluations/crv/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/crv/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/crv/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/crv/val-accrual/_metric.json
delete mode 100644 content/evaluations/crv/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/crv/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/crv/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/crv/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/crv/verifiability/_metric.json
delete mode 100644 content/evaluations/crv/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/crv/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/ena/distribution/_metric.json
delete mode 100644 content/evaluations/ena/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/ena/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/ena/offchain/_metric.json
delete mode 100644 content/evaluations/ena/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/ena/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/ena/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/ena/val-accrual/_metric.json
delete mode 100644 content/evaluations/ena/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/ena/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/ena/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/ena/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/ena/verifiability/_metric.json
delete mode 100644 content/evaluations/ena/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/ena/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/ethfi/distribution/_metric.json
delete mode 100644 content/evaluations/ethfi/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/ethfi/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/ethfi/offchain/_metric.json
delete mode 100644 content/evaluations/ethfi/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/ethfi/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/ethfi/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/ethfi/val-accrual/_metric.json
delete mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/ethfi/verifiability/_metric.json
delete mode 100644 content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/ethfi/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/ldo/distribution/_metric.json
delete mode 100644 content/evaluations/ldo/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/ldo/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/ldo/offchain/_metric.json
delete mode 100644 content/evaluations/ldo/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/ldo/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/ldo/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/ldo/val-accrual/_metric.json
delete mode 100644 content/evaluations/ldo/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/ldo/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/ldo/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/ldo/verifiability/_metric.json
delete mode 100644 content/evaluations/ldo/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/ldo/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/lqty/distribution/_metric.json
delete mode 100644 content/evaluations/lqty/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/lqty/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/lqty/offchain/_metric.json
delete mode 100644 content/evaluations/lqty/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/lqty/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/lqty/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/lqty/val-accrual/_metric.json
delete mode 100644 content/evaluations/lqty/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/lqty/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/lqty/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/lqty/verifiability/_metric.json
delete mode 100644 content/evaluations/lqty/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/lqty/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/ondo/distribution/_metric.json
delete mode 100644 content/evaluations/ondo/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/ondo/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/ondo/offchain/_metric.json
delete mode 100644 content/evaluations/ondo/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/ondo/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/ondo/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/ondo/val-accrual/_metric.json
delete mode 100644 content/evaluations/ondo/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/ondo/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/ondo/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/ondo/verifiability/_metric.json
delete mode 100644 content/evaluations/ondo/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/ondo/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/sky/distribution/_metric.json
delete mode 100644 content/evaluations/sky/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/sky/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/sky/offchain/_metric.json
delete mode 100644 content/evaluations/sky/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/sky/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/sky/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/sky/val-accrual/_metric.json
delete mode 100644 content/evaluations/sky/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/sky/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/sky/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/sky/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/sky/verifiability/_metric.json
delete mode 100644 content/evaluations/sky/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/sky/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/uni/distribution/_metric.json
delete mode 100644 content/evaluations/uni/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/uni/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/uni/offchain/_metric.json
delete mode 100644 content/evaluations/uni/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/uni/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/uni/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/uni/val-accrual/_metric.json
delete mode 100644 content/evaluations/uni/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/uni/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/uni/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/uni/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/uni/verifiability/_metric.json
delete mode 100644 content/evaluations/uni/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/uni/verifiability/verifiability__token-source.json
delete mode 100644 content/evaluations/yb/distribution/_metric.json
delete mode 100644 content/evaluations/yb/distribution/distribution__concentration.json
delete mode 100644 content/evaluations/yb/distribution/distribution__supply-schedule.json
delete mode 100644 content/evaluations/yb/offchain/_metric.json
delete mode 100644 content/evaluations/yb/offchain/offchain__distribution.json
delete mode 100644 content/evaluations/yb/offchain/offchain__licensing.json
delete mode 100644 content/evaluations/yb/offchain/offchain__trademark.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/_metric.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 content/evaluations/yb/val-accrual/_metric.json
delete mode 100644 content/evaluations/yb/val-accrual/val-accrual__active.json
delete mode 100644 content/evaluations/yb/val-accrual/val-accrual__mechanism.json
delete mode 100644 content/evaluations/yb/val-accrual/val-accrual__offchain.json
delete mode 100644 content/evaluations/yb/val-accrual/val-accrual__treasury.json
delete mode 100644 content/evaluations/yb/verifiability/_metric.json
delete mode 100644 content/evaluations/yb/verifiability/verifiability__protocol-source.json
delete mode 100644 content/evaluations/yb/verifiability/verifiability__token-source.json
delete mode 100644 content/faq.json
delete mode 100644 content/framework/_meta.json
delete mode 100644 content/framework/distribution.json
delete mode 100644 content/framework/offchain.json
delete mode 100644 content/framework/onchain-ctrl.json
delete mode 100644 content/framework/val-accrual.json
delete mode 100644 content/framework/verifiability.json
delete mode 100644 content/testimonials.json
delete mode 100644 content/tokens/aave.json
delete mode 100644 content/tokens/aero.json
delete mode 100644 content/tokens/crv.json
delete mode 100644 content/tokens/ena.json
delete mode 100644 content/tokens/ethfi.json
delete mode 100644 content/tokens/ldo.json
delete mode 100644 content/tokens/lqty.json
delete mode 100644 content/tokens/ondo.json
delete mode 100644 content/tokens/sky.json
delete mode 100644 content/tokens/uni.json
delete mode 100644 content/tokens/yb.json
delete mode 100644 scripts/compose-data.mjs
delete mode 100644 scripts/get-changed-token-ids.mjs
delete mode 100644 scripts/migrate-to-atoms.mjs
delete mode 100644 scripts/sync-coingecko-ids.mjs
delete mode 100644 scripts/update-token-timestamps.mjs
delete mode 100644 tests/atoms-valid.test.ts
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
delete mode 100644 tests/fixtures/content-6b17fa7/faq.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/_meta.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/distribution.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/offchain.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/val-accrual.json
delete mode 100644 tests/fixtures/content-6b17fa7/framework/verifiability.json
delete mode 100644 tests/fixtures/content-6b17fa7/testimonials.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/aave.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/aero.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/crv.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/ena.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/ethfi.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/ldo.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/lqty.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/ondo.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/sky.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/uni.json
delete mode 100644 tests/fixtures/content-6b17fa7/tokens/yb.json
delete mode 100644 tests/freshness.test.ts
create mode 100644 tests/generated-valid.test.ts
delete mode 100644 tests/golden/faq.json
delete mode 100644 tests/golden/framework.json
delete mode 100644 tests/golden/metrics.json
delete mode 100644 tests/golden/scores.json
delete mode 100644 tests/golden/testimonials.json
delete mode 100644 tests/golden/tokens.json
delete mode 100644 tests/round-trip.test.ts
diff --git a/.github/workflows/update-token-timestamps.yml b/.github/workflows/update-token-timestamps.yml
deleted file mode 100644
index c91649e..0000000
--- a/.github/workflows/update-token-timestamps.yml
+++ /dev/null
@@ -1,79 +0,0 @@
-name: Update token timestamps
-
-on:
- push:
- branches: [development]
- paths:
- - content/tokens/**
- - content/evaluations/**
-
-permissions:
- contents: write
-
-jobs:
- update-token-timestamp:
- if: github.actor != 'github-actions[bot]'
- runs-on: ubuntu-latest
- steps:
- - name: Load secrets
- id: load-secrets
- uses: 1password/load-secrets-action@8d0d610af187e78a2772c2d18d627f4c52d3fbfb # v3.1.0
- with:
- export-env: false
- env:
- OP_SERVICE_ACCOUNT_TOKEN: "${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}"
- GPG_PASSPHRASE: op://kv_ownership-token-index_infra/arabot-1_SIGN_CERTS/credential
- GPG_PRIVATE_KEY: op://kv_ownership-token-index_infra/arabot-1_SIGN_CERTS/private_key
-
- - name: Checkout development
- uses: actions/checkout@v4
- with:
- ref: development
- fetch-depth: 0
-
- - name: Import GPG key
- uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
- with:
- gpg_private_key: ${{ steps.load-secrets.outputs.GPG_PRIVATE_KEY }}
- passphrase: ${{ steps.load-secrets.outputs.GPG_PASSPHRASE }}
- git_user_signingkey: true
- git_commit_gpgsign: true
-
- - name: Setup Node
- uses: actions/setup-node@v4
- with:
- node-version: "20"
-
- - name: Detect changed token ids
- id: changed
- run: |
- ids=$(node scripts/get-changed-token-ids.mjs --before "${{ github.event.before }}" --after "${{ github.event.after }}")
- echo "ids=$ids" >> $GITHUB_OUTPUT
-
- - name: Resolve commit timestamp
- id: timestamp
- run: |
- echo "value=$(node -e 'console.log(Math.floor(new Date(process.argv[1]).getTime() / 1000))' '${{ github.event.head_commit.timestamp }}')" >> $GITHUB_OUTPUT
-
- - name: Update timestamp
- if: steps.changed.outputs.ids != ''
- run: node scripts/update-token-timestamps.mjs --ids "${{ steps.changed.outputs.ids }}" --timestamp "${{ steps.timestamp.outputs.value }}"
-
- - name: Recompose read models
- if: steps.changed.outputs.ids != ''
- run: node scripts/compose-data.mjs
-
- - name: Set commit message
- id: commit-message
- run: |
- echo "message=chore: update token lastUpdated" >> $GITHUB_OUTPUT
-
- - name: Commit and push
- run: |
- if git diff --quiet; then
- echo "No changes to commit."
- exit 0
- fi
- git add content src/data/generated
- git commit -am "${{ steps.commit-message.outputs.message }}"
- git push origin HEAD:development
diff --git a/content/evaluations/aave/distribution/_metric.json b/content/evaluations/aave/distribution/_metric.json
deleted file mode 100644
index 2163fcd..0000000
--- a/content/evaluations/aave/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/aave/distribution/distribution__concentration.json b/content/evaluations/aave/distribution/distribution__concentration.json
deleted file mode 100644
index 5e8dfb9..0000000
--- a/content/evaluations/aave/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "evidence": []
-}
diff --git a/content/evaluations/aave/distribution/distribution__supply-schedule.json b/content/evaluations/aave/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 195571e..0000000
--- a/content/evaluations/aave/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
- "evidence": []
-}
diff --git a/content/evaluations/aave/offchain/_metric.json b/content/evaluations/aave/offchain/_metric.json
deleted file mode 100644
index 3c60448..0000000
--- a/content/evaluations/aave/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/aave/offchain/offchain__distribution.json b/content/evaluations/aave/offchain/offchain__distribution.json
deleted file mode 100644
index 729980a..0000000
--- a/content/evaluations/aave/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface terms identify Aave Labs as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://aave.com/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/offchain/offchain__licensing.json b/content/evaluations/aave/offchain/offchain__licensing.json
deleted file mode 100644
index 5cae96f..0000000
--- a/content/evaluations/aave/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/content/evaluations/aave/offchain/offchain__trademark.json b/content/evaluations/aave/offchain/offchain__trademark.json
deleted file mode 100644
index 46ea782..0000000
--- a/content/evaluations/aave/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Trademark filing",
- "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/_metric.json b/content/evaluations/aave/onchain-ctrl/_metric.json
deleted file mode 100644
index af0a600..0000000
--- a/content/evaluations/aave/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 4a5906e..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "status": "positive",
- "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
- "evidence": [
- {
- "name": "Core",
- "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
- "urls": [
- {
- "name": "Core Protocol Role addresses",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
- "type": "github"
- },
- {
- "name": "Core Protocol Roles in ACLManager",
- "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
- "type": "explorer"
- },
- {
- "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
- "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
- "type": "explorer"
- },
- {
- "name": "POOL_ADMIN_ROLE: Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Delegated Steward Roles",
- "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
- "urls": [
- {
- "name": "Stewards (docs)",
- "url": "https://aave.com/help/governance/aave-community",
- "type": "docs"
- },
- {
- "name": "Stewards (addresses)",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Protocol Emergency Guardian",
- "summary": "A separate multisig that executes limited emergency operations for the protocol.",
- "urls": [
- {
- "name": "Protocol Emergency Guardian",
- "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
- "type": "docs"
- },
- {
- "name": "Detailed protocol permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 7ca7f0a..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token's implementation code",
- "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index e0d0466..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://aave.com/docs/ecosystem/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 27b3b55..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "Holders control implementation upgrades for all v3 market deployments.",
- "evidence": [
- {
- "name": "Upgrade Documentation",
- "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
- "urls": [
- {
- "name": "Upgradability per contract",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Ownership Chain",
- "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
- "urls": [
- {
- "name": "Pool",
- "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
- "type": "explorer"
- },
- {
- "name": "Governance",
- "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index a065c83..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "positive",
- "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
- "evidence": [
- {
- "name": "Governance Emergency Guardian",
- "urls": [
- {
- "name": "Onchain address",
- "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Detailed Governance Permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 32d8315..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 1182c67..0000000
--- a/content/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "The AAVE token is upgradeable but controlled by token holders.",
- "evidence": [
- {
- "name": "Ownership Chain",
- "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
- "urls": [
- {
- "name": "AAVE Proxy",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "ProxyAdmin",
- "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/val-accrual/_metric.json b/content/evaluations/aave/val-accrual/_metric.json
deleted file mode 100644
index d5958bb..0000000
--- a/content/evaluations/aave/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__active.json b/content/evaluations/aave/val-accrual/val-accrual__active.json
deleted file mode 100644
index 497f899..0000000
--- a/content/evaluations/aave/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Safety Module - Incentives",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
- "type": "docs"
- },
- {
- "name": "Umbrella Transition",
- "url": "https://aave.com/help/umbrella/stake",
- "type": "docs"
- },
- {
- "name": "Umbrella Activation Proposal",
- "url": "https://vote.onaave.com/proposal/?proposalId=320",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__mechanism.json b/content/evaluations/aave/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index a0753b1..0000000
--- a/content/evaluations/aave/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
- "evidence": [
- {
- "name": "ACL Control",
- "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
- "urls": [
- {
- "name": "POOL_ADMIN role",
- "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
- "type": "docs"
- },
- {
- "name": "ACLManager",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__offchain.json b/content/evaluations/aave/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 7d7ee44..0000000
--- a/content/evaluations/aave/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/content/evaluations/aave/val-accrual/val-accrual__treasury.json b/content/evaluations/aave/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index cb89d8e..0000000
--- a/content/evaluations/aave/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "Token holders direct treasury via governance.",
- "urls": [
- {
- "name": "Treasury docs",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Fee Sources",
- "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
- "urls": [
- {
- "name": "mintToTreasury (PoolLogic)",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
- "type": "github"
- },
- {
- "name": "Flashloan premium",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
- "type": "github"
- },
- {
- "name": "Liquidation fee",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/verifiability/_metric.json b/content/evaluations/aave/verifiability/_metric.json
deleted file mode 100644
index 6bfa4a9..0000000
--- a/content/evaluations/aave/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/aave/verifiability/verifiability__protocol-source.json b/content/evaluations/aave/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 92845b9..0000000
--- a/content/evaluations/aave/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aave/verifiability/verifiability__token-source.json b/content/evaluations/aave/verifiability/verifiability__token-source.json
deleted file mode 100644
index 5f8b629..0000000
--- a/content/evaluations/aave/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/distribution/_metric.json b/content/evaluations/aero/distribution/_metric.json
deleted file mode 100644
index 5ca27bd..0000000
--- a/content/evaluations/aero/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/aero/distribution/distribution__concentration.json b/content/evaluations/aero/distribution/distribution__concentration.json
deleted file mode 100644
index dad8ff0..0000000
--- a/content/evaluations/aero/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "evidence": []
-}
diff --git a/content/evaluations/aero/distribution/distribution__supply-schedule.json b/content/evaluations/aero/distribution/distribution__supply-schedule.json
deleted file mode 100644
index ccc8eba..0000000
--- a/content/evaluations/aero/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
- "evidence": []
-}
diff --git a/content/evaluations/aero/offchain/_metric.json b/content/evaluations/aero/offchain/_metric.json
deleted file mode 100644
index e86b6c4..0000000
--- a/content/evaluations/aero/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/aero/offchain/offchain__distribution.json b/content/evaluations/aero/offchain/offchain__distribution.json
deleted file mode 100644
index bc7fd01..0000000
--- a/content/evaluations/aero/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Legal",
- "url": "https://aero.drome.eth.link/legal",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/offchain/offchain__licensing.json b/content/evaluations/aero/offchain/offchain__licensing.json
deleted file mode 100644
index e33118a..0000000
--- a/content/evaluations/aero/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/content/evaluations/aero/offchain/offchain__trademark.json b/content/evaluations/aero/offchain/offchain__trademark.json
deleted file mode 100644
index af8ead8..0000000
--- a/content/evaluations/aero/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "USPTO Report",
- "url": "https://uspto.report/TM/99083103",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/_metric.json b/content/evaluations/aero/onchain-ctrl/_metric.json
deleted file mode 100644
index 2c8fa4d..0000000
--- a/content/evaluations/aero/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index f854e83..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "status": "warning",
- "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
- "evidence": [
- {
- "name": "Fee Manager Role",
- "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
- "urls": [
- {
- "name": "Safe (Fee Manager)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-SlipStream Fees",
- "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
- "urls": [
- {
- "name": "PoolFactory: FeeManager",
- "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "SlipStream Fees",
- "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
- "urls": [
- {
- "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
- "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
- "type": "explorer"
- },
- {
- "name": "SwapFeeModule: setCustomFee",
- "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index de6f75c..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
- "evidence": [
- {
- "name": "Team Rate",
- "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
- "urls": [
- {
- "name": "Safe (Team)",
- "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
- "type": "explorer"
- },
- {
- "name": "Team Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
- "type": "github"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
- "urls": [
- {
- "name": "Governor (Safe)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
- "type": "explorer"
- },
- {
- "name": "Emission Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index c6dac94..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
- "evidence": [
- {
- "name": "Voting System",
- "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "VotingEscrow",
- "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
- "type": "explorer"
- },
- {
- "name": "Voter",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Council",
- "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
- "urls": [
- {
- "name": "EmergencyCouncil",
- "url": "https://aerodrome.limited/pages/security.html",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 3e17d2e..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contract Addresses",
- "url": "https://aerodrome.finance/security",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 2c27da6..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
- "evidence": [
- {
- "name": "Emergency Council",
- "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
- "urls": [
- {
- "name": "Voter: emergencyCouncil",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
- "type": "explorer"
- },
- {
- "name": "EmergencyCouncil",
- "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 0dfcfda..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "status": "positive",
- "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
- "evidence": [
- {
- "name": "Minter Contract",
- "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
- "urls": [
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
- "urls": [
- {
- "name": "Minter Emission Increase (Epochs 1-14)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
- "type": "github"
- },
- {
- "name": "Minter Emission Decay",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
- "type": "github"
- }
- ]
- },
- {
- "name": "Growth Emissions",
- "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
- "urls": [
- {
- "name": "Growth Emissions Formula",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
- "type": "github"
- }
- ]
- },
- {
- "name": "Team Emission Rate",
- "summary": "Currently set to 0% of total weekly emissions.",
- "urls": [
- {
- "name": "Team Emission Rate",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index f04a477..0000000
--- a/content/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/val-accrual/_metric.json b/content/evaluations/aero/val-accrual/_metric.json
deleted file mode 100644
index 98d089b..0000000
--- a/content/evaluations/aero/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__active.json b/content/evaluations/aero/val-accrual/val-accrual__active.json
deleted file mode 100644
index 09489eb..0000000
--- a/content/evaluations/aero/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
- "evidence": [
- {
- "name": "Growth Emissions",
- "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
- "urls": [
- {
- "name": "Growth Transfer to RewardDistributor",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
- "type": "github"
- },
- {
- "name": "RewardsDistributor Claim",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
- "type": "github"
- }
- ]
- },
- {
- "name": "Non-Slipstream Trading Fees",
- "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
- "urls": [
- {
- "name": "Gauge Deposit Logic",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
- "type": "github"
- },
- {
- "name": "Swap Fee Accrued",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
- "type": "github"
- },
- {
- "name": "Voter calling Gauge to claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed by Gauge on PoolFees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
- "type": "github"
- }
- ]
- },
- {
- "name": "Slipstream Trading Fees",
- "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
- "urls": [
- {
- "name": "Fees Split",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
- "type": "github"
- },
- {
- "name": "Gauge Fees calculated separately",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
- "type": "github"
- },
- {
- "name": "Non Staked LP Fees collected",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
- "type": "github"
- },
- {
- "name": "Gauge Fees to feesVotingReward",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
- "type": "github"
- },
- {
- "name": "veAERO voters claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__mechanism.json b/content/evaluations/aero/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 463eee0..0000000
--- a/content/evaluations/aero/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
- "evidence": [
- {
- "name": "Locking Control",
- "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
- "urls": [
- {
- "name": "VotingEscrow create_lock",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
- "urls": [
- {
- "name": "Voter vote function",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
- "type": "github"
- },
- {
- "name": "Gauge getReward",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__offchain.json b/content/evaluations/aero/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index ee52be6..0000000
--- a/content/evaluations/aero/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
- "evidence": []
-}
diff --git a/content/evaluations/aero/val-accrual/val-accrual__treasury.json b/content/evaluations/aero/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 3c85ba0..0000000
--- a/content/evaluations/aero/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
- "evidence": []
-}
diff --git a/content/evaluations/aero/verifiability/_metric.json b/content/evaluations/aero/verifiability/_metric.json
deleted file mode 100644
index 41079e6..0000000
--- a/content/evaluations/aero/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/aero/verifiability/verifiability__protocol-source.json b/content/evaluations/aero/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 13be4d3..0000000
--- a/content/evaluations/aero/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contracts (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts",
- "type": "github"
- },
- {
- "name": "Aerodrome Slipstream (GitHub)",
- "url": "https://github.com/aerodrome-finance/slipstream",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/aero/verifiability/verifiability__token-source.json b/content/evaluations/aero/verifiability/verifiability__token-source.json
deleted file mode 100644
index a7da64f..0000000
--- a/content/evaluations/aero/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token (Basescan)",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Aero.sol Source (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/distribution/_metric.json b/content/evaluations/crv/distribution/_metric.json
deleted file mode 100644
index 40ad32e..0000000
--- a/content/evaluations/crv/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/crv/distribution/distribution__concentration.json b/content/evaluations/crv/distribution/distribution__concentration.json
deleted file mode 100644
index b5fa2a4..0000000
--- a/content/evaluations/crv/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
- "evidence": []
-}
diff --git a/content/evaluations/crv/distribution/distribution__supply-schedule.json b/content/evaluations/crv/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 5f677ee..0000000
--- a/content/evaluations/crv/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/offchain/_metric.json b/content/evaluations/crv/offchain/_metric.json
deleted file mode 100644
index 74fb5a8..0000000
--- a/content/evaluations/crv/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/crv/offchain/offchain__distribution.json b/content/evaluations/crv/offchain/offchain__distribution.json
deleted file mode 100644
index 7a6be45..0000000
--- a/content/evaluations/crv/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve Legal",
- "url": "https://www.curve.finance/dex/ethereum/legal",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/offchain/offchain__licensing.json b/content/evaluations/crv/offchain/offchain__licensing.json
deleted file mode 100644
index a17a25c..0000000
--- a/content/evaluations/crv/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/content/evaluations/crv/offchain/offchain__trademark.json b/content/evaluations/crv/offchain/offchain__trademark.json
deleted file mode 100644
index a7441b2..0000000
--- a/content/evaluations/crv/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Swiss Trademark Registry",
- "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/_metric.json b/content/evaluations/crv/onchain-ctrl/_metric.json
deleted file mode 100644
index 5e84784..0000000
--- a/content/evaluations/crv/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index b8d6f95..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
- "evidence": [
- {
- "name": "Add/Kill Gauge",
- "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
- "urls": [
- {
- "name": "Gauge Kill Implementation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5704953..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Standard Transfer",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
- "type": "github"
- },
- {
- "name": "ERC20CRV.vy Metadata Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 5617c7a..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aragon Voting Contract",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
- "type": "explorer"
- },
- {
- "name": "Agent Contract",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
- "type": "explorer"
- },
- {
- "name": "CRV Token: Admin is set to Agent",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 2e50f5a..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "status": "positive",
- "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
- "evidence": [
- {
- "name": "Core Contracts",
- "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
- "urls": [
- {
- "name": "CRV Token (Admin: Agent)",
- "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
- "type": "explorer"
- },
- {
- "name": "GaugeController (Admin: Agent)",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent Contract",
- "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Voting Contract",
- "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index c84b85c..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "positive",
- "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
- "evidence": [
- {
- "name": "Gauge Addition",
- "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
- "urls": [
- {
- "name": "GaugeController: admin is Agent",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Pool Factory Ownership",
- "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
- "urls": [
- {
- "name": "Curve Pool Factory: admin is OwnerProxy",
- "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index ef408a0..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
- "evidence": [
- {
- "name": "Supply Schedule",
- "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- },
- {
- "name": "ERC20CRV.vy Yearly Epoch Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Access",
- "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
- "urls": [
- {
- "name": "ERC20CRV.vy Mint Access",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
- "type": "github"
- },
- {
- "name": "Minter.vy Gauge Validation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 0f5537c..0000000
--- a/content/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Source",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/val-accrual/_metric.json b/content/evaluations/crv/val-accrual/_metric.json
deleted file mode 100644
index 6260c77..0000000
--- a/content/evaluations/crv/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__active.json b/content/evaluations/crv/val-accrual/val-accrual__active.json
deleted file mode 100644
index 66103a1..0000000
--- a/content/evaluations/crv/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "status": "positive",
- "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
- "evidence": [
- {
- "name": "CRV Emissions Rewards",
- "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
- "urls": [
- {
- "name": "working_balance reward calculation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
- "type": "github"
- }
- ]
- },
- {
- "name": "Pool Rewards in crvUSD",
- "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
- "urls": [
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Borrow Rewards in crvUSD",
- "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
- "urls": [
- {
- "name": "FeeSplitter",
- "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__mechanism.json b/content/evaluations/crv/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 5989d6d..0000000
--- a/content/evaluations/crv/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "status": "positive",
- "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
- "evidence": [
- {
- "name": "Pool Fee Control",
- "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
- "urls": [
- {
- "name": "DAI/USDC/USDT Pool: commit_new_fee",
- "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burner Attachment",
- "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
- "urls": [
- {
- "name": "StableSwapProxy: set_burner",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burn Execution",
- "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
- "urls": [
- {
- "name": "StableSwapProxy: burn",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__offchain.json b/content/evaluations/crv/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index ed5f6d9..0000000
--- a/content/evaluations/crv/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
- "evidence": []
-}
diff --git a/content/evaluations/crv/val-accrual/val-accrual__treasury.json b/content/evaluations/crv/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index a1ca859..0000000
--- a/content/evaluations/crv/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
- "evidence": [
- {
- "urls": [
- {
- "name": "veCRV Revenue Share (Docs)",
- "url": "https://docs.curve.finance/user/vecrv/revenue",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/verifiability/_metric.json b/content/evaluations/crv/verifiability/_metric.json
deleted file mode 100644
index 8a84410..0000000
--- a/content/evaluations/crv/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/crv/verifiability/verifiability__protocol-source.json b/content/evaluations/crv/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index dfa266b..0000000
--- a/content/evaluations/crv/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Curve DAO protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve DAO Contracts (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/crv/verifiability/verifiability__token-source.json b/content/evaluations/crv/verifiability/verifiability__token-source.json
deleted file mode 100644
index 88abb06..0000000
--- a/content/evaluations/crv/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Token (Etherscan)",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- },
- {
- "name": "ERC20CRV.vy Source (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/distribution/_metric.json b/content/evaluations/ena/distribution/_metric.json
deleted file mode 100644
index 99cf88c..0000000
--- a/content/evaluations/ena/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/ena/distribution/distribution__concentration.json b/content/evaluations/ena/distribution/distribution__concentration.json
deleted file mode 100644
index 6302a56..0000000
--- a/content/evaluations/ena/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
- "evidence": [
- {
- "name": "Token Allocation",
- "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
- "urls": [
- {
- "name": "Tokenomist.ai - ENA",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- },
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/distribution/distribution__supply-schedule.json b/content/evaluations/ena/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 2906392..0000000
--- a/content/evaluations/ena/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
- "evidence": [
- {
- "name": "Vesting Schedules",
- "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
- "urls": [
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- },
- {
- "name": "Tokenomist.ai - ENA Vesting",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/offchain/_metric.json b/content/evaluations/ena/offchain/_metric.json
deleted file mode 100644
index 692c514..0000000
--- a/content/evaluations/ena/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/ena/offchain/offchain__distribution.json b/content/evaluations/ena/offchain/offchain__distribution.json
deleted file mode 100644
index 09259c1..0000000
--- a/content/evaluations/ena/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/offchain/offchain__licensing.json b/content/evaluations/ena/offchain/offchain__licensing.json
deleted file mode 100644
index 5df1cf4..0000000
--- a/content/evaluations/ena/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "warning",
- "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena GitHub License",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/offchain/offchain__trademark.json b/content/evaluations/ena/offchain/offchain__trademark.json
deleted file mode 100644
index 3ea8daa..0000000
--- a/content/evaluations/ena/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/_metric.json b/content/evaluations/ena/onchain-ctrl/_metric.json
deleted file mode 100644
index aa732f2..0000000
--- a/content/evaluations/ena/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 85c8a35..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
- "evidence": [
- {
- "name": "Privileged Roles (per Multisig Matrix)",
- "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Gatekeeper Powers",
- "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
- "urls": [
- {
- "name": "`disableMintRedeem()` (line 278)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
- "type": "github"
- },
- {
- "name": "`removeMinterRole()` (line 339)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
- "type": "github"
- },
- {
- "name": "`removeRedeemerRole()` (line 345)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index ea421fc..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "warning",
- "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
- "evidence": [
- {
- "name": "sENA/sUSDe Blacklist Capabilities",
- "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
- "urls": [
- {
- "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
- "type": "github"
- },
- {
- "name": "`redistributeLockedAmount()` (lines 106-127)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
- "type": "github"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index f3a9970..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "warning",
- "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
- "evidence": [
- {
- "name": "Snapshot Governance",
- "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
- "urls": [
- {
- "name": "Snapshot Space",
- "url": "https://snapshot.org/#/ethenagovernance.eth",
- "type": "docs"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Multisig Execution",
- "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
- "urls": [
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 967e44f..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "status": "warning",
- "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
- "evidence": [
- {
- "name": "Non-Upgradeable Contracts",
- "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Upgradeable Contracts (sENA and rsENA)",
- "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
- "urls": [
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "sENA Implementation",
- "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
- "type": "explorer"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Implementation",
- "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index b840de7..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "status": "warning",
- "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
- "evidence": [
- {
- "name": "Multisig Control Matrix",
- "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- },
- {
- "name": "Hot Swap Multisig",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "Trading Operations Multisig",
- "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
- "type": "explorer"
- },
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "EOA Control Points",
- "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
- "urls": [
- {
- "name": "StakingRewardsDistributor Operator (EOA)",
- "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
- "type": "explorer"
- },
- {
- "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index ff12bcc..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
- "evidence": [
- {
- "name": "Mint Function",
- "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
- "urls": [
- {
- "name": "ENA.sol `mint()` function (lines 42-49)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
- "type": "github"
- },
- {
- "name": "ENA Token totalSupply",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 6f0354c..0000000
--- a/content/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
- "evidence": [
- {
- "name": "ENA Non-Upgradeability Verification",
- "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
- "urls": [
- {
- "name": "ENA.sol Source",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/val-accrual/_metric.json b/content/evaluations/ena/val-accrual/_metric.json
deleted file mode 100644
index 12be505..0000000
--- a/content/evaluations/ena/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__active.json b/content/evaluations/ena/val-accrual/val-accrual__active.json
deleted file mode 100644
index 35bf37b..0000000
--- a/content/evaluations/ena/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "status": "warning",
- "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
- "evidence": [
- {
- "name": "Fee Switch Status",
- "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "USDe Token (verify totalSupply)",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
- "type": "explorer"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Ethena Network Airdrops",
- "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
- "urls": [
- {
- "name": "Ethena Network Documentation",
- "url": "https://docs.ethena.fi/ethena-network",
- "type": "docs"
- }
- ]
- },
- {
- "name": "rsENA (Restaked ENA via Symbiotic)",
- "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
- "urls": [
- {
- "name": "rsENA Contract",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
- "type": "explorer"
- },
- {
- "name": "ENA Staking Documentation",
- "url": "https://docs.ethena.fi/ena",
- "type": "docs"
- },
- {
- "name": "Mellow Finance rsENA Vault",
- "url": "https://app.mellow.finance/vaults/ethereum-rsena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__mechanism.json b/content/evaluations/ena/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 1e775e7..0000000
--- a/content/evaluations/ena/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "warning",
- "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
- "evidence": [
- {
- "name": "ENA Value Accrual Controls",
- "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
- "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Tokenholder Cannot Force Activation",
- "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__offchain.json b/content/evaluations/ena/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index dd3c133..0000000
--- a/content/evaluations/ena/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "warning",
- "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
- "evidence": [
- {
- "name": "USDe Yield Sources",
- "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
- "urls": [
- {
- "name": "Coin Metrics Analysis (USDe Yield Sources)",
- "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Yield Distribution Flow",
- "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
- "urls": [
- {
- "name": "`transferInRewards()` (lines 88-94)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
- "type": "github"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/val-accrual/val-accrual__treasury.json b/content/evaluations/ena/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index cec61a8..0000000
--- a/content/evaluations/ena/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
- "evidence": [
- {
- "name": "Revenue Flow",
- "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
- "urls": [
- {
- "name": "Key Addresses Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-addresses",
- "type": "docs"
- },
- {
- "name": "Hot Swap Multisig (revenue receiver)",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Reserve Fund (Negative Funding Backup)",
- "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
- "urls": [
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/verifiability/_metric.json b/content/evaluations/ena/verifiability/_metric.json
deleted file mode 100644
index 9ae768f..0000000
--- a/content/evaluations/ena/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/ena/verifiability/verifiability__protocol-source.json b/content/evaluations/ena/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index f2d5e2d..0000000
--- a/content/evaluations/ena/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
- "evidence": [
- {
- "name": "Verified Contracts",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "GitHub Repository",
- "urls": [
- {
- "name": "Ethena Public Assets (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets",
- "type": "github"
- }
- ]
- },
- {
- "name": "Audits",
- "urls": [
- {
- "name": "Code4rena 2023 Audit",
- "url": "https://github.com/code-423n4/2023-10-ethena",
- "type": "github"
- },
- {
- "name": "Code4rena 2024 Audit",
- "url": "https://github.com/code-423n4/2024-11-ethena-labs",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ena/verifiability/verifiability__token-source.json b/content/evaluations/ena/verifiability/verifiability__token-source.json
deleted file mode 100644
index 832ff34..0000000
--- a/content/evaluations/ena/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "ENA.sol Source (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/distribution/_metric.json b/content/evaluations/ethfi/distribution/_metric.json
deleted file mode 100644
index e97bf51..0000000
--- a/content/evaluations/ethfi/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/ethfi/distribution/distribution__concentration.json b/content/evaluations/ethfi/distribution/distribution__concentration.json
deleted file mode 100644
index a95862d..0000000
--- a/content/evaluations/ethfi/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
- "evidence": [
- {
- "name": "Token Allocation",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/distribution/distribution__supply-schedule.json b/content/evaluations/ethfi/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 2fbf530..0000000
--- a/content/evaluations/ethfi/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "warning",
- "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "DefiLlama Unlocks",
- "url": "https://defillama.com/unlocks/ether.fi",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/offchain/_metric.json b/content/evaluations/ethfi/offchain/_metric.json
deleted file mode 100644
index e2152cc..0000000
--- a/content/evaluations/ethfi/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/ethfi/offchain/offchain__distribution.json b/content/evaluations/ethfi/offchain/offchain__distribution.json
deleted file mode 100644
index 45c898e..0000000
--- a/content/evaluations/ethfi/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
- "evidence": [
- {
- "name": "Legal Entity",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/offchain/offchain__licensing.json b/content/evaluations/ethfi/offchain/offchain__licensing.json
deleted file mode 100644
index bfa11ce..0000000
--- a/content/evaluations/ethfi/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "warning",
- "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
- "evidence": [
- {
- "name": "License",
- "urls": [
- {
- "name": "GitHub Repository",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Terms of Use (Non-Contract IP)",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/offchain/offchain__trademark.json b/content/evaluations/ethfi/offchain/offchain__trademark.json
deleted file mode 100644
index c573eef..0000000
--- a/content/evaluations/ethfi/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
- "evidence": [
- {
- "name": "Trademark Ownership",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/_metric.json b/content/evaluations/ethfi/onchain-ctrl/_metric.json
deleted file mode 100644
index ca55eb6..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 5b3acc3..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
- "evidence": [
- {
- "name": "Pause Authority",
- "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
- "urls": [
- {
- "name": "EtherFiAdmin Pause Function",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 2c44b78..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "warning",
- "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
- "evidence": [
- {
- "name": "Token Analysis",
- "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- },
- {
- "name": "Arbitrum ETHFI (Upgradeable)",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI (Upgradeable)",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 472575d..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "at_risk",
- "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "evidence": [
- {
- "name": "Governance Structure",
- "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "urls": [
- {
- "name": "Governance Info",
- "url": "https://vote.ether.fi/info",
- "type": "docs"
- },
- {
- "name": "Governance Resources",
- "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
- "type": "docs"
- },
- {
- "name": "Governance Roadmap",
- "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index a68cded..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "warning",
- "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
- "urls": [
- {
- "name": "RoleRegistry Upgrade Check",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
- "type": "github"
- },
- {
- "name": "LiquidityPool Upgrade Authorization",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
- "type": "github"
- }
- ]
- },
- {
- "name": "RoleRegistry Owner",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 0936aa7..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
- "evidence": [
- {
- "name": "RoleRegistry Owner (Upgrade Timelock)",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock (72h)",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Two-Timelock System",
- "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
- "urls": [
- {
- "name": "Upgrade Admin (4-of-7)",
- "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
- "type": "explorer"
- },
- {
- "name": "Operating Timelock (8h)",
- "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
- "type": "explorer"
- },
- {
- "name": "Operating Admin (3-of-5)",
- "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 98f9307..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
- "evidence": [
- {
- "name": "Fixed Supply",
- "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 4024ae0..0000000
--- a/content/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
- "evidence": [
- {
- "name": "Mainnet Token (Not Upgradeable)",
- "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "L2 Tokens (Upgradeable, No Timelock)",
- "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
- "urls": [
- {
- "name": "Arbitrum ETHFI",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Arbitrum Admin (3-of-6)",
- "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- },
- {
- "name": "Base Admin (3-of-6)",
- "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/val-accrual/_metric.json b/content/evaluations/ethfi/val-accrual/_metric.json
deleted file mode 100644
index aad827f..0000000
--- a/content/evaluations/ethfi/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__active.json b/content/evaluations/ethfi/val-accrual/val-accrual__active.json
deleted file mode 100644
index 84671dc..0000000
--- a/content/evaluations/ethfi/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "positive",
- "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
- "evidence": [
- {
- "name": "Buyback Program",
- "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
- "urls": [
- {
- "name": "ETHFI Buyback Program",
- "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
- "type": "docs"
- },
- {
- "name": "Buyback History (Dune)",
- "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
- "type": "docs"
- },
- {
- "name": "sETHFI Staking",
- "url": "https://www.ether.fi/app/ethfi",
- "type": "docs"
- },
- {
- "name": "Buyback Wallet (1-of-5)",
- "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json b/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 0e84742..0000000
--- a/content/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
- "evidence": [
- {
- "name": "Fee Configuration",
- "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
- "urls": [
- {
- "name": "LiquidityPool Fee Functions",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json b/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index be71a37..0000000
--- a/content/evaluations/ethfi/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json b/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 1e800d0..0000000
--- a/content/evaluations/ethfi/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/verifiability/_metric.json b/content/evaluations/ethfi/verifiability/_metric.json
deleted file mode 100644
index 14c61d2..0000000
--- a/content/evaluations/ethfi/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json b/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 17de7d2..0000000
--- a/content/evaluations/ethfi/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
- "evidence": [
- {
- "name": "Protocol Source & Audits",
- "urls": [
- {
- "name": "etherfi-protocol/smart-contracts",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ethfi/verifiability/verifiability__token-source.json b/content/evaluations/ethfi/verifiability/verifiability__token-source.json
deleted file mode 100644
index 04155b4..0000000
--- a/content/evaluations/ethfi/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
- "evidence": [
- {
- "name": "Token Verification",
- "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
- "urls": [
- {
- "name": "Etherscan Verified Source",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/distribution/_metric.json b/content/evaluations/ldo/distribution/_metric.json
deleted file mode 100644
index 01ef2fb..0000000
--- a/content/evaluations/ldo/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/ldo/distribution/distribution__concentration.json b/content/evaluations/ldo/distribution/distribution__concentration.json
deleted file mode 100644
index f0ea33e..0000000
--- a/content/evaluations/ldo/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
- "evidence": []
-}
diff --git a/content/evaluations/ldo/distribution/distribution__supply-schedule.json b/content/evaluations/ldo/distribution/distribution__supply-schedule.json
deleted file mode 100644
index b781f77..0000000
--- a/content/evaluations/ldo/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
- "evidence": []
-}
diff --git a/content/evaluations/ldo/offchain/_metric.json b/content/evaluations/ldo/offchain/_metric.json
deleted file mode 100644
index 4da96c8..0000000
--- a/content/evaluations/ldo/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/ldo/offchain/offchain__distribution.json b/content/evaluations/ldo/offchain/offchain__distribution.json
deleted file mode 100644
index 0ba589a..0000000
--- a/content/evaluations/ldo/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/offchain/offchain__licensing.json b/content/evaluations/ldo/offchain/offchain__licensing.json
deleted file mode 100644
index 0ba589a..0000000
--- a/content/evaluations/ldo/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/offchain/offchain__trademark.json b/content/evaluations/ldo/offchain/offchain__trademark.json
deleted file mode 100644
index ebae64a..0000000
--- a/content/evaluations/ldo/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UK IPO Trademark Journal",
- "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
- "type": "docs"
- },
- {
- "name": "Lido Logo",
- "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/_metric.json b/content/evaluations/ldo/onchain-ctrl/_metric.json
deleted file mode 100644
index 5a79c2d..0000000
--- a/content/evaluations/ldo/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 30793e1..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
- "evidence": [
- {
- "name": "Guardian Role",
- "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
- "urls": [
- {
- "name": "DepositSecurityModule",
- "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
- "type": "explorer"
- },
- {
- "name": "Lido.sol deposit logic",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
- "type": "github"
- },
- {
- "name": "Guardians use automated software",
- "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Guardian Accountability",
- "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
- "urls": [
- {
- "name": "Guardian Committee Membership",
- "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
- "type": "docs"
- },
- {
- "name": "Guardians cannot control stake allocation",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index adf749d..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
- "evidence": [
- {
- "name": "Burn Capability",
- "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
- "urls": [
- {
- "name": "MiniMeToken.destroyTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
- "type": "github"
- },
- {
- "name": "Aragon ACL",
- "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Transfer Control",
- "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
- "urls": [
- {
- "name": "MiniMeToken.enableTransfers",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 3b27084..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "status": "positive",
- "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
- "evidence": [
- {
- "name": "Governance 1A",
- "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- },
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Governance 1B",
- "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Easy Track",
- "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
- "urls": [
- {
- "name": "Easy Track Interface",
- "url": "https://easytrack.lido.fi/",
- "type": "docs"
- },
- {
- "name": "Easy Track Guide",
- "url": "https://docs.lido.fi/guides/easy-track-guide",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index a3a5da8..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "positive",
- "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
- "evidence": [
- {
- "name": "Upgradeable Contracts",
- "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-upgradeable Contracts",
- "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
- "urls": [
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index deeabc7..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
- "evidence": [
- {
- "name": "Voting",
- "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent",
- "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "TokenManager",
- "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "StakingRouter",
- "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index a476ae1..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
- "evidence": [
- {
- "name": "Minting Path",
- "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
- "urls": [
- {
- "name": "MiniMeToken.generateTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 2f65c1e..0000000
--- a/content/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
- "evidence": [
- {
- "name": "Token Contract",
- "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
- "urls": [
- {
- "name": "LDO Token",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Controller Upgrade Path",
- "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/val-accrual/_metric.json b/content/evaluations/ldo/val-accrual/_metric.json
deleted file mode 100644
index 15c6eb7..0000000
--- a/content/evaluations/ldo/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__active.json b/content/evaluations/ldo/val-accrual/val-accrual__active.json
deleted file mode 100644
index 558e4a9..0000000
--- a/content/evaluations/ldo/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "status": "positive",
- "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
- "evidence": [
- {
- "name": "Treasury Fee Flow",
- "urls": [
- {
- "name": "StakingRouter (read contract)",
- "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
- "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
- "type": "github"
- }
- ]
- },
- {
- "name": "Buyback Program",
- "urls": [
- {
- "name": "stETH/LDO Buyback Proposal",
- "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
- "type": "docs"
- },
- {
- "name": "stETH/LDO Buyback Snapshot Vote",
- "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
- "type": "vote"
- },
- {
- "name": "NEST",
- "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
- "type": "docs"
- },
- {
- "name": "Liquid buybacks research",
- "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json b/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 0b6d587..0000000
--- a/content/evaluations/ldo/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "StakingRouter add/update",
- "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__offchain.json b/content/evaluations/ldo/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 57a1dff..0000000
--- a/content/evaluations/ldo/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
- "evidence": []
-}
diff --git a/content/evaluations/ldo/val-accrual/val-accrual__treasury.json b/content/evaluations/ldo/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index f1662c6..0000000
--- a/content/evaluations/ldo/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "positive",
- "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
- "urls": [
- {
- "name": "Agent (Treasury)",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/verifiability/_metric.json b/content/evaluations/ldo/verifiability/_metric.json
deleted file mode 100644
index 3fa336c..0000000
--- a/content/evaluations/ldo/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/ldo/verifiability/verifiability__protocol-source.json b/content/evaluations/ldo/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index cefc201..0000000
--- a/content/evaluations/ldo/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido core protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Core Contracts (GitHub)",
- "url": "https://github.com/lidofinance/core",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ldo/verifiability/verifiability__token-source.json b/content/evaluations/ldo/verifiability/verifiability__token-source.json
deleted file mode 100644
index 713a79f..0000000
--- a/content/evaluations/ldo/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LDO Token (Etherscan)",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- },
- {
- "name": "MiniMeToken Source (GitHub)",
- "url": "https://github.com/aragon/minime",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/distribution/_metric.json b/content/evaluations/lqty/distribution/_metric.json
deleted file mode 100644
index 18de867..0000000
--- a/content/evaluations/lqty/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/lqty/distribution/distribution__concentration.json b/content/evaluations/lqty/distribution/distribution__concentration.json
deleted file mode 100644
index 110aef5..0000000
--- a/content/evaluations/lqty/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
-}
diff --git a/content/evaluations/lqty/distribution/distribution__supply-schedule.json b/content/evaluations/lqty/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 836aa8d..0000000
--- a/content/evaluations/lqty/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LockupContractFactory (Etherscan)",
- "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
- "type": "explorer"
- },
- {
- "name": "CommunityIssuance (Etherscan)",
- "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/offchain/_metric.json b/content/evaluations/lqty/offchain/_metric.json
deleted file mode 100644
index df30ae9..0000000
--- a/content/evaluations/lqty/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/lqty/offchain/offchain__distribution.json b/content/evaluations/lqty/offchain/offchain__distribution.json
deleted file mode 100644
index e8a8be0..0000000
--- a/content/evaluations/lqty/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "warning",
- "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity Runs on Decentralized Frontends - Official Blog",
- "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
- "type": "website"
- },
- {
- "name": "Frontend Operators Page",
- "url": "https://www.liquity.org/frontend-operators",
- "type": "website"
- },
- {
- "name": "Liquity Launch Details (AG does not run frontend)",
- "url": "https://www.liquity.org/blog/liquity-launch-details",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/offchain/offchain__licensing.json b/content/evaluations/lqty/offchain/offchain__licensing.json
deleted file mode 100644
index be0df5c..0000000
--- a/content/evaluations/lqty/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "at_risk",
- "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Licensing Liquity V2 - Official Blog",
- "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
- "type": "website"
- },
- {
- "name": "Liquity V2 Core LICENSE File (GitHub)",
- "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
- "type": "github"
- },
- {
- "name": "What's New in Liquity V2 - Bankless",
- "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/offchain/offchain__trademark.json b/content/evaluations/lqty/offchain/offchain__trademark.json
deleted file mode 100644
index 877957e..0000000
--- a/content/evaluations/lqty/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "at_risk",
- "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity AG - Crunchbase Company Profile",
- "url": "https://www.crunchbase.com/organization/liquity-1d3e",
- "type": "website"
- },
- {
- "name": "Liquity - Tracxn Company Profile",
- "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
- "type": "website"
- },
- {
- "name": "Team Page - Liquity.org",
- "url": "https://www.liquity.org/team",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/_metric.json b/content/evaluations/lqty/onchain-ctrl/_metric.json
deleted file mode 100644
index 1893248..0000000
--- a/content/evaluations/lqty/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 8bca964..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "Access Gating",
- "status": "positive",
- "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index f76566d..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY token's implementation code",
- "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index ff7b2b4..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index c6e33ce..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 02906f9..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index eb35281..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 9495e41..0000000
--- a/content/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token Source",
- "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/val-accrual/_metric.json b/content/evaluations/lqty/val-accrual/_metric.json
deleted file mode 100644
index 9ad32dc..0000000
--- a/content/evaluations/lqty/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__active.json b/content/evaluations/lqty/val-accrual/val-accrual__active.json
deleted file mode 100644
index f67d587..0000000
--- a/content/evaluations/lqty/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "status": "positive",
- "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
- "type": "github"
- },
- {
- "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
- "type": "github"
- },
- {
- "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
- "url": "https://docs.liquity.org/v2-faq/lqty-staking",
- "type": "docs"
- },
- {
- "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
- "type": "github"
- },
- {
- "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
- "type": "github"
- },
- {
- "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json b/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index c9c1666..0000000
--- a/content/evaluations/lqty/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__offchain.json b/content/evaluations/lqty/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 54f5685..0000000
--- a/content/evaluations/lqty/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/content/evaluations/lqty/val-accrual/val-accrual__treasury.json b/content/evaluations/lqty/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 40dc2ab..0000000
--- a/content/evaluations/lqty/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Docs",
- "url": "https://www.liquity.org/blog/liquity-v2-is-live",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/verifiability/_metric.json b/content/evaluations/lqty/verifiability/_metric.json
deleted file mode 100644
index 53b7a50..0000000
--- a/content/evaluations/lqty/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/lqty/verifiability/verifiability__protocol-source.json b/content/evaluations/lqty/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 0170fd6..0000000
--- a/content/evaluations/lqty/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Liquity protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Core (GitHub)",
- "url": "https://github.com/liquity/bold",
- "type": "github"
- },
- {
- "name": "Liquity V2 Governance (GitHub)",
- "url": "https://github.com/liquity/V2-gov",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/lqty/verifiability/verifiability__token-source.json b/content/evaluations/lqty/verifiability/verifiability__token-source.json
deleted file mode 100644
index c4daa88..0000000
--- a/content/evaluations/lqty/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token (Etherscan)",
- "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
- "type": "explorer"
- },
- {
- "name": "LQTYToken.sol Source (GitHub)",
- "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/distribution/_metric.json b/content/evaluations/ondo/distribution/_metric.json
deleted file mode 100644
index 6ff8f37..0000000
--- a/content/evaluations/ondo/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/ondo/distribution/distribution__concentration.json b/content/evaluations/ondo/distribution/distribution__concentration.json
deleted file mode 100644
index b811b98..0000000
--- a/content/evaluations/ondo/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "at_risk",
- "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
- "evidence": [
- {
- "name": "Team Holdings",
- "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
- "urls": [
- {
- "name": "Team Multisig holdings",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/distribution/distribution__supply-schedule.json b/content/evaluations/ondo/distribution/distribution__supply-schedule.json
deleted file mode 100644
index dc07df0..0000000
--- a/content/evaluations/ondo/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
- "evidence": [
- {
- "name": "Documented Schedule",
- "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
- "urls": [
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- },
- {
- "name": "CoinList - ONDO Community Sale",
- "url": "https://coinlist.co/ondo",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/offchain/_metric.json b/content/evaluations/ondo/offchain/_metric.json
deleted file mode 100644
index cdc655c..0000000
--- a/content/evaluations/ondo/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/ondo/offchain/offchain__distribution.json b/content/evaluations/ondo/offchain/offchain__distribution.json
deleted file mode 100644
index e5575dc..0000000
--- a/content/evaluations/ondo/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Interface Services",
- "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/offchain/offchain__licensing.json b/content/evaluations/ondo/offchain/offchain__licensing.json
deleted file mode 100644
index f3632d4..0000000
--- a/content/evaluations/ondo/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
- "evidence": [
- {
- "name": "BUSL-1.1 Source Headers",
- "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
- "urls": [
- {
- "name": "USDY source SPDX header",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
- "type": "github"
- },
- {
- "name": "rOUSG source SPDX header",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
- "type": "github"
- },
- {
- "name": "BUSL-1.1 license text",
- "url": "https://spdx.org/licenses/BUSL-1.1.html",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/offchain/offchain__trademark.json b/content/evaluations/ondo/offchain/offchain__trademark.json
deleted file mode 100644
index d53d771..0000000
--- a/content/evaluations/ondo/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Proprietary Rights",
- "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/_metric.json b/content/evaluations/ondo/onchain-ctrl/_metric.json
deleted file mode 100644
index c2dfc4d..0000000
--- a/content/evaluations/ondo/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 3a6f103..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
- "evidence": [
- {
- "name": "OUSG Transfer Restrictions",
- "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
- "urls": [
- {
- "name": "OUSG Contract (KYC enforcement)",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "OUSG KYC check (source)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
- "type": "github"
- },
- {
- "name": "KYCRegistry",
- "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "USDY Transfer Restrictions",
- "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
- "urls": [
- {
- "name": "USDY restrictions (source)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
- "type": "github"
- },
- {
- "name": "USDY Contract",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index a5dc7f1..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
- "evidence": [
- {
- "name": "No Censorship Capability",
- "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Source code (ondo-v1)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 4c5b928..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
- "evidence": [
- {
- "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
- "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (OUSG admin)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin owner",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 1cee348..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
- "evidence": [
- {
- "name": "OUSG/USDY (Team-Controlled)",
- "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
- "urls": [
- {
- "name": "OUSG Proxy",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "OUSG ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY Proxy",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Polygon OUSG ProxyAdmin Owner",
- "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
- "type": "explorer"
- },
- {
- "name": "Mantle USDY ProxyAdmin Owner",
- "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
- "type": "explorer"
- },
- {
- "name": "Arbitrum USDY ProxyAdmin Owner",
- "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Global Markets (Team-Controlled via TimelockController)",
- "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
- "urls": [
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 8e32210..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
- "evidence": [
- {
- "name": "Team-Controlled Roles (ONDO Token)",
- "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
- "urls": [
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (OUSG/USDY)",
- "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "rOUSG",
- "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "rUSDY",
- "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (Global Markets)",
- "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- },
- {
- "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
- "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
- "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (EOA)",
- "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
- "type": "explorer"
- },
- {
- "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
- "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index fb8a3ba..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
- "evidence": [
- {
- "name": "Current Supply",
- "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
- "urls": [
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Mint Function Exists",
- "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
- "urls": [
- {
- "name": "ONDO Token (verified source)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (MINTER_ROLE holder)",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 578d308..0000000
--- a/content/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
- "evidence": [
- {
- "name": "ONDO Token Roles",
- "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Contract Source Note",
- "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
- "urls": [
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/val-accrual/_metric.json b/content/evaluations/ondo/val-accrual/_metric.json
deleted file mode 100644
index f11d02f..0000000
--- a/content/evaluations/ondo/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__active.json b/content/evaluations/ondo/val-accrual/val-accrual__active.json
deleted file mode 100644
index 7939a86..0000000
--- a/content/evaluations/ondo/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "at_risk",
- "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
- "evidence": [
- {
- "name": "Product Economics vs ONDO Holder Accrual",
- "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json b/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index ee2c0ab..0000000
--- a/content/evaluations/ondo/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
- "evidence": [
- {
- "name": "OUSG/USDY Price Oracles (Company-Controlled)",
- "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
- "urls": [
- {
- "name": "OUSG Oracle",
- "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
- "type": "explorer"
- },
- {
- "name": "USDY Oracle",
- "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
- "type": "explorer"
- },
- {
- "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
- "type": "github"
- },
- {
- "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets (Company-Controlled via TimelockController)",
- "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__offchain.json b/content/evaluations/ondo/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 1c5bd2f..0000000
--- a/content/evaluations/ondo/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
- "tags": [
- "Reference"
- ],
- "evidence": [
- {
- "name": "Ondo Product Economics",
- "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "USDY Issuer / Ondo Finance Relationship",
- "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Global Markets Revenue",
- "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
- "urls": [
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/val-accrual/val-accrual__treasury.json b/content/evaluations/ondo/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 4157d3a..0000000
--- a/content/evaluations/ondo/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "at_risk",
- "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
- "evidence": [
- {
- "name": "No Treasury Identified",
- "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
- "urls": [
- {
- "name": "Ondo DAO Proposals",
- "url": "https://www.tally.xyz/gov/ondo-dao",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/verifiability/_metric.json b/content/evaluations/ondo/verifiability/_metric.json
deleted file mode 100644
index 9d49936..0000000
--- a/content/evaluations/ondo/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/ondo/verifiability/verifiability__protocol-source.json b/content/evaluations/ondo/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index dc042a9..0000000
--- a/content/evaluations/ondo/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "status": "positive",
- "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
- "evidence": [
- {
- "name": "OUSG/USDY",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "USDY GitHub",
- "url": "https://github.com/ondoprotocol/usdy",
- "type": "github"
- },
- {
- "name": "Audit code (Code4rena)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "USDonManager",
- "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/ondo/verifiability/verifiability__token-source.json b/content/evaluations/ondo/verifiability/verifiability__token-source.json
deleted file mode 100644
index 69b23f7..0000000
--- a/content/evaluations/ondo/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ONDO Token (Etherscan verified)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/distribution/_metric.json b/content/evaluations/sky/distribution/_metric.json
deleted file mode 100644
index d46c247..0000000
--- a/content/evaluations/sky/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not been able to verify the concentration of holdings.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/sky/distribution/distribution__concentration.json b/content/evaluations/sky/distribution/distribution__concentration.json
deleted file mode 100644
index 14854bc..0000000
--- a/content/evaluations/sky/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify the concentration of holdings.",
- "evidence": []
-}
diff --git a/content/evaluations/sky/distribution/distribution__supply-schedule.json b/content/evaluations/sky/distribution/distribution__supply-schedule.json
deleted file mode 100644
index ea1ed76..0000000
--- a/content/evaluations/sky/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
- "evidence": [
- {
- "name": "Vesting Contracts",
- "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
- "urls": [
- {
- "name": "Vest Contract",
- "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/offchain/_metric.json b/content/evaluations/sky/offchain/_metric.json
deleted file mode 100644
index 5919811..0000000
--- a/content/evaluations/sky/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/sky/offchain/offchain__distribution.json b/content/evaluations/sky/offchain/offchain__distribution.json
deleted file mode 100644
index ab1dfb9..0000000
--- a/content/evaluations/sky/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
- "evidence": [
- {
- "name": "Open Source Frontends",
- "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
- "urls": [
- {
- "name": "Governance Portal Source",
- "url": "https://github.com/sky-ecosystem/governance-portal-v2",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/offchain/offchain__licensing.json b/content/evaluations/sky/offchain/offchain__licensing.json
deleted file mode 100644
index aa47403..0000000
--- a/content/evaluations/sky/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
- "evidence": [
- {
- "name": "AGPL-3.0 License",
- "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
- "urls": [
- {
- "name": "License File",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/offchain/offchain__trademark.json b/content/evaluations/sky/offchain/offchain__trademark.json
deleted file mode 100644
index 7dda59a..0000000
--- a/content/evaluations/sky/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "warning",
- "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
- "evidence": [
- {
- "name": "Skybase International Terms of Use",
- "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
- "type": "docs"
- }
- ]
- },
- {
- "name": "DAI Foundation",
- "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
- "urls": [
- {
- "name": "Foundation Website",
- "url": "https://daifoundation.org",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/_metric.json b/content/evaluations/sky/onchain-ctrl/_metric.json
deleted file mode 100644
index 17b64c3..0000000
--- a/content/evaluations/sky/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 2a8eb2b..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
- "evidence": [
- {
- "name": "Emergency Shutdown",
- "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
- "urls": [
- {
- "name": "ESM source code",
- "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
- "type": "github"
- },
- {
- "name": "ESM contract on Etherscan",
- "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "No Arbitrary Pause",
- "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
- "urls": []
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5515ba9..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
- "evidence": [
- {
- "name": "No Censorship Functions",
- "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
- "urls": [
- {
- "name": "Transfer Functions (L96-135)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 210d15f..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
- "evidence": [
- {
- "name": "Governance Workflow",
- "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
- "urls": [
- {
- "name": "Voting Contract",
- "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
- "type": "explorer"
- },
- {
- "name": "plot() delay enforcement (L111-116)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
- "type": "github"
- }
- ]
- },
- {
- "name": "Timelock Contract",
- "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
- "urls": [
- {
- "name": "Pause Proxy (Etherscan)",
- "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
- "type": "explorer"
- },
- {
- "name": "exec() function (L124-136)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index b5ad61d..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
- "evidence": [
- {
- "name": "Immutable Core",
- "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
- "urls": [
- {
- "name": "Vat source code",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
- "type": "github"
- },
- {
- "name": "SKY token source code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Stablecoins",
- "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
- "urls": [
- {
- "name": "USDS upgrade authorization",
- "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
- "type": "github"
- },
- {
- "name": "sUSDS source code",
- "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index b56bd54..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
- "evidence": [
- {
- "name": "Core Contracts Controlled by Governance",
- "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
- "urls": [
- {
- "name": "Vat wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
- "type": "explorer"
- },
- {
- "name": "Vow wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- },
- {
- "name": "SKY wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Controls",
- "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
- "urls": [
- {
- "name": "Mom authority pattern (source)",
- "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
- "type": "github"
- },
- {
- "name": "OSM_MOM — verify authority()",
- "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 2655fba..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
- "evidence": [
- {
- "name": "Minting Restricted to Governance",
- "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
- "urls": [
- {
- "name": "mint() function (L146-154)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
- "type": "github"
- }
- ]
- },
- {
- "name": "MKR Conversion",
- "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
- "urls": [
- {
- "name": "rate() returns 24000",
- "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
- "type": "explorer"
- },
- {
- "name": "Immutable rate declaration",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 8678d04..0000000
--- a/content/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
- "evidence": [
- {
- "name": "Non-Upgradeable Token",
- "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
- "urls": [
- {
- "name": "SKY Token Contract",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/val-accrual/_metric.json b/content/evaluations/sky/val-accrual/_metric.json
deleted file mode 100644
index 0d3d99d..0000000
--- a/content/evaluations/sky/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__active.json b/content/evaluations/sky/val-accrual/val-accrual__active.json
deleted file mode 100644
index 5595264..0000000
--- a/content/evaluations/sky/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "positive",
- "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
- "evidence": [
- {
- "name": "Smart Burn Engine",
- "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
- "urls": [
- {
- "name": "Splitter contract",
- "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
- "type": "explorer"
- },
- {
- "name": "Flapper (buyback executor)",
- "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
- "type": "explorer"
- },
- {
- "name": "Flapper source code",
- "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
- "type": "github"
- },
- {
- "name": "Smart Burn Engine Dashboard",
- "url": "https://info.sky.money/smart-burn-engine",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
- "urls": [
- {
- "name": "Stability fee accrual",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
- "type": "github"
- },
- {
- "name": "Surplus routing to flapper",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__mechanism.json b/content/evaluations/sky/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index bdb8dc4..0000000
--- a/content/evaluations/sky/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
- "evidence": [
- {
- "name": "Fee Rate Control",
- "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
- "urls": [
- {
- "name": "Jug fee configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
- "type": "github"
- },
- {
- "name": "Jug contract",
- "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Surplus Buffer Control",
- "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
- "urls": [
- {
- "name": "Vow hump configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
- "type": "github"
- },
- {
- "name": "Vow contract — read hump",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__offchain.json b/content/evaluations/sky/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index a541c0a..0000000
--- a/content/evaluations/sky/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
- "tags": [
- "Reference"
- ],
- "evidence": [
- {
- "name": "Foundation Independence",
- "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
- "urls": [
- {
- "name": "Foundation Mandate",
- "url": "https://daifoundation.org/mandate",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/val-accrual/val-accrual__treasury.json b/content/evaluations/sky/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 832c737..0000000
--- a/content/evaluations/sky/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
- "evidence": [
- {
- "name": "Onchain Treasury",
- "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/verifiability/_metric.json b/content/evaluations/sky/verifiability/_metric.json
deleted file mode 100644
index 7655c73..0000000
--- a/content/evaluations/sky/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/sky/verifiability/verifiability__protocol-source.json b/content/evaluations/sky/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 648a473..0000000
--- a/content/evaluations/sky/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
- "evidence": [
- {
- "name": "Open Source Repositories",
- "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
- "urls": [
- {
- "name": "Core Protocol",
- "url": "https://github.com/sky-ecosystem/dss",
- "type": "github"
- },
- {
- "name": "Contract Registry",
- "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/sky/verifiability/verifiability__token-source.json b/content/evaluations/sky/verifiability/verifiability__token-source.json
deleted file mode 100644
index 0d71b8d..0000000
--- a/content/evaluations/sky/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
- "evidence": [
- {
- "name": "Verified Source",
- "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
- "urls": [
- {
- "name": "Source Code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- },
- {
- "name": "Verified on Etherscan",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/distribution/_metric.json b/content/evaluations/uni/distribution/_metric.json
deleted file mode 100644
index 69c4a54..0000000
--- a/content/evaluations/uni/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/uni/distribution/distribution__concentration.json b/content/evaluations/uni/distribution/distribution__concentration.json
deleted file mode 100644
index 110aef5..0000000
--- a/content/evaluations/uni/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
-}
diff --git a/content/evaluations/uni/distribution/distribution__supply-schedule.json b/content/evaluations/uni/distribution/distribution__supply-schedule.json
deleted file mode 100644
index aa8e115..0000000
--- a/content/evaluations/uni/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "status": "positive",
- "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
- "evidence": [
- {
- "name": "TreasuryVester Contracts",
- "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
- "urls": [
- {
- "name": "TreasuryVester Code",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
- "type": "github"
- },
- {
- "name": "TreasuryVester 1",
- "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 2",
- "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 3",
- "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 4",
- "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/offchain/_metric.json b/content/evaluations/uni/offchain/_metric.json
deleted file mode 100644
index 32abe85..0000000
--- a/content/evaluations/uni/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/uni/offchain/offchain__distribution.json b/content/evaluations/uni/offchain/offchain__distribution.json
deleted file mode 100644
index 83546db..0000000
--- a/content/evaluations/uni/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Terms of Service",
- "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/offchain/offchain__licensing.json b/content/evaluations/uni/offchain/offchain__licensing.json
deleted file mode 100644
index 20a3717..0000000
--- a/content/evaluations/uni/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "warning",
- "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
- "evidence": []
-}
diff --git a/content/evaluations/uni/offchain/offchain__trademark.json b/content/evaluations/uni/offchain/offchain__trademark.json
deleted file mode 100644
index def920e..0000000
--- a/content/evaluations/uni/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Trademark Guidelines",
- "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/_metric.json b/content/evaluations/uni/onchain-ctrl/_metric.json
deleted file mode 100644
index a1bf5bc..0000000
--- a/content/evaluations/uni/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 81720c4..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
- "evidence": []
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5f6c7c5..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 4ba972f..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
- "evidence": [
- {
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- },
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index d3f6dd6..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
- "evidence": [
- {
- "name": "Non-upgradeable Protocol Contracts",
- "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
- "urls": [
- {
- "name": "V2 Factory Create2",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
- "type": "github"
- },
- {
- "name": "V3 Pool Protection",
- "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
- "type": "github"
- },
- {
- "name": "V4 PoolManager: Singleton",
- "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Governance Contract",
- "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 981f1bb..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
- "evidence": [
- {
- "name": "V2 Factory",
- "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
- "urls": [
- {
- "name": "V2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Factory",
- "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
- "urls": [
- {
- "name": "V3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V4 PoolManager",
- "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
- "urls": [
- {
- "name": "V4PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "UNI Token",
- "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
- "urls": [
- {
- "name": "UNI Token",
- "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
- "type": "explorer"
- },
- {
- "name": "Timelock (deployed minter)",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 2b18768..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
- "evidence": [
- {
- "name": "Inflation Cap",
- "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
- "urls": [
- {
- "name": "Mint once per year logic",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
- "type": "github"
- },
- {
- "name": "2% mint cap",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Control",
- "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index e50c26f..0000000
--- a/content/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol Source",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- },
- {
- "name": "Etherscan",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/val-accrual/_metric.json b/content/evaluations/uni/val-accrual/_metric.json
deleted file mode 100644
index 3c8d23e..0000000
--- a/content/evaluations/uni/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__active.json b/content/evaluations/uni/val-accrual/val-accrual__active.json
deleted file mode 100644
index 9360e90..0000000
--- a/content/evaluations/uni/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "status": "positive",
- "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
- "evidence": [
- {
- "name": "V2 Fees",
- "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
- "urls": [
- {
- "name": "UniswapV2Pool: feeTo",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Pool: Fee Destination",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "V3 Fees",
- "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
- "urls": [
- {
- "name": "V3FeeAdapter",
- "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: collectProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fees",
- "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
- "urls": [
- {
- "name": "V4 PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- },
- {
- "name": "V4 PoolManager: CollectProtocolFees",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
- "type": "github"
- }
- ]
- },
- {
- "name": "Burn Mechanism",
- "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
- "urls": [
- {
- "name": "FirePit 4000 UNI Requirement",
- "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__mechanism.json b/content/evaluations/uni/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index f500fa5..0000000
--- a/content/evaluations/uni/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "status": "positive",
- "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
- "evidence": [
- {
- "name": "V2 Fee Control",
- "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Fee Control",
- "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
- "urls": [
- {
- "name": "UniswapV3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: setFeeProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fee Control",
- "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
- "urls": [
- {
- "name": "PoolManager(V4): setProtocolFee",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__offchain.json b/content/evaluations/uni/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 8c00c48..0000000
--- a/content/evaluations/uni/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
- "evidence": [
- {
- "urls": [
- {
- "name": "DUNI Proposal",
- "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/val-accrual/val-accrual__treasury.json b/content/evaluations/uni/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 2afc7f0..0000000
--- a/content/evaluations/uni/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/verifiability/_metric.json b/content/evaluations/uni/verifiability/_metric.json
deleted file mode 100644
index 40ae2ee..0000000
--- a/content/evaluations/uni/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/uni/verifiability/verifiability__protocol-source.json b/content/evaluations/uni/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 5d637b5..0000000
--- a/content/evaluations/uni/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "status": "positive",
- "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap V2 Core (GitHub)",
- "url": "https://github.com/Uniswap/v2-core",
- "type": "github"
- },
- {
- "name": "Uniswap V3 Core (GitHub)",
- "url": "https://github.com/Uniswap/v3-core",
- "type": "github"
- },
- {
- "name": "Uniswap V4 Core (GitHub)",
- "url": "https://github.com/Uniswap/v4-core",
- "type": "github"
- },
- {
- "name": "UniswapX (GitHub)",
- "url": "https://github.com/Uniswap/UniswapX",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/uni/verifiability/verifiability__token-source.json b/content/evaluations/uni/verifiability/verifiability__token-source.json
deleted file mode 100644
index 33eea24..0000000
--- a/content/evaluations/uni/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UNI Token (Etherscan)",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- },
- {
- "name": "Uni.sol Source (GitHub)",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/distribution/_metric.json b/content/evaluations/yb/distribution/_metric.json
deleted file mode 100644
index d1b94bc..0000000
--- a/content/evaluations/yb/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/content/evaluations/yb/distribution/distribution__concentration.json b/content/evaluations/yb/distribution/distribution__concentration.json
deleted file mode 100644
index 47c4744..0000000
--- a/content/evaluations/yb/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
- "evidence": [
- {
- "name": "veYB Supply",
- "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/distribution/distribution__supply-schedule.json b/content/evaluations/yb/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 9e11843..0000000
--- a/content/evaluations/yb/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
- "urls": [
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/offchain/_metric.json b/content/evaluations/yb/offchain/_metric.json
deleted file mode 100644
index 6c4bba4..0000000
--- a/content/evaluations/yb/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/content/evaluations/yb/offchain/offchain__distribution.json b/content/evaluations/yb/offchain/offchain__distribution.json
deleted file mode 100644
index d5547e1..0000000
--- a/content/evaluations/yb/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YieldBasis Website",
- "url": "https://yieldbasis.com/",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/offchain/offchain__licensing.json b/content/evaluations/yb/offchain/offchain__licensing.json
deleted file mode 100644
index 9374e87..0000000
--- a/content/evaluations/yb/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
- "evidence": [
- {
- "name": "License Analysis",
- "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
- "urls": [
- {
- "name": "yb-core contracts directory",
- "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
- "type": "github"
- },
- {
- "name": "Curve Licensing Vesting",
- "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/offchain/offchain__trademark.json b/content/evaluations/yb/offchain/offchain__trademark.json
deleted file mode 100644
index 00e0821..0000000
--- a/content/evaluations/yb/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify trademark ownership.",
- "evidence": []
-}
diff --git a/content/evaluations/yb/onchain-ctrl/_metric.json b/content/evaluations/yb/onchain-ctrl/_metric.json
deleted file mode 100644
index 03c2d81..0000000
--- a/content/evaluations/yb/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index e2feb0c..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
- "evidence": [
- {
- "name": "Exit Paths",
- "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
- "urls": [
- {
- "name": "VotingEscrow.withdraw",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
- "type": "github"
- },
- {
- "name": "FeeDistributor.claim",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index e76cece..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB.vy full source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 1b7a16e..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "positive",
- "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
- "evidence": [
- {
- "name": "Governance System",
- "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
- "urls": [
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- },
- {
- "name": "veYB (VotingEscrow)",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "TokenVoting Plugin",
- "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
- "type": "explorer"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.yieldbasis.com/user/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index e0368ef..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
- "urls": [
- {
- "name": "Factory Contract",
- "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
- "type": "explorer"
- },
- {
- "name": "Factory.set_implementations",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
- "type": "github"
- },
- {
- "name": "MigrationFactoryOwner ADMIN immutable",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 93f7045..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
- "evidence": [
- {
- "name": "DAO-Controlled Contracts",
- "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
- "urls": [
- {
- "name": "GaugeController",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- },
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "MigrationFactoryOwner",
- "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "veYB Owner (_yb.eth)",
- "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "set_transfer_clearance_checker",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 0203010..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
- "evidence": [
- {
- "name": "Emission Mechanism",
- "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
- "urls": [
- {
- "name": "get_adjustment (minting rate)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
- "type": "github"
- },
- {
- "name": "YB.emit function",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
- "type": "github"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json b/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 788c4e7..0000000
--- a/content/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
- "evidence": [
- {
- "name": "Token Ownership",
- "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
- "urls": [
- {
- "name": "YB Token Contract",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "renounce_ownership",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/val-accrual/_metric.json b/content/evaluations/yb/val-accrual/_metric.json
deleted file mode 100644
index 689d6be..0000000
--- a/content/evaluations/yb/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__active.json b/content/evaluations/yb/val-accrual/val-accrual__active.json
deleted file mode 100644
index dd9e19d..0000000
--- a/content/evaluations/yb/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "status": "positive",
- "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
- "evidence": [
- {
- "name": "Fee Flow",
- "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
- "urls": [
- {
- "name": "LT.withdraw_admin_fees",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
- "type": "github"
- },
- {
- "name": "Factory.fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
- "type": "github"
- },
- {
- "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
- "type": "github"
- },
- {
- "name": "FeeDistributor Contract",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "veYB Documentation",
- "url": "https://docs.yieldbasis.com/user/veyb",
- "type": "docs"
- },
- {
- "name": "Fee Data (ValueVerse)",
- "url": "https://yb.valueverse.ai",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__mechanism.json b/content/evaluations/yb/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 8b8ce8b..0000000
--- a/content/evaluations/yb/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
- "evidence": [
- {
- "name": "Fee Flow Direction",
- "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
- "urls": [
- {
- "name": "MigrationFactoryOwner.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
- "type": "github"
- },
- {
- "name": "Factory.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
- "urls": [
- {
- "name": "vote_for_gauge_weights",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
- "type": "github"
- },
- {
- "name": "GaugeController Contract",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__offchain.json b/content/evaluations/yb/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 084ddf2..0000000
--- a/content/evaluations/yb/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/content/evaluations/yb/val-accrual/val-accrual__treasury.json b/content/evaluations/yb/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index ed8c75a..0000000
--- a/content/evaluations/yb/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "at_risk",
- "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
- "evidence": [
- {
- "name": "Ecosystem Reserve",
- "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
- "urls": [
- {
- "name": "Ecosystem Reserve",
- "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
- "type": "explorer"
- },
- {
- "name": "Ecosystem Reserve Owner (EOA)",
- "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
- "type": "explorer"
- },
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/verifiability/_metric.json b/content/evaluations/yb/verifiability/_metric.json
deleted file mode 100644
index df29e57..0000000
--- a/content/evaluations/yb/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/content/evaluations/yb/verifiability/verifiability__protocol-source.json b/content/evaluations/yb/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 57de733..0000000
--- a/content/evaluations/yb/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
- "evidence": [
- {
- "name": "Verification and Audits",
- "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
- "urls": [
- {
- "name": "yb-core GitHub Repository",
- "url": "https://github.com/yield-basis/yb-core",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/content/evaluations/yb/verifiability/verifiability__token-source.json b/content/evaluations/yb/verifiability/verifiability__token-source.json
deleted file mode 100644
index fe6d309..0000000
--- a/content/evaluations/yb/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB Token Verified on Etherscan",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "YB.vy Source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/content/faq.json b/content/faq.json
deleted file mode 100644
index 64170db..0000000
--- a/content/faq.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "topics": [
- {
- "id": "basics",
- "name": "Basics",
- "about": "Core definitions and how to use the framework.",
- "questions": [
- {
- "id": "basics__ownership-token",
- "question": "What is an ownership token?",
- "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
- },
- {
- "id": "basics__how-to-use",
- "question": "How can I use the Ownership Token Framework?",
- "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
- }
- ]
- },
- {
- "id": "methodology",
- "name": "Methodology",
- "about": "How evaluation, sourcing, and verification work.",
- "questions": [
- {
- "id": "methodology__evaluation",
- "question": "How do you evaluate tokens?",
- "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- },
- {
- "id": "methodology__evidence",
- "question": "How do you source and verify evidence?",
- "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- }
- ]
- },
- {
- "id": "participation",
- "name": "Participation",
- "about": "How tokens are selected and how to get involved.",
- "questions": [
- {
- "id": "participation__selection",
- "question": "How do you choose which tokens to feature?",
- "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
- },
- {
- "id": "participation__listing",
- "question": "How can I get a token listed?",
- "answer": "Submit a request (or refer a token) using this [here](submit-token)."
- },
- {
- "id": "participation__contribute",
- "question": "How can I contribute to this initiative?",
- "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
- }
- ]
- }
- ]
-}
diff --git a/content/framework/_meta.json b/content/framework/_meta.json
deleted file mode 100644
index 2f58a3f..0000000
--- a/content/framework/_meta.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "baseUrl": "https://github.com/aragon/ownership-token-framework/blob/development/README.md",
- "order": [
- "onchain-ctrl",
- "val-accrual",
- "verifiability",
- "distribution",
- "offchain"
- ]
-}
diff --git a/content/framework/distribution.json b/content/framework/distribution.json
deleted file mode 100644
index 52be47f..0000000
--- a/content/framework/distribution.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "id": "distribution",
- "name": "Metric 4: Token Distribution",
- "displayName": "Token Distribution",
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "anchor": "#metric-4-token-distribution",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
- }
- ]
-}
diff --git a/content/framework/offchain.json b/content/framework/offchain.json
deleted file mode 100644
index 9dc3d8d..0000000
--- a/content/framework/offchain.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "id": "offchain",
- "name": "Offchain Dependencies",
- "displayName": "Offchain Dependencies",
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "anchor": "#offchain-dependencies",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
- }
- ]
-}
diff --git a/content/framework/onchain-ctrl.json b/content/framework/onchain-ctrl.json
deleted file mode 100644
index 57f816a..0000000
--- a/content/framework/onchain-ctrl.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "id": "onchain-ctrl",
- "name": "Metric 1: Onchain Control",
- "displayName": "Onchain Control",
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "anchor": "#metric-1-onchain-control",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
- }
- ]
-}
diff --git a/content/framework/val-accrual.json b/content/framework/val-accrual.json
deleted file mode 100644
index 676fa1a..0000000
--- a/content/framework/val-accrual.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "id": "val-accrual",
- "name": "Metric 2: Value Accrual",
- "displayName": "Value Accrual",
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "anchor": "#metric-2-value-accrual",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
- }
- ]
-}
diff --git a/content/framework/verifiability.json b/content/framework/verifiability.json
deleted file mode 100644
index 9e0f5b8..0000000
--- a/content/framework/verifiability.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "id": "verifiability",
- "name": "Metric 3: Verifiability",
- "displayName": "Verifiability",
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "anchor": "#metric-3-verifiability",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
- }
- ]
-}
diff --git a/content/testimonials.json b/content/testimonials.json
deleted file mode 100644
index 2846926..0000000
--- a/content/testimonials.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "title": "Evidence-backed due diligence for investors",
- "testimonials": [
- {
- "id": "miles-a16z",
- "name": "Miles Jennings",
- "organization": "a16z",
- "avatar": "/images/testimonials/miles-jennings.png",
- "url": "https://a16zcrypto.com/",
- "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
- },
- {
- "id": "f5-crypto",
- "name": "Paul Otto",
- "organization": "F5 Crypto",
- "avatar": "/images/testimonials/paul-otto.png",
- "url": "https://f5crypto.com/en/",
- "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
- }
- ]
-}
diff --git a/content/tokens/aave.json b/content/tokens/aave.json
deleted file mode 100644
index 96d8e46..0000000
--- a/content/tokens/aave.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "aave",
- "coingeckoId": "aave",
- "name": "AAVE",
- "symbol": "AAVE",
- "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
- "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
- "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aave.com/",
- "twitter": "https://twitter.com/aave",
- "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
- },
- "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
-}
diff --git a/content/tokens/aero.json b/content/tokens/aero.json
deleted file mode 100644
index fe193fc..0000000
--- a/content/tokens/aero.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "aero",
- "coingeckoId": "aerodrome-finance",
- "name": "AERO",
- "symbol": "AERO",
- "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
- "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
- "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
- "network": "base",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aerodrome.finance/",
- "twitter": "https://twitter.com/Aerodrome",
- "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
- },
- "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
-}
diff --git a/content/tokens/crv.json b/content/tokens/crv.json
deleted file mode 100644
index 7db7514..0000000
--- a/content/tokens/crv.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "crv",
- "coingeckoId": "curve-dao-token",
- "name": "CRV",
- "symbol": "CRV",
- "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
- "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
- "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://curve.finance/",
- "twitter": "https://twitter.com/curvefinance",
- "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
- },
- "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
-}
diff --git a/content/tokens/ena.json b/content/tokens/ena.json
deleted file mode 100644
index 5b0151f..0000000
--- a/content/tokens/ena.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ena",
- "coingeckoId": "ethena",
- "name": "ENA",
- "symbol": "ENA",
- "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
- "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
- "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ethena.fi/",
- "twitter": "https://twitter.com/ethena",
- "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
- },
- "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
-}
diff --git a/content/tokens/ethfi.json b/content/tokens/ethfi.json
deleted file mode 100644
index 1e86fa1..0000000
--- a/content/tokens/ethfi.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ethfi",
- "coingeckoId": "ether-fi",
- "name": "ETHFI",
- "symbol": "ETHFI",
- "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
- "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
- "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ether.fi/",
- "twitter": "https://twitter.com/ether_fi",
- "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
- },
- "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
-}
diff --git a/content/tokens/ldo.json b/content/tokens/ldo.json
deleted file mode 100644
index 386c487..0000000
--- a/content/tokens/ldo.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ldo",
- "coingeckoId": "lido-dao",
- "name": "LDO",
- "symbol": "LDO",
- "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
- "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
- "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
- "network": "ethereum",
- "lastUpdated": 1777631939,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://lido.fi/",
- "twitter": "https://twitter.com/lidofinance",
- "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
- },
- "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
-}
diff --git a/content/tokens/lqty.json b/content/tokens/lqty.json
deleted file mode 100644
index 406fd2f..0000000
--- a/content/tokens/lqty.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "lqty",
- "coingeckoId": "liquity",
- "name": "LQTY",
- "symbol": "LQTY",
- "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
- "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
- "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
- "network": "ethereum",
- "lastUpdated": 1778064256,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://www.liquity.org/",
- "twitter": "https://twitter.com/LiquityProtocol",
- "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
- },
- "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
-}
diff --git a/content/tokens/ondo.json b/content/tokens/ondo.json
deleted file mode 100644
index fa64d38..0000000
--- a/content/tokens/ondo.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ondo",
- "name": "ONDO",
- "symbol": "ONDO",
- "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
- "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
- "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
- "network": "ethereum",
- "lastUpdated": 1778674909,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ondo.finance/",
- "twitter": "https://twitter.com/OndoFinance",
- "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
- },
- "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
- "coingeckoId": "ondo-finance"
-}
diff --git a/content/tokens/sky.json b/content/tokens/sky.json
deleted file mode 100644
index bd377b7..0000000
--- a/content/tokens/sky.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "sky",
- "coingeckoId": "sky",
- "name": "SKY",
- "symbol": "SKY",
- "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
- "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
- "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://sky.money/",
- "twitter": "https://twitter.com/SkyEcosystem",
- "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
- },
- "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
-}
diff --git a/content/tokens/uni.json b/content/tokens/uni.json
deleted file mode 100644
index f3142e2..0000000
--- a/content/tokens/uni.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "uni",
- "coingeckoId": "uniswap",
- "name": "UNI",
- "symbol": "UNI",
- "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
- "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
- "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://uniswap.org/",
- "twitter": "https://twitter.com/uniswap",
- "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
- },
- "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
-}
diff --git a/content/tokens/yb.json b/content/tokens/yb.json
deleted file mode 100644
index 7f9c298..0000000
--- a/content/tokens/yb.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "yb",
- "coingeckoId": "yield-basis",
- "name": "YB",
- "symbol": "YB",
- "address": "0x01791F726B4103694969820be083196cC7c045fF",
- "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
- "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://yieldbasis.com/",
- "twitter": "https://x.com/yieldbasis",
- "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
- },
- "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
-}
diff --git a/package.json b/package.json
index 246590b..0db91d4 100644
--- a/package.json
+++ b/package.json
@@ -3,9 +3,8 @@
"private": true,
"type": "module",
"scripts": {
- "dev": "node scripts/sync-coingecko-ids.mjs --write && node scripts/compose-data.mjs && vite dev --port 3000",
- "build": "node scripts/sync-coingecko-ids.mjs --write && node scripts/compose-data.mjs && vite build",
- "compose": "node scripts/compose-data.mjs",
+ "dev": "vite dev --port 3000",
+ "build": "vite build",
"preview": "vite preview",
"test": "vitest run",
"format": "biome format",
diff --git a/scripts/compose-data.mjs b/scripts/compose-data.mjs
deleted file mode 100644
index f9eb240..0000000
--- a/scripts/compose-data.mjs
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env node
-/**
- * Composer: content/ atoms → src/data/generated/ read models.
- *
- * Joins research-shaped atoms (registry, framework, evaluations) into
- * consumer-shaped docs by id:
- * - criterion name/about come from framework (atom `name` overrides)
- * - metric display name + about come from framework
- * - scores and status counts are computed here (compose time), not at render
- *
- * Replaces the runtime framework-merge formerly in src/lib/metrics-data.ts.
- * The scoring logic mirrors the pure functions in src/lib/scoring.ts and is
- * pinned to them by the golden round-trip tests.
- *
- * Exports composeAll() for tests; run directly to write src/data/generated/.
- */
-import { createHash } from "node:crypto"
-import {
- mkdirSync,
- readdirSync,
- readFileSync,
- rmSync,
- writeFileSync,
-} from "node:fs"
-import { dirname, join } from "node:path"
-import { fileURLToPath } from "node:url"
-
-const root = join(dirname(fileURLToPath(import.meta.url)), "..")
-const contentDir = join(root, "content")
-const generatedDir = join(root, "src", "data", "generated")
-
-const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
-
-const SCORED_STATUSES = new Set(["positive", "warning", "at_risk"])
-
-function getMetricScore(metric) {
- const reference = metric.tags?.includes("Reference") ?? false
- const evaluatedCriteria = metric.criteria.filter((c) =>
- SCORED_STATUSES.has(c.status)
- )
- const total = evaluatedCriteria.length
- const passing = evaluatedCriteria.filter(
- (c) => c.status === "positive"
- ).length
- const evaluated = reference ? false : total > 0
- const percentage = total > 0 ? (passing / total) * 100 : 0
-
- return {
- metricId: metric.id,
- metricName: metric.name,
- passing,
- total,
- percentage,
- evaluated,
- reference,
- }
-}
-
-function getTokenScore(tokenId, metrics) {
- const metricScores = metrics.map(getMetricScore)
- const scoredMetrics = metricScores.filter((m) => m.evaluated && !m.reference)
- const passing = scoredMetrics.reduce((sum, m) => sum + m.passing, 0)
- const total = scoredMetrics.reduce((sum, m) => sum + m.total, 0)
- const percentage = total > 0 ? (passing / total) * 100 : 0
-
- return { tokenId, passing, total, percentage, metrics: metricScores }
-}
-
-export function composeAll(dir = contentDir) {
- const meta = readJson(join(dir, "framework", "_meta.json"))
- const framework = meta.order.map((id) =>
- readJson(join(dir, "framework", `${id}.json`))
- )
- const criterionDefs = new Map(
- framework.flatMap((m) => m.criteria.map((c) => [c.id, c]))
- )
-
- const tokenIds = readdirSync(join(dir, "tokens"))
- .filter((f) => f.endsWith(".json"))
- .map((f) => f.replace(/\.json$/, ""))
- .sort()
-
- const tokenAtoms = new Map(
- tokenIds.map((id) => [id, readJson(join(dir, "tokens", `${id}.json`))])
- )
-
- const tokenDocs = []
- for (const tokenId of tokenIds) {
- const metrics = []
- for (const fm of framework) {
- const metricDir = join(dir, "evaluations", tokenId, fm.id)
- const editorial = readJson(join(metricDir, "_metric.json"))
- const criteria = fm.criteria.map((fc) => {
- const atom = readJson(join(metricDir, `${fc.id}.json`))
- const composed = {
- id: fc.id,
- name: atom.name ?? fc.name,
- about: fc.about,
- status: atom.status,
- notes: atom.notes,
- }
- if ("tags" in atom) composed.tags = atom.tags
- if ("evidence" in atom) composed.evidence = atom.evidence
- return composed
- })
- metrics.push({
- id: fm.id,
- name: fm.displayName,
- about: fm.about,
- summary: editorial.summary,
- tags: editorial.tags,
- criteria,
- })
- }
-
- const allCriteria = metrics.flatMap((m) => m.criteria)
- const countBy = (status) =>
- allCriteria.filter((c) => c.status === status).length
- const score = getTokenScore(tokenId, metrics)
-
- tokenDocs.push({
- ...tokenAtoms.get(tokenId),
- positive: countBy("positive"),
- neutral: countBy("warning"),
- atRisk: countBy("at_risk"),
- evidenceEntries: allCriteria.flatMap((c) => c.evidence ?? []).length,
- score,
- criteriaStatuses: Object.fromEntries(
- allCriteria.map((c) => [c.id, c.status])
- ),
- metrics,
- })
- }
-
- // Index rows are the dashboard read model: full score (the score hover
- // shows the per-metric breakdown) and a flat criterion-status map (the
- // table renders single-criterion columns across all tokens) — so the
- // dashboard needs exactly one fetch and never loads per-token docs.
- const index = {
- tokens: tokenDocs.map(({ metrics: _metrics, ...row }) => row),
- }
-
- const frameworkDoc = { baseUrl: meta.baseUrl, metrics: framework }
- const faq = readJson(join(dir, "faq.json"))
- const testimonials = readJson(join(dir, "testimonials.json"))
-
- // Deterministic snapshot identity: a content hash over the composed output.
- // Stable across recompositions of identical content (keeps the freshness
- // gate meaningful); changes exactly when published data changes. The future
- // publish pipeline reuses this as the R2 snapshot key component.
- const snapshotId = createHash("sha256")
- .update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
- .digest("hex")
- .slice(0, 16)
- const manifest = {
- snapshot_id: snapshotId,
- tokens: tokenDocs.map((d) => d.id),
- }
-
- return {
- index,
- tokenDocs,
- frameworkDoc,
- faq,
- testimonials,
- manifest,
- }
-}
-
-function main() {
- const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
- composeAll()
-
- rmSync(generatedDir, { recursive: true, force: true })
- const writeJson = (p, data) => {
- mkdirSync(dirname(p), { recursive: true })
- writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
- }
-
- writeJson(join(generatedDir, "index.json"), index)
- for (const doc of tokenDocs) {
- writeJson(join(generatedDir, "tokens", `${doc.id}.json`), doc)
- }
- writeJson(join(generatedDir, "framework.json"), frameworkDoc)
- writeJson(join(generatedDir, "faq.json"), faq)
- writeJson(join(generatedDir, "testimonials.json"), testimonials)
- writeJson(join(generatedDir, "manifest.json"), manifest)
-
- console.log(
- `composed: index (${index.tokens.length} rows), ${tokenDocs.length} token docs, framework, faq, testimonials (snapshot ${manifest.snapshot_id})`
- )
-}
-
-if (process.argv[1] === fileURLToPath(import.meta.url)) {
- main()
-}
diff --git a/scripts/get-changed-token-ids.mjs b/scripts/get-changed-token-ids.mjs
deleted file mode 100644
index aa6ddcc..0000000
--- a/scripts/get-changed-token-ids.mjs
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Emit a comma-separated list of token ids whose content changed between two
- * git refs. A token counts as changed when its registry atom
- * (content/tokens/.json) or any of its evaluation atoms
- * (content/evaluations//**) differ.
- *
- * Usage: node scripts/get-changed-token-ids.mjs --before --after
- * With no usable --before (e.g. zero sha on first push), all token ids are
- * reported.
- */
-import { execSync } from "node:child_process"
-import { readdir } from "node:fs/promises"
-
-function parseArgs(argv) {
- const beforeIndex = argv.indexOf("--before")
- const afterIndex = argv.indexOf("--after")
- return {
- before: beforeIndex === -1 ? "" : argv[beforeIndex + 1] ?? "",
- after: afterIndex === -1 ? "" : argv[afterIndex + 1] ?? "",
- }
-}
-
-function tokenIdFromPath(filePath) {
- const registry = filePath.match(/^content\/tokens\/([^/]+)\.json$/)
- if (registry) return registry[1]
- const evaluation = filePath.match(/^content\/evaluations\/([^/]+)\//)
- if (evaluation) return evaluation[1]
- return null
-}
-
-async function allTokenIds() {
- const files = await readdir("content/tokens")
- return files
- .filter((f) => f.endsWith(".json"))
- .map((f) => f.replace(/\.json$/, ""))
-}
-
-const { before, after } = parseArgs(process.argv.slice(2))
-const zeroSha = /^0+$/
-const hasBefore = before && !zeroSha.test(before)
-const hasAfter = after && !zeroSha.test(after)
-
-let ids
-
-if (!hasBefore) {
- ids = await allTokenIds()
-} else {
- try {
- const range = hasAfter ? `${before} ${after}` : before
- const diff = execSync(
- `git diff --name-only ${range} -- content/tokens content/evaluations`,
- { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
- )
- ids = [
- ...new Set(
- diff
- .split("\n")
- .map((line) => tokenIdFromPath(line.trim()))
- .filter(Boolean)
- ),
- ]
- } catch (_error) {
- console.error(
- "::warning::Unable to diff content paths from git; skipping updates."
- )
- process.exit(0)
- }
-}
-
-process.stdout.write(ids.join(","))
diff --git a/scripts/migrate-to-atoms.mjs b/scripts/migrate-to-atoms.mjs
deleted file mode 100644
index a42c163..0000000
--- a/scripts/migrate-to-atoms.mjs
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env node
-/**
- * One-shot migration: src/data/*.json (legacy monoliths) → content/ atoms.
- *
- * Deterministic and idempotent — wipes and rebuilds content/ from the legacy
- * files. Kept for re-runs during review; obsolete once the legacy files are
- * deleted.
- *
- * What it strips (and why):
- * - token positive/neutral/atRisk/evidenceEntries: derived counts, stale for
- * every token in the legacy data — recomputed at compose time
- * - metric/criterion `about`: framework-owned, masked at runtime today
- * (metrics-data.ts merge) — composed from framework atoms
- * - metric `name`: uniform per metric id across tokens — becomes
- * framework displayName
- * - criterion `name`: kept ONLY where it diverges from the framework name
- * (exactly one case today: lqty onchain-ctrl__access-gating)
- */
-import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
-import { dirname, join } from "node:path"
-import { fileURLToPath } from "node:url"
-
-const root = join(dirname(fileURLToPath(import.meta.url)), "..")
-const src = join(root, "src", "data")
-const out = join(root, "content")
-
-const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
-const writeJson = (p, data) => {
- mkdirSync(dirname(p), { recursive: true })
- writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
-}
-
-// Framework constants leaving src/lib/framework.ts
-const METRIC_ANCHORS = {
- "onchain-ctrl": "#metric-1-onchain-control",
- "val-accrual": "#metric-2-value-accrual",
- verifiability: "#metric-3-verifiability",
- distribution: "#metric-4-token-distribution",
- offchain: "#offchain-dependencies",
-}
-const FRAMEWORK_BASE_URL =
- "https://github.com/aragon/ownership-token-framework/blob/development/README.md"
-
-const tokens = readJson(join(src, "tokens.json")).tokens
-const metricsByToken = readJson(join(src, "metrics.json"))
-const framework = readJson(join(src, "framework.json"))
-
-rmSync(out, { recursive: true, force: true })
-
-// --- content/tokens/.json ---------------------------------------------
-for (const t of tokens) {
- const {
- positive: _p,
- neutral: _n,
- atRisk: _r,
- evidenceEntries: _e,
- ...atom
- } = t
- writeJson(join(out, "tokens", `${t.id}.json`), atom)
-}
-
-// --- content/framework/ ----------------------------------------------------
-// displayName = the per-token metric name, asserted uniform across tokens
-const displayNames = new Map()
-for (const [tokenId, metrics] of Object.entries(metricsByToken)) {
- for (const m of metrics) {
- const seen = displayNames.get(m.id)
- if (seen !== undefined && seen !== m.name) {
- throw new Error(
- `metric ${m.id} display name diverges at ${tokenId}: "${m.name}" vs "${seen}"`
- )
- }
- displayNames.set(m.id, m.name)
- }
-}
-
-for (const fm of framework) {
- const atom = {
- id: fm.id,
- name: fm.name,
- displayName: displayNames.get(fm.id) ?? fm.name,
- about: fm.about,
- ...(METRIC_ANCHORS[fm.id] ? { anchor: METRIC_ANCHORS[fm.id] } : {}),
- criteria: fm.criteria,
- }
- writeJson(join(out, "framework", `${fm.id}.json`), atom)
-}
-writeJson(join(out, "framework", "_meta.json"), {
- baseUrl: FRAMEWORK_BASE_URL,
- order: framework.map((m) => m.id),
-})
-
-// --- content/evaluations/// -----------------------------
-const frameworkCriterionNames = new Map(
- framework.flatMap((m) => m.criteria.map((c) => [c.id, c.name]))
-)
-
-let criterionCount = 0
-let nameOverrides = 0
-for (const [tokenId, metrics] of Object.entries(metricsByToken)) {
- for (const m of metrics) {
- const dir = join(out, "evaluations", tokenId, m.id)
- writeJson(join(dir, "_metric.json"), { summary: m.summary, tags: m.tags })
- for (const c of m.criteria) {
- const atom = {}
- if (c.name !== frameworkCriterionNames.get(c.id)) {
- atom.name = c.name
- nameOverrides++
- }
- atom.status = c.status
- atom.notes = c.notes
- if ("tags" in c) atom.tags = c.tags
- if ("evidence" in c) atom.evidence = c.evidence
- writeJson(join(dir, `${c.id}.json`), atom)
- criterionCount++
- }
- }
-}
-
-// --- content/faq.json + content/testimonials.json --------------------------
-writeJson(join(out, "faq.json"), readJson(join(src, "faq.json")))
-writeJson(join(out, "testimonials.json"), readJson(join(src, "testimonials.json")))
-
-console.log(
- `migrated: ${tokens.length} tokens, ${framework.length} framework metrics, ` +
- `${criterionCount} criterion evaluations (${nameOverrides} name overrides)`
-)
diff --git a/scripts/sync-coingecko-ids.mjs b/scripts/sync-coingecko-ids.mjs
deleted file mode 100644
index 0fc7e44..0000000
--- a/scripts/sync-coingecko-ids.mjs
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Sync CoinGecko IDs for the token registry atoms in content/tokens/
- *
- * Uses CoinGecko's /coins/{platform}/contract/{address} endpoint
- * to resolve the canonical CoinGecko ID from contract address + network.
- *
- * Usage:
- * node scripts/sync-coingecko-ids.mjs # dry-run, skips tokens with existing IDs
- * node scripts/sync-coingecko-ids.mjs --write # writes back to content/tokens/.json
- * node scripts/sync-coingecko-ids.mjs --force # re-verify all tokens (ignores cached IDs)
- */
-
-import { readdirSync, readFileSync, writeFileSync } from "node:fs"
-import { dirname, join, resolve } from "node:path"
-import { fileURLToPath } from "node:url"
-
-const __dirname = dirname(fileURLToPath(import.meta.url))
-const TOKENS_DIR = resolve(__dirname, "../content/tokens")
-
-// CoinGecko platform IDs mapped from our network names
-const NETWORK_TO_PLATFORM = {
- ethereum: "ethereum",
- base: "base",
- arbitrum: "arbitrum-one",
- optimism: "optimistic-ethereum",
- polygon: "polygon-pos",
- avalanche: "avalanche",
- bsc: "binance-smart-chain",
-}
-
-const COINGECKO_API = "https://api.coingecko.com/api/v3"
-
-// Rate limit: CoinGecko free tier allows ~10-30 req/min
-const DELAY_MS = 2500
-
-const c = {
- reset: "\x1b[0m",
- dim: "\x1b[2m",
- green: "\x1b[32m",
- yellow: "\x1b[33m",
- red: "\x1b[31m",
- cyan: "\x1b[36m",
- bold: "\x1b[1m",
-}
-
-function sleep(ms) {
- return new Promise((r) => setTimeout(r, ms))
-}
-
-async function lookupCoingeckoId(address, network) {
- const platform = NETWORK_TO_PLATFORM[network]
- if (!platform) {
- return { error: `Unknown network: ${network}` }
- }
-
- const url = `${COINGECKO_API}/coins/${platform}/contract/${address.toLowerCase()}`
- const res = await fetch(url)
-
- if (!res.ok) {
- return { error: `HTTP ${res.status} for ${address} on ${network}` }
- }
-
- const data = await res.json()
- return { id: data.id, name: data.name, symbol: data.symbol }
-}
-
-async function main() {
- const writeMode = process.argv.includes("--write")
- const tokenFiles = readdirSync(TOKENS_DIR).filter((f) => f.endsWith(".json"))
- const tokens = tokenFiles.map((file) => ({
- file: join(TOKENS_DIR, file),
- ...JSON.parse(readFileSync(join(TOKENS_DIR, file), "utf-8")),
- }))
-
- let changes = 0
- const changedFiles = new Set()
-
- console.log(`\n${c.cyan}${c.bold} 🦎 CoinGecko Sync${c.reset}`)
- console.log(`${c.dim} ─────────────────────────────${c.reset}\n`)
-
- const forceAll = process.argv.includes("--force")
- const missing = tokens.filter((t) => !t.coingeckoId)
-
- if (!forceAll && missing.length === 0) {
- console.log(` ${c.green}✓${c.reset} ${c.bold}${tokens.length} tokens${c.reset} synced ${c.dim}· no lookups needed${c.reset}\n`)
- return
- }
-
- const toProcess = forceAll ? tokens : missing
-
- for (const token of toProcess) {
- process.stdout.write(` ${c.dim}${token.symbol}${c.reset} ${c.dim}${token.network}:${token.address.slice(0, 10)}…${c.reset} `)
-
- const result = await lookupCoingeckoId(token.address, token.network)
-
- if (result.error) {
- console.log(`${c.red}✗ ${result.error}${c.reset}`)
- continue
- }
-
- if (!token.coingeckoId) {
- console.log(`${c.green}+ ${result.id}${c.reset}`)
- token.coingeckoId = result.id
- changes++
- changedFiles.add(token.file)
- } else if (token.coingeckoId !== result.id) {
- console.log(`${c.yellow}≠ ${token.coingeckoId} → ${result.id}${c.reset}`)
- token.coingeckoId = result.id
- changes++
- changedFiles.add(token.file)
- } else {
- console.log(`${c.green}✓ ${result.id}${c.reset}`)
- }
-
- await sleep(DELAY_MS)
- }
-
- console.log()
- if (changes > 0 && writeMode) {
- for (const token of tokens) {
- if (!changedFiles.has(token.file)) continue
- const { file, ...atom } = token
- writeFileSync(file, JSON.stringify(atom, null, 2) + "\n")
- }
- console.log(` ${c.green}✓${c.reset} Written ${c.bold}${changes}${c.reset} update(s) to content/tokens/\n`)
- } else if (changes > 0) {
- console.log(` ${c.yellow}${changes}${c.reset} update(s) pending ${c.dim}· run with --write to save${c.reset}\n`)
- } else {
- console.log(` ${c.green}✓${c.reset} All verified ${c.dim}· no changes${c.reset}\n`)
- }
-}
-
-main().catch((err) => {
- console.error(err)
- process.exit(1)
-})
diff --git a/scripts/update-token-timestamps.mjs b/scripts/update-token-timestamps.mjs
deleted file mode 100644
index 5e55bfa..0000000
--- a/scripts/update-token-timestamps.mjs
+++ /dev/null
@@ -1,62 +0,0 @@
-import { readdir, readFile, writeFile } from "node:fs/promises"
-import path from "node:path"
-
-const tokensDir = path.resolve("content/tokens")
-
-function normalizeSymbol(value) {
- return value.split("/").pop()?.trim().toUpperCase() ?? ""
-}
-
-function parseArgs(argv) {
- const args = new Set(argv)
- const idsIndex = argv.indexOf("--ids")
- const symbolIndex = argv.indexOf("--symbol")
- const timestampIndex = argv.indexOf("--timestamp")
-
- const ids =
- idsIndex === -1 ? null : argv[idsIndex + 1]?.split(",").filter(Boolean)
- const symbol = symbolIndex === -1 ? "" : argv[symbolIndex + 1] ?? ""
- const timestampArg = timestampIndex === -1 ? null : argv[timestampIndex + 1]
-
- return {
- updateAll: args.has("--all") || (!ids && !symbol),
- ids,
- symbol: normalizeSymbol(symbol),
- timestamp: timestampArg ? Number(timestampArg) : null,
- }
-}
-
-const { updateAll, ids, symbol, timestamp } = parseArgs(process.argv.slice(2))
-const nextTimestamp = Number.isFinite(timestamp)
- ? timestamp
- : Math.floor(Date.now() / 1000)
-
-const idSet = ids ? new Set(ids.map((id) => id.toLowerCase())) : null
-let updated = 0
-
-const files = (await readdir(tokensDir)).filter((f) => f.endsWith(".json"))
-
-for (const file of files) {
- const filePath = path.join(tokensDir, file)
- const token = JSON.parse(await readFile(filePath, "utf-8"))
-
- const matches =
- updateAll ||
- (idSet?.has(token.id.toLowerCase()) ?? false) ||
- (symbol !== "" && token.symbol.toUpperCase() === symbol)
-
- if (!matches) continue
-
- token.lastUpdated = nextTimestamp
- await writeFile(filePath, `${JSON.stringify(token, null, 2)}\n`, "utf-8")
- updated += 1
-}
-
-if (updated === 0) {
- console.log("No tokens matched; nothing updated.")
- process.exit(0)
-}
-
-console.log(
- `Updated ${updated} token${updated === 1 ? "" : "s"} to ${nextTimestamp}.`
-)
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index 39aa441..265175e 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -1,9 +1,13 @@
/**
- * OTF data contract — Zod schemas for the write model (content/ atoms) and
- * the read models (src/data/generated/ composed docs).
+ * OTF data contract — VENDORED COPY.
*
- * This module must not import app code: it is designed to extract cleanly
- * into a shared package if content moves to a separate repo (otf-cms).
+ * Source of truth: https://github.com/aragon/otf-cms (schemas/). Do not edit
+ * here; change in otf-cms and re-vendor. A CI drift check pins the two
+ * (plan task T-SCHEMA-DRIFT).
+ *
+ * Write-model schemas describe otf-cms content/ atoms; read-model schemas
+ * describe the composed docs this app serves (src/data/generated/, later
+ * Blob/Edge Config). This module must not import app code.
*/
export * from "./atoms"
export * from "./common"
diff --git a/tests/atoms-valid.test.ts b/tests/atoms-valid.test.ts
deleted file mode 100644
index 2f9bb84..0000000
--- a/tests/atoms-valid.test.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Schema validation: every atom under content/ and every composed read model
- * under src/data/generated/ must parse against the shared Zod contract.
- */
-import { readdirSync, readFileSync } from "node:fs"
-import { join } from "node:path"
-import { describe, expect, it } from "vitest"
-import {
- criterionEvaluationAtomSchema,
- faqSchema,
- frameworkDocSchema,
- frameworkMetaSchema,
- frameworkMetricAtomSchema,
- indexSchema,
- metricEditorialAtomSchema,
- testimonialsSchema,
- tokenAtomSchema,
- tokenDocSchema,
-} from "@/lib/schemas"
-
-const root = join(__dirname, "..")
-const content = join(root, "content")
-const generated = join(root, "src", "data", "generated")
-
-const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
-const jsonFiles = (dir: string) =>
- readdirSync(dir).filter((f) => f.endsWith(".json"))
-
-describe("content/ atoms parse against write-model schemas", () => {
- it("token atoms", () => {
- for (const f of jsonFiles(join(content, "tokens"))) {
- expect(
- () => tokenAtomSchema.parse(readJson(join(content, "tokens", f))),
- f
- ).not.toThrow()
- }
- })
-
- it("framework atoms + meta", () => {
- for (const f of jsonFiles(join(content, "framework"))) {
- const schema =
- f === "_meta.json" ? frameworkMetaSchema : frameworkMetricAtomSchema
- expect(
- () => schema.parse(readJson(join(content, "framework", f))),
- f
- ).not.toThrow()
- }
- })
-
- it("evaluation atoms", () => {
- const evals = join(content, "evaluations")
- for (const tokenId of readdirSync(evals)) {
- for (const metricId of readdirSync(join(evals, tokenId))) {
- for (const f of jsonFiles(join(evals, tokenId, metricId))) {
- const schema =
- f === "_metric.json"
- ? metricEditorialAtomSchema
- : criterionEvaluationAtomSchema
- expect(
- () => schema.parse(readJson(join(evals, tokenId, metricId, f))),
- `${tokenId}/${metricId}/${f}`
- ).not.toThrow()
- }
- }
- }
- })
-
- it("faq + testimonials", () => {
- expect(() => faqSchema.parse(readJson(join(content, "faq.json")))).not.toThrow()
- expect(() =>
- testimonialsSchema.parse(readJson(join(content, "testimonials.json")))
- ).not.toThrow()
- })
-})
-
-describe("src/data/generated/ parses against read-model schemas", () => {
- it("index", () => {
- expect(() =>
- indexSchema.parse(readJson(join(generated, "index.json")))
- ).not.toThrow()
- })
-
- it("token docs", () => {
- for (const f of jsonFiles(join(generated, "tokens"))) {
- expect(
- () => tokenDocSchema.parse(readJson(join(generated, "tokens", f))),
- f
- ).not.toThrow()
- }
- })
-
- it("framework doc", () => {
- expect(() =>
- frameworkDocSchema.parse(readJson(join(generated, "framework.json")))
- ).not.toThrow()
- })
-
- it("faq + testimonials passthrough", () => {
- expect(() =>
- faqSchema.parse(readJson(join(generated, "faq.json")))
- ).not.toThrow()
- expect(() =>
- testimonialsSchema.parse(readJson(join(generated, "testimonials.json")))
- ).not.toThrow()
- })
-})
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
deleted file mode 100644
index 2163fcd..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
deleted file mode 100644
index 5e8dfb9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 195571e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
deleted file mode 100644
index 3c60448..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
deleted file mode 100644
index 729980a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface terms identify Aave Labs as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://aave.com/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
deleted file mode 100644
index 5cae96f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
deleted file mode 100644
index 46ea782..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Trademark filing",
- "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
deleted file mode 100644
index af0a600..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 4a5906e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "status": "positive",
- "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
- "evidence": [
- {
- "name": "Core",
- "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
- "urls": [
- {
- "name": "Core Protocol Role addresses",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
- "type": "github"
- },
- {
- "name": "Core Protocol Roles in ACLManager",
- "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
- "type": "explorer"
- },
- {
- "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
- "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
- "type": "explorer"
- },
- {
- "name": "POOL_ADMIN_ROLE: Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Delegated Steward Roles",
- "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
- "urls": [
- {
- "name": "Stewards (docs)",
- "url": "https://aave.com/help/governance/aave-community",
- "type": "docs"
- },
- {
- "name": "Stewards (addresses)",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Protocol Emergency Guardian",
- "summary": "A separate multisig that executes limited emergency operations for the protocol.",
- "urls": [
- {
- "name": "Protocol Emergency Guardian",
- "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
- "type": "docs"
- },
- {
- "name": "Detailed protocol permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 7ca7f0a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token's implementation code",
- "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index e0d0466..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://aave.com/docs/ecosystem/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 27b3b55..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "Holders control implementation upgrades for all v3 market deployments.",
- "evidence": [
- {
- "name": "Upgrade Documentation",
- "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
- "urls": [
- {
- "name": "Upgradability per contract",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Ownership Chain",
- "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
- "urls": [
- {
- "name": "Pool",
- "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
- "type": "explorer"
- },
- {
- "name": "Governance",
- "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index a065c83..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "positive",
- "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
- "evidence": [
- {
- "name": "Governance Emergency Guardian",
- "urls": [
- {
- "name": "Onchain address",
- "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Detailed Governance Permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 32d8315..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 1182c67..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "The AAVE token is upgradeable but controlled by token holders.",
- "evidence": [
- {
- "name": "Ownership Chain",
- "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
- "urls": [
- {
- "name": "AAVE Proxy",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "ProxyAdmin",
- "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
deleted file mode 100644
index d5958bb..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
deleted file mode 100644
index 497f899..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Safety Module - Incentives",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
- "type": "docs"
- },
- {
- "name": "Umbrella Transition",
- "url": "https://aave.com/help/umbrella/stake",
- "type": "docs"
- },
- {
- "name": "Umbrella Activation Proposal",
- "url": "https://vote.onaave.com/proposal/?proposalId=320",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index a0753b1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
- "evidence": [
- {
- "name": "ACL Control",
- "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
- "urls": [
- {
- "name": "POOL_ADMIN role",
- "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
- "type": "docs"
- },
- {
- "name": "ACLManager",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 7d7ee44..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index cb89d8e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "Token holders direct treasury via governance.",
- "urls": [
- {
- "name": "Treasury docs",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Fee Sources",
- "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
- "urls": [
- {
- "name": "mintToTreasury (PoolLogic)",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
- "type": "github"
- },
- {
- "name": "Flashloan premium",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
- "type": "github"
- },
- {
- "name": "Liquidation fee",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
deleted file mode 100644
index 6bfa4a9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 92845b9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
deleted file mode 100644
index 5f8b629..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aave/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
deleted file mode 100644
index 5ca27bd..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
deleted file mode 100644
index dad8ff0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
deleted file mode 100644
index ccc8eba..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
deleted file mode 100644
index e86b6c4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
deleted file mode 100644
index bc7fd01..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Legal",
- "url": "https://aero.drome.eth.link/legal",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
deleted file mode 100644
index e33118a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
deleted file mode 100644
index af8ead8..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "USPTO Report",
- "url": "https://uspto.report/TM/99083103",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
deleted file mode 100644
index 2c8fa4d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index f854e83..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "status": "warning",
- "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
- "evidence": [
- {
- "name": "Fee Manager Role",
- "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
- "urls": [
- {
- "name": "Safe (Fee Manager)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-SlipStream Fees",
- "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
- "urls": [
- {
- "name": "PoolFactory: FeeManager",
- "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "SlipStream Fees",
- "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
- "urls": [
- {
- "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
- "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
- "type": "explorer"
- },
- {
- "name": "SwapFeeModule: setCustomFee",
- "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index de6f75c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
- "evidence": [
- {
- "name": "Team Rate",
- "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
- "urls": [
- {
- "name": "Safe (Team)",
- "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
- "type": "explorer"
- },
- {
- "name": "Team Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
- "type": "github"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
- "urls": [
- {
- "name": "Governor (Safe)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
- "type": "explorer"
- },
- {
- "name": "Emission Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index c6dac94..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
- "evidence": [
- {
- "name": "Voting System",
- "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "VotingEscrow",
- "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
- "type": "explorer"
- },
- {
- "name": "Voter",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Council",
- "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
- "urls": [
- {
- "name": "EmergencyCouncil",
- "url": "https://aerodrome.limited/pages/security.html",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 3e17d2e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contract Addresses",
- "url": "https://aerodrome.finance/security",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 2c27da6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
- "evidence": [
- {
- "name": "Emergency Council",
- "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
- "urls": [
- {
- "name": "Voter: emergencyCouncil",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
- "type": "explorer"
- },
- {
- "name": "EmergencyCouncil",
- "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 0dfcfda..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "status": "positive",
- "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
- "evidence": [
- {
- "name": "Minter Contract",
- "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
- "urls": [
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
- "urls": [
- {
- "name": "Minter Emission Increase (Epochs 1-14)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
- "type": "github"
- },
- {
- "name": "Minter Emission Decay",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
- "type": "github"
- }
- ]
- },
- {
- "name": "Growth Emissions",
- "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
- "urls": [
- {
- "name": "Growth Emissions Formula",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
- "type": "github"
- }
- ]
- },
- {
- "name": "Team Emission Rate",
- "summary": "Currently set to 0% of total weekly emissions.",
- "urls": [
- {
- "name": "Team Emission Rate",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index f04a477..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
deleted file mode 100644
index 98d089b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
deleted file mode 100644
index 09489eb..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
- "evidence": [
- {
- "name": "Growth Emissions",
- "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
- "urls": [
- {
- "name": "Growth Transfer to RewardDistributor",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
- "type": "github"
- },
- {
- "name": "RewardsDistributor Claim",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
- "type": "github"
- }
- ]
- },
- {
- "name": "Non-Slipstream Trading Fees",
- "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
- "urls": [
- {
- "name": "Gauge Deposit Logic",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
- "type": "github"
- },
- {
- "name": "Swap Fee Accrued",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
- "type": "github"
- },
- {
- "name": "Voter calling Gauge to claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed by Gauge on PoolFees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
- "type": "github"
- }
- ]
- },
- {
- "name": "Slipstream Trading Fees",
- "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
- "urls": [
- {
- "name": "Fees Split",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
- "type": "github"
- },
- {
- "name": "Gauge Fees calculated separately",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
- "type": "github"
- },
- {
- "name": "Non Staked LP Fees collected",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
- "type": "github"
- },
- {
- "name": "Gauge Fees to feesVotingReward",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
- "type": "github"
- },
- {
- "name": "veAERO voters claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 463eee0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
- "evidence": [
- {
- "name": "Locking Control",
- "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
- "urls": [
- {
- "name": "VotingEscrow create_lock",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
- "urls": [
- {
- "name": "Voter vote function",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
- "type": "github"
- },
- {
- "name": "Gauge getReward",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index ee52be6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 3c85ba0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
deleted file mode 100644
index 41079e6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 13be4d3..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contracts (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts",
- "type": "github"
- },
- {
- "name": "Aerodrome Slipstream (GitHub)",
- "url": "https://github.com/aerodrome-finance/slipstream",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
deleted file mode 100644
index a7da64f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/aero/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token (Basescan)",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Aero.sol Source (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
deleted file mode 100644
index 40ad32e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
deleted file mode 100644
index b5fa2a4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 5f677ee..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
deleted file mode 100644
index 74fb5a8..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
deleted file mode 100644
index 7a6be45..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve Legal",
- "url": "https://www.curve.finance/dex/ethereum/legal",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
deleted file mode 100644
index a17a25c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
deleted file mode 100644
index a7441b2..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Swiss Trademark Registry",
- "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
deleted file mode 100644
index 5e84784..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index b8d6f95..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
- "evidence": [
- {
- "name": "Add/Kill Gauge",
- "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
- "urls": [
- {
- "name": "Gauge Kill Implementation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5704953..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Standard Transfer",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
- "type": "github"
- },
- {
- "name": "ERC20CRV.vy Metadata Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 5617c7a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aragon Voting Contract",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
- "type": "explorer"
- },
- {
- "name": "Agent Contract",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
- "type": "explorer"
- },
- {
- "name": "CRV Token: Admin is set to Agent",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 2e50f5a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "status": "positive",
- "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
- "evidence": [
- {
- "name": "Core Contracts",
- "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
- "urls": [
- {
- "name": "CRV Token (Admin: Agent)",
- "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
- "type": "explorer"
- },
- {
- "name": "GaugeController (Admin: Agent)",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent Contract",
- "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Voting Contract",
- "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index c84b85c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "positive",
- "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
- "evidence": [
- {
- "name": "Gauge Addition",
- "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
- "urls": [
- {
- "name": "GaugeController: admin is Agent",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Pool Factory Ownership",
- "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
- "urls": [
- {
- "name": "Curve Pool Factory: admin is OwnerProxy",
- "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index ef408a0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
- "evidence": [
- {
- "name": "Supply Schedule",
- "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- },
- {
- "name": "ERC20CRV.vy Yearly Epoch Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Access",
- "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
- "urls": [
- {
- "name": "ERC20CRV.vy Mint Access",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
- "type": "github"
- },
- {
- "name": "Minter.vy Gauge Validation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 0f5537c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Source",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
deleted file mode 100644
index 6260c77..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
deleted file mode 100644
index 66103a1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "status": "positive",
- "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
- "evidence": [
- {
- "name": "CRV Emissions Rewards",
- "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
- "urls": [
- {
- "name": "working_balance reward calculation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
- "type": "github"
- }
- ]
- },
- {
- "name": "Pool Rewards in crvUSD",
- "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
- "urls": [
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Borrow Rewards in crvUSD",
- "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
- "urls": [
- {
- "name": "FeeSplitter",
- "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 5989d6d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "status": "positive",
- "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
- "evidence": [
- {
- "name": "Pool Fee Control",
- "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
- "urls": [
- {
- "name": "DAI/USDC/USDT Pool: commit_new_fee",
- "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burner Attachment",
- "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
- "urls": [
- {
- "name": "StableSwapProxy: set_burner",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burn Execution",
- "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
- "urls": [
- {
- "name": "StableSwapProxy: burn",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index ed5f6d9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index a1ca859..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
- "evidence": [
- {
- "urls": [
- {
- "name": "veCRV Revenue Share (Docs)",
- "url": "https://docs.curve.finance/user/vecrv/revenue",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
deleted file mode 100644
index 8a84410..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index dfa266b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Curve DAO protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve DAO Contracts (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
deleted file mode 100644
index 88abb06..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/crv/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Token (Etherscan)",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- },
- {
- "name": "ERC20CRV.vy Source (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
deleted file mode 100644
index 99cf88c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
deleted file mode 100644
index 6302a56..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
- "evidence": [
- {
- "name": "Token Allocation",
- "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
- "urls": [
- {
- "name": "Tokenomist.ai - ENA",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- },
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 2906392..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
- "evidence": [
- {
- "name": "Vesting Schedules",
- "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
- "urls": [
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- },
- {
- "name": "Tokenomist.ai - ENA Vesting",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
deleted file mode 100644
index 692c514..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
deleted file mode 100644
index 09259c1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
deleted file mode 100644
index 5df1cf4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "warning",
- "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena GitHub License",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
deleted file mode 100644
index 3ea8daa..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
deleted file mode 100644
index aa732f2..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 85c8a35..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
- "evidence": [
- {
- "name": "Privileged Roles (per Multisig Matrix)",
- "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Gatekeeper Powers",
- "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
- "urls": [
- {
- "name": "`disableMintRedeem()` (line 278)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
- "type": "github"
- },
- {
- "name": "`removeMinterRole()` (line 339)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
- "type": "github"
- },
- {
- "name": "`removeRedeemerRole()` (line 345)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index ea421fc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "warning",
- "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
- "evidence": [
- {
- "name": "sENA/sUSDe Blacklist Capabilities",
- "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
- "urls": [
- {
- "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
- "type": "github"
- },
- {
- "name": "`redistributeLockedAmount()` (lines 106-127)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
- "type": "github"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index f3a9970..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "warning",
- "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
- "evidence": [
- {
- "name": "Snapshot Governance",
- "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
- "urls": [
- {
- "name": "Snapshot Space",
- "url": "https://snapshot.org/#/ethenagovernance.eth",
- "type": "docs"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Multisig Execution",
- "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
- "urls": [
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 967e44f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "status": "warning",
- "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
- "evidence": [
- {
- "name": "Non-Upgradeable Contracts",
- "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Upgradeable Contracts (sENA and rsENA)",
- "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
- "urls": [
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "sENA Implementation",
- "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
- "type": "explorer"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Implementation",
- "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index b840de7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "status": "warning",
- "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
- "evidence": [
- {
- "name": "Multisig Control Matrix",
- "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- },
- {
- "name": "Hot Swap Multisig",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "Trading Operations Multisig",
- "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
- "type": "explorer"
- },
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "EOA Control Points",
- "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
- "urls": [
- {
- "name": "StakingRewardsDistributor Operator (EOA)",
- "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
- "type": "explorer"
- },
- {
- "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index ff12bcc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
- "evidence": [
- {
- "name": "Mint Function",
- "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
- "urls": [
- {
- "name": "ENA.sol `mint()` function (lines 42-49)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
- "type": "github"
- },
- {
- "name": "ENA Token totalSupply",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 6f0354c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
- "evidence": [
- {
- "name": "ENA Non-Upgradeability Verification",
- "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
- "urls": [
- {
- "name": "ENA.sol Source",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
deleted file mode 100644
index 12be505..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
deleted file mode 100644
index 35bf37b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "status": "warning",
- "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
- "evidence": [
- {
- "name": "Fee Switch Status",
- "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "USDe Token (verify totalSupply)",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
- "type": "explorer"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Ethena Network Airdrops",
- "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
- "urls": [
- {
- "name": "Ethena Network Documentation",
- "url": "https://docs.ethena.fi/ethena-network",
- "type": "docs"
- }
- ]
- },
- {
- "name": "rsENA (Restaked ENA via Symbiotic)",
- "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
- "urls": [
- {
- "name": "rsENA Contract",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
- "type": "explorer"
- },
- {
- "name": "ENA Staking Documentation",
- "url": "https://docs.ethena.fi/ena",
- "type": "docs"
- },
- {
- "name": "Mellow Finance rsENA Vault",
- "url": "https://app.mellow.finance/vaults/ethereum-rsena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 1e775e7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "warning",
- "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
- "evidence": [
- {
- "name": "ENA Value Accrual Controls",
- "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
- "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Tokenholder Cannot Force Activation",
- "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index dd3c133..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "warning",
- "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
- "evidence": [
- {
- "name": "USDe Yield Sources",
- "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
- "urls": [
- {
- "name": "Coin Metrics Analysis (USDe Yield Sources)",
- "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Yield Distribution Flow",
- "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
- "urls": [
- {
- "name": "`transferInRewards()` (lines 88-94)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
- "type": "github"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index cec61a8..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
- "evidence": [
- {
- "name": "Revenue Flow",
- "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
- "urls": [
- {
- "name": "Key Addresses Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-addresses",
- "type": "docs"
- },
- {
- "name": "Hot Swap Multisig (revenue receiver)",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Reserve Fund (Negative Funding Backup)",
- "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
- "urls": [
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
deleted file mode 100644
index 9ae768f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index f2d5e2d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
- "evidence": [
- {
- "name": "Verified Contracts",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "GitHub Repository",
- "urls": [
- {
- "name": "Ethena Public Assets (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets",
- "type": "github"
- }
- ]
- },
- {
- "name": "Audits",
- "urls": [
- {
- "name": "Code4rena 2023 Audit",
- "url": "https://github.com/code-423n4/2023-10-ethena",
- "type": "github"
- },
- {
- "name": "Code4rena 2024 Audit",
- "url": "https://github.com/code-423n4/2024-11-ethena-labs",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
deleted file mode 100644
index 832ff34..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ena/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "ENA.sol Source (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
deleted file mode 100644
index e97bf51..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
deleted file mode 100644
index a95862d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
- "evidence": [
- {
- "name": "Token Allocation",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 2fbf530..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "warning",
- "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "DefiLlama Unlocks",
- "url": "https://defillama.com/unlocks/ether.fi",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
deleted file mode 100644
index e2152cc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
deleted file mode 100644
index 45c898e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
- "evidence": [
- {
- "name": "Legal Entity",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
deleted file mode 100644
index bfa11ce..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "warning",
- "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
- "evidence": [
- {
- "name": "License",
- "urls": [
- {
- "name": "GitHub Repository",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Terms of Use (Non-Contract IP)",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
deleted file mode 100644
index c573eef..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "status": "warning",
- "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
- "evidence": [
- {
- "name": "Trademark Ownership",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
deleted file mode 100644
index ca55eb6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 5b3acc3..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
- "evidence": [
- {
- "name": "Pause Authority",
- "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
- "urls": [
- {
- "name": "EtherFiAdmin Pause Function",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 2c44b78..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "warning",
- "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
- "evidence": [
- {
- "name": "Token Analysis",
- "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- },
- {
- "name": "Arbitrum ETHFI (Upgradeable)",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI (Upgradeable)",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 472575d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "at_risk",
- "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "evidence": [
- {
- "name": "Governance Structure",
- "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "urls": [
- {
- "name": "Governance Info",
- "url": "https://vote.ether.fi/info",
- "type": "docs"
- },
- {
- "name": "Governance Resources",
- "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
- "type": "docs"
- },
- {
- "name": "Governance Roadmap",
- "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index a68cded..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "warning",
- "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
- "urls": [
- {
- "name": "RoleRegistry Upgrade Check",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
- "type": "github"
- },
- {
- "name": "LiquidityPool Upgrade Authorization",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
- "type": "github"
- }
- ]
- },
- {
- "name": "RoleRegistry Owner",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 0936aa7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
- "evidence": [
- {
- "name": "RoleRegistry Owner (Upgrade Timelock)",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock (72h)",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Two-Timelock System",
- "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
- "urls": [
- {
- "name": "Upgrade Admin (4-of-7)",
- "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
- "type": "explorer"
- },
- {
- "name": "Operating Timelock (8h)",
- "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
- "type": "explorer"
- },
- {
- "name": "Operating Admin (3-of-5)",
- "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 98f9307..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
- "evidence": [
- {
- "name": "Fixed Supply",
- "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 4024ae0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "warning",
- "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
- "evidence": [
- {
- "name": "Mainnet Token (Not Upgradeable)",
- "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "L2 Tokens (Upgradeable, No Timelock)",
- "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
- "urls": [
- {
- "name": "Arbitrum ETHFI",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Arbitrum Admin (3-of-6)",
- "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- },
- {
- "name": "Base Admin (3-of-6)",
- "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
deleted file mode 100644
index aad827f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
deleted file mode 100644
index 84671dc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "positive",
- "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
- "evidence": [
- {
- "name": "Buyback Program",
- "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
- "urls": [
- {
- "name": "ETHFI Buyback Program",
- "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
- "type": "docs"
- },
- {
- "name": "Buyback History (Dune)",
- "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
- "type": "docs"
- },
- {
- "name": "sETHFI Staking",
- "url": "https://www.ether.fi/app/ethfi",
- "type": "docs"
- },
- {
- "name": "Buyback Wallet (1-of-5)",
- "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 0e84742..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
- "evidence": [
- {
- "name": "Fee Configuration",
- "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
- "urls": [
- {
- "name": "LiquidityPool Fee Functions",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index be71a37..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 1e800d0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
deleted file mode 100644
index 14c61d2..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 17de7d2..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
- "evidence": [
- {
- "name": "Protocol Source & Audits",
- "urls": [
- {
- "name": "etherfi-protocol/smart-contracts",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
deleted file mode 100644
index 04155b4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ethfi/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
- "evidence": [
- {
- "name": "Token Verification",
- "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
- "urls": [
- {
- "name": "Etherscan Verified Source",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
deleted file mode 100644
index 01ef2fb..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
deleted file mode 100644
index f0ea33e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
deleted file mode 100644
index b781f77..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
deleted file mode 100644
index 4da96c8..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
deleted file mode 100644
index 0ba589a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
deleted file mode 100644
index 0ba589a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
deleted file mode 100644
index ebae64a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UK IPO Trademark Journal",
- "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
- "type": "docs"
- },
- {
- "name": "Lido Logo",
- "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
deleted file mode 100644
index 5a79c2d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 30793e1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
- "evidence": [
- {
- "name": "Guardian Role",
- "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
- "urls": [
- {
- "name": "DepositSecurityModule",
- "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
- "type": "explorer"
- },
- {
- "name": "Lido.sol deposit logic",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
- "type": "github"
- },
- {
- "name": "Guardians use automated software",
- "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Guardian Accountability",
- "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
- "urls": [
- {
- "name": "Guardian Committee Membership",
- "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
- "type": "docs"
- },
- {
- "name": "Guardians cannot control stake allocation",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index adf749d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
- "evidence": [
- {
- "name": "Burn Capability",
- "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
- "urls": [
- {
- "name": "MiniMeToken.destroyTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
- "type": "github"
- },
- {
- "name": "Aragon ACL",
- "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Transfer Control",
- "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
- "urls": [
- {
- "name": "MiniMeToken.enableTransfers",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 3b27084..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "status": "positive",
- "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
- "evidence": [
- {
- "name": "Governance 1A",
- "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- },
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Governance 1B",
- "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Easy Track",
- "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
- "urls": [
- {
- "name": "Easy Track Interface",
- "url": "https://easytrack.lido.fi/",
- "type": "docs"
- },
- {
- "name": "Easy Track Guide",
- "url": "https://docs.lido.fi/guides/easy-track-guide",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index a3a5da8..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "positive",
- "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
- "evidence": [
- {
- "name": "Upgradeable Contracts",
- "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-upgradeable Contracts",
- "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
- "urls": [
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index deeabc7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
- "evidence": [
- {
- "name": "Voting",
- "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent",
- "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "TokenManager",
- "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "StakingRouter",
- "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index a476ae1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
- "evidence": [
- {
- "name": "Minting Path",
- "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
- "urls": [
- {
- "name": "MiniMeToken.generateTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 2f65c1e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
- "evidence": [
- {
- "name": "Token Contract",
- "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
- "urls": [
- {
- "name": "LDO Token",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Controller Upgrade Path",
- "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
deleted file mode 100644
index 15c6eb7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
deleted file mode 100644
index 558e4a9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "status": "positive",
- "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
- "evidence": [
- {
- "name": "Treasury Fee Flow",
- "urls": [
- {
- "name": "StakingRouter (read contract)",
- "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
- "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
- "type": "github"
- }
- ]
- },
- {
- "name": "Buyback Program",
- "urls": [
- {
- "name": "stETH/LDO Buyback Proposal",
- "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
- "type": "docs"
- },
- {
- "name": "stETH/LDO Buyback Snapshot Vote",
- "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
- "type": "vote"
- },
- {
- "name": "NEST",
- "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
- "type": "docs"
- },
- {
- "name": "Liquid buybacks research",
- "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 0b6d587..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "StakingRouter add/update",
- "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 57a1dff..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index f1662c6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "positive",
- "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
- "urls": [
- {
- "name": "Agent (Treasury)",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
deleted file mode 100644
index 3fa336c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index cefc201..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Lido core protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Core Contracts (GitHub)",
- "url": "https://github.com/lidofinance/core",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
deleted file mode 100644
index 713a79f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ldo/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LDO Token (Etherscan)",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- },
- {
- "name": "MiniMeToken Source (GitHub)",
- "url": "https://github.com/aragon/minime",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
deleted file mode 100644
index 18de867..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
deleted file mode 100644
index 110aef5..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 836aa8d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LockupContractFactory (Etherscan)",
- "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
- "type": "explorer"
- },
- {
- "name": "CommunityIssuance (Etherscan)",
- "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
deleted file mode 100644
index df30ae9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
deleted file mode 100644
index cad5d6b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "partial",
- "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity Runs on Decentralized Frontends - Official Blog",
- "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
- "type": "website"
- },
- {
- "name": "Frontend Operators Page",
- "url": "https://www.liquity.org/frontend-operators",
- "type": "website"
- },
- {
- "name": "Liquity Launch Details (AG does not run frontend)",
- "url": "https://www.liquity.org/blog/liquity-launch-details",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
deleted file mode 100644
index 782d787..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "fail",
- "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Licensing Liquity V2 - Official Blog",
- "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
- "type": "website"
- },
- {
- "name": "Liquity V2 Core LICENSE File (GitHub)",
- "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
- "type": "github"
- },
- {
- "name": "What's New in Liquity V2 - Bankless",
- "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
deleted file mode 100644
index c87d208..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status": "fail",
- "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity AG - Crunchbase Company Profile",
- "url": "https://www.crunchbase.com/organization/liquity-1d3e",
- "type": "website"
- },
- {
- "name": "Liquity - Tracxn Company Profile",
- "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
- "type": "website"
- },
- {
- "name": "Team Page - Liquity.org",
- "url": "https://www.liquity.org/team",
- "type": "website"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
deleted file mode 100644
index 1893248..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 8bca964..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "Access Gating",
- "status": "positive",
- "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index f76566d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY token's implementation code",
- "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index ff7b2b4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index c6e33ce..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 02906f9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index eb35281..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 9495e41..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token Source",
- "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
deleted file mode 100644
index 9ad32dc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
deleted file mode 100644
index f67d587..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "status": "positive",
- "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
- "type": "github"
- },
- {
- "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
- "type": "github"
- },
- {
- "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
- "url": "https://docs.liquity.org/v2-faq/lqty-staking",
- "type": "docs"
- },
- {
- "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
- "type": "github"
- },
- {
- "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
- "type": "github"
- },
- {
- "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index c9c1666..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 54f5685..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 40dc2ab..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Docs",
- "url": "https://www.liquity.org/blog/liquity-v2-is-live",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
deleted file mode 100644
index 53b7a50..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 0170fd6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Liquity protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Core (GitHub)",
- "url": "https://github.com/liquity/bold",
- "type": "github"
- },
- {
- "name": "Liquity V2 Governance (GitHub)",
- "url": "https://github.com/liquity/V2-gov",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
deleted file mode 100644
index c4daa88..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/lqty/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token (Etherscan)",
- "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
- "type": "explorer"
- },
- {
- "name": "LQTYToken.sol Source (GitHub)",
- "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
deleted file mode 100644
index 6ff8f37..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
deleted file mode 100644
index b811b98..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "at_risk",
- "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
- "evidence": [
- {
- "name": "Team Holdings",
- "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
- "urls": [
- {
- "name": "Team Multisig holdings",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
deleted file mode 100644
index dc07df0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
- "evidence": [
- {
- "name": "Documented Schedule",
- "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
- "urls": [
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- },
- {
- "name": "CoinList - ONDO Community Sale",
- "url": "https://coinlist.co/ondo",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
deleted file mode 100644
index cdc655c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
deleted file mode 100644
index e5575dc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Interface Services",
- "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
deleted file mode 100644
index f3632d4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
- "evidence": [
- {
- "name": "BUSL-1.1 Source Headers",
- "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
- "urls": [
- {
- "name": "USDY source SPDX header",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
- "type": "github"
- },
- {
- "name": "rOUSG source SPDX header",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
- "type": "github"
- },
- {
- "name": "BUSL-1.1 license text",
- "url": "https://spdx.org/licenses/BUSL-1.1.html",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
deleted file mode 100644
index d53d771..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Proprietary Rights",
- "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
deleted file mode 100644
index c2dfc4d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 3a6f103..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
- "evidence": [
- {
- "name": "OUSG Transfer Restrictions",
- "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
- "urls": [
- {
- "name": "OUSG Contract (KYC enforcement)",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "OUSG KYC check (source)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
- "type": "github"
- },
- {
- "name": "KYCRegistry",
- "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "USDY Transfer Restrictions",
- "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
- "urls": [
- {
- "name": "USDY restrictions (source)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
- "type": "github"
- },
- {
- "name": "USDY Contract",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index a5dc7f1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
- "evidence": [
- {
- "name": "No Censorship Capability",
- "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Source code (ondo-v1)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 4c5b928..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
- "evidence": [
- {
- "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
- "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (OUSG admin)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin owner",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index 1cee348..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
- "evidence": [
- {
- "name": "OUSG/USDY (Team-Controlled)",
- "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
- "urls": [
- {
- "name": "OUSG Proxy",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "OUSG ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY Proxy",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Polygon OUSG ProxyAdmin Owner",
- "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
- "type": "explorer"
- },
- {
- "name": "Mantle USDY ProxyAdmin Owner",
- "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
- "type": "explorer"
- },
- {
- "name": "Arbitrum USDY ProxyAdmin Owner",
- "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Global Markets (Team-Controlled via TimelockController)",
- "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
- "urls": [
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 8e32210..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
- "evidence": [
- {
- "name": "Team-Controlled Roles (ONDO Token)",
- "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
- "urls": [
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (OUSG/USDY)",
- "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "rOUSG",
- "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "rUSDY",
- "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (Global Markets)",
- "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- },
- {
- "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
- "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
- "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (EOA)",
- "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
- "type": "explorer"
- },
- {
- "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
- "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index fb8a3ba..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
- "evidence": [
- {
- "name": "Current Supply",
- "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
- "urls": [
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Mint Function Exists",
- "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
- "urls": [
- {
- "name": "ONDO Token (verified source)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (MINTER_ROLE holder)",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 578d308..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
- "evidence": [
- {
- "name": "ONDO Token Roles",
- "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Contract Source Note",
- "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
- "urls": [
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
deleted file mode 100644
index f11d02f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
deleted file mode 100644
index 7939a86..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "at_risk",
- "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
- "evidence": [
- {
- "name": "Product Economics vs ONDO Holder Accrual",
- "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index ee2c0ab..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "at_risk",
- "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
- "evidence": [
- {
- "name": "OUSG/USDY Price Oracles (Company-Controlled)",
- "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
- "urls": [
- {
- "name": "OUSG Oracle",
- "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
- "type": "explorer"
- },
- {
- "name": "USDY Oracle",
- "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
- "type": "explorer"
- },
- {
- "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
- "type": "github"
- },
- {
- "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets (Company-Controlled via TimelockController)",
- "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 1c5bd2f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "status": "warning",
- "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
- "tags": [
- "Reference"
- ],
- "evidence": [
- {
- "name": "Ondo Product Economics",
- "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "USDY Issuer / Ondo Finance Relationship",
- "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Global Markets Revenue",
- "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
- "urls": [
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 4157d3a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "at_risk",
- "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
- "evidence": [
- {
- "name": "No Treasury Identified",
- "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
- "urls": [
- {
- "name": "Ondo DAO Proposals",
- "url": "https://www.tally.xyz/gov/ondo-dao",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
deleted file mode 100644
index 9d49936..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index dc042a9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "status": "positive",
- "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
- "evidence": [
- {
- "name": "OUSG/USDY",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "USDY GitHub",
- "url": "https://github.com/ondoprotocol/usdy",
- "type": "github"
- },
- {
- "name": "Audit code (Code4rena)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "USDonManager",
- "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
deleted file mode 100644
index 69b23f7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/ondo/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ONDO Token (Etherscan verified)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
deleted file mode 100644
index d46c247..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not been able to verify the concentration of holdings.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
deleted file mode 100644
index 14854bc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify the concentration of holdings.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
deleted file mode 100644
index ea1ed76..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
- "evidence": [
- {
- "name": "Vesting Contracts",
- "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
- "urls": [
- {
- "name": "Vest Contract",
- "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
deleted file mode 100644
index 5919811..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
deleted file mode 100644
index ab1dfb9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
- "evidence": [
- {
- "name": "Open Source Frontends",
- "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
- "urls": [
- {
- "name": "Governance Portal Source",
- "url": "https://github.com/sky-ecosystem/governance-portal-v2",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
deleted file mode 100644
index aa47403..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
- "evidence": [
- {
- "name": "AGPL-3.0 License",
- "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
- "urls": [
- {
- "name": "License File",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
deleted file mode 100644
index 7dda59a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "status": "warning",
- "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
- "evidence": [
- {
- "name": "Skybase International Terms of Use",
- "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
- "type": "docs"
- }
- ]
- },
- {
- "name": "DAI Foundation",
- "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
- "urls": [
- {
- "name": "Foundation Website",
- "url": "https://daifoundation.org",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
deleted file mode 100644
index 17b64c3..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 2a8eb2b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
- "evidence": [
- {
- "name": "Emergency Shutdown",
- "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
- "urls": [
- {
- "name": "ESM source code",
- "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
- "type": "github"
- },
- {
- "name": "ESM contract on Etherscan",
- "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "No Arbitrary Pause",
- "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
- "urls": []
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5515ba9..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
- "evidence": [
- {
- "name": "No Censorship Functions",
- "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
- "urls": [
- {
- "name": "Transfer Functions (L96-135)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 210d15f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
- "evidence": [
- {
- "name": "Governance Workflow",
- "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
- "urls": [
- {
- "name": "Voting Contract",
- "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
- "type": "explorer"
- },
- {
- "name": "plot() delay enforcement (L111-116)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
- "type": "github"
- }
- ]
- },
- {
- "name": "Timelock Contract",
- "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
- "urls": [
- {
- "name": "Pause Proxy (Etherscan)",
- "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
- "type": "explorer"
- },
- {
- "name": "exec() function (L124-136)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index b5ad61d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
- "evidence": [
- {
- "name": "Immutable Core",
- "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
- "urls": [
- {
- "name": "Vat source code",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
- "type": "github"
- },
- {
- "name": "SKY token source code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Stablecoins",
- "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
- "urls": [
- {
- "name": "USDS upgrade authorization",
- "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
- "type": "github"
- },
- {
- "name": "sUSDS source code",
- "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index b56bd54..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
- "evidence": [
- {
- "name": "Core Contracts Controlled by Governance",
- "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
- "urls": [
- {
- "name": "Vat wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
- "type": "explorer"
- },
- {
- "name": "Vow wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- },
- {
- "name": "SKY wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Controls",
- "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
- "urls": [
- {
- "name": "Mom authority pattern (source)",
- "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
- "type": "github"
- },
- {
- "name": "OSM_MOM — verify authority()",
- "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 2655fba..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
- "evidence": [
- {
- "name": "Minting Restricted to Governance",
- "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
- "urls": [
- {
- "name": "mint() function (L146-154)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
- "type": "github"
- }
- ]
- },
- {
- "name": "MKR Conversion",
- "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
- "urls": [
- {
- "name": "rate() returns 24000",
- "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
- "type": "explorer"
- },
- {
- "name": "Immutable rate declaration",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 8678d04..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
- "evidence": [
- {
- "name": "Non-Upgradeable Token",
- "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
- "urls": [
- {
- "name": "SKY Token Contract",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
deleted file mode 100644
index 0d3d99d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
deleted file mode 100644
index 5595264..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "status": "positive",
- "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
- "evidence": [
- {
- "name": "Smart Burn Engine",
- "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
- "urls": [
- {
- "name": "Splitter contract",
- "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
- "type": "explorer"
- },
- {
- "name": "Flapper (buyback executor)",
- "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
- "type": "explorer"
- },
- {
- "name": "Flapper source code",
- "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
- "type": "github"
- },
- {
- "name": "Smart Burn Engine Dashboard",
- "url": "https://info.sky.money/smart-burn-engine",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
- "urls": [
- {
- "name": "Stability fee accrual",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
- "type": "github"
- },
- {
- "name": "Surplus routing to flapper",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index bdb8dc4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
- "evidence": [
- {
- "name": "Fee Rate Control",
- "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
- "urls": [
- {
- "name": "Jug fee configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
- "type": "github"
- },
- {
- "name": "Jug contract",
- "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Surplus Buffer Control",
- "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
- "urls": [
- {
- "name": "Vow hump configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
- "type": "github"
- },
- {
- "name": "Vow contract — read hump",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index a541c0a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
- "tags": [
- "Reference"
- ],
- "evidence": [
- {
- "name": "Foundation Independence",
- "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
- "urls": [
- {
- "name": "Foundation Mandate",
- "url": "https://daifoundation.org/mandate",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 832c737..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "positive",
- "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
- "evidence": [
- {
- "name": "Onchain Treasury",
- "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
deleted file mode 100644
index 7655c73..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 648a473..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
- "evidence": [
- {
- "name": "Open Source Repositories",
- "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
- "urls": [
- {
- "name": "Core Protocol",
- "url": "https://github.com/sky-ecosystem/dss",
- "type": "github"
- },
- {
- "name": "Contract Registry",
- "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
deleted file mode 100644
index 0d71b8d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/sky/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
- "evidence": [
- {
- "name": "Verified Source",
- "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
- "urls": [
- {
- "name": "Source Code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- },
- {
- "name": "Verified on Etherscan",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
deleted file mode 100644
index 69c4a54..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
deleted file mode 100644
index 110aef5..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
deleted file mode 100644
index aa8e115..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "status": "positive",
- "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
- "evidence": [
- {
- "name": "TreasuryVester Contracts",
- "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
- "urls": [
- {
- "name": "TreasuryVester Code",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
- "type": "github"
- },
- {
- "name": "TreasuryVester 1",
- "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 2",
- "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 3",
- "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 4",
- "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
deleted file mode 100644
index 32abe85..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
deleted file mode 100644
index 83546db..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Terms of Service",
- "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
deleted file mode 100644
index 20a3717..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "warning",
- "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
deleted file mode 100644
index def920e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Trademark Guidelines",
- "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
deleted file mode 100644
index a1bf5bc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index 81720c4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "positive",
- "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index 5f6c7c5..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 4ba972f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
- "evidence": [
- {
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- },
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index d3f6dd6..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
- "evidence": [
- {
- "name": "Non-upgradeable Protocol Contracts",
- "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
- "urls": [
- {
- "name": "V2 Factory Create2",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
- "type": "github"
- },
- {
- "name": "V3 Pool Protection",
- "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
- "type": "github"
- },
- {
- "name": "V4 PoolManager: Singleton",
- "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Governance Contract",
- "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 981f1bb..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
- "evidence": [
- {
- "name": "V2 Factory",
- "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
- "urls": [
- {
- "name": "V2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Factory",
- "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
- "urls": [
- {
- "name": "V3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V4 PoolManager",
- "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
- "urls": [
- {
- "name": "V4PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "UNI Token",
- "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
- "urls": [
- {
- "name": "UNI Token",
- "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
- "type": "explorer"
- },
- {
- "name": "Timelock (deployed minter)",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 2b18768..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "status": "positive",
- "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
- "evidence": [
- {
- "name": "Inflation Cap",
- "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
- "urls": [
- {
- "name": "Mint once per year logic",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
- "type": "github"
- },
- {
- "name": "2% mint cap",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Control",
- "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index e50c26f..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol Source",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- },
- {
- "name": "Etherscan",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
deleted file mode 100644
index 3c8d23e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
deleted file mode 100644
index 9360e90..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "status": "positive",
- "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
- "evidence": [
- {
- "name": "V2 Fees",
- "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
- "urls": [
- {
- "name": "UniswapV2Pool: feeTo",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Pool: Fee Destination",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "V3 Fees",
- "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
- "urls": [
- {
- "name": "V3FeeAdapter",
- "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: collectProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fees",
- "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
- "urls": [
- {
- "name": "V4 PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- },
- {
- "name": "V4 PoolManager: CollectProtocolFees",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
- "type": "github"
- }
- ]
- },
- {
- "name": "Burn Mechanism",
- "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
- "urls": [
- {
- "name": "FirePit 4000 UNI Requirement",
- "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index f500fa5..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "status": "positive",
- "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
- "evidence": [
- {
- "name": "V2 Fee Control",
- "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Fee Control",
- "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
- "urls": [
- {
- "name": "UniswapV3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: setFeeProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fee Control",
- "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
- "urls": [
- {
- "name": "PoolManager(V4): setProtocolFee",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 8c00c48..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
- "evidence": [
- {
- "urls": [
- {
- "name": "DUNI Proposal",
- "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index 2afc7f0..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
deleted file mode 100644
index 40ae2ee..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 5d637b5..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "status": "positive",
- "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap V2 Core (GitHub)",
- "url": "https://github.com/Uniswap/v2-core",
- "type": "github"
- },
- {
- "name": "Uniswap V3 Core (GitHub)",
- "url": "https://github.com/Uniswap/v3-core",
- "type": "github"
- },
- {
- "name": "Uniswap V4 Core (GitHub)",
- "url": "https://github.com/Uniswap/v4-core",
- "type": "github"
- },
- {
- "name": "UniswapX (GitHub)",
- "url": "https://github.com/Uniswap/UniswapX",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
deleted file mode 100644
index 33eea24..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/uni/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UNI Token (Etherscan)",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- },
- {
- "name": "Uni.sol Source (GitHub)",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
deleted file mode 100644
index d1b94bc..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
- "tags": [
- "Metric 4"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
deleted file mode 100644
index 47c4744..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__concentration.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
- "evidence": [
- {
- "name": "veYB Supply",
- "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json b/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
deleted file mode 100644
index 9e11843..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/distribution/distribution__supply-schedule.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "status": "warning",
- "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
- "urls": [
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
deleted file mode 100644
index 6c4bba4..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
- "tags": [
- "Reference"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
deleted file mode 100644
index d5547e1..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__distribution.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "warning",
- "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YieldBasis Website",
- "url": "https://yieldbasis.com/",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
deleted file mode 100644
index 9374e87..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__licensing.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "warning",
- "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
- "evidence": [
- {
- "name": "License Analysis",
- "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
- "urls": [
- {
- "name": "yb-core contracts directory",
- "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
- "type": "github"
- },
- {
- "name": "Curve Licensing Vesting",
- "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json b/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
deleted file mode 100644
index 00e0821..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/offchain/offchain__trademark.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify trademark ownership.",
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
deleted file mode 100644
index 03c2d81..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
- "tags": [
- "Metric 1"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
deleted file mode 100644
index e2feb0c..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__access-gating.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
- "evidence": [
- {
- "name": "Exit Paths",
- "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
- "urls": [
- {
- "name": "VotingEscrow.withdraw",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
- "type": "github"
- },
- {
- "name": "FeeDistributor.claim",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
deleted file mode 100644
index e76cece..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__censorship.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "status": "positive",
- "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB.vy full source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
deleted file mode 100644
index 1b7a16e..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__governance-workflow.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "status": "positive",
- "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
- "evidence": [
- {
- "name": "Governance System",
- "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
- "urls": [
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- },
- {
- "name": "veYB (VotingEscrow)",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "TokenVoting Plugin",
- "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
- "type": "explorer"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.yieldbasis.com/user/governance",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
deleted file mode 100644
index e0368ef..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__protocol-upgrade.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
- "urls": [
- {
- "name": "Factory Contract",
- "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
- "type": "explorer"
- },
- {
- "name": "Factory.set_implementations",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
- "type": "github"
- },
- {
- "name": "MigrationFactoryOwner ADMIN immutable",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
deleted file mode 100644
index 93f7045..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__role-accountability.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "status": "positive",
- "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
- "evidence": [
- {
- "name": "DAO-Controlled Contracts",
- "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
- "urls": [
- {
- "name": "GaugeController",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- },
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "MigrationFactoryOwner",
- "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "veYB Owner (_yb.eth)",
- "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "set_transfer_clearance_checker",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
deleted file mode 100644
index 0203010..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__supply.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "positive",
- "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
- "evidence": [
- {
- "name": "Emission Mechanism",
- "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
- "urls": [
- {
- "name": "get_adjustment (minting rate)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
- "type": "github"
- },
- {
- "name": "YB.emit function",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
- "type": "github"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json b/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
deleted file mode 100644
index 788c4e7..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/onchain-ctrl/onchain-ctrl__token-upgrade.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
- "evidence": [
- {
- "name": "Token Ownership",
- "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
- "urls": [
- {
- "name": "YB Token Contract",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "renounce_ownership",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
deleted file mode 100644
index 689d6be..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
- "tags": [
- "Metric 2"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
deleted file mode 100644
index dd9e19d..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__active.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "status": "positive",
- "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
- "evidence": [
- {
- "name": "Fee Flow",
- "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
- "urls": [
- {
- "name": "LT.withdraw_admin_fees",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
- "type": "github"
- },
- {
- "name": "Factory.fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
- "type": "github"
- },
- {
- "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
- "type": "github"
- },
- {
- "name": "FeeDistributor Contract",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "veYB Documentation",
- "url": "https://docs.yieldbasis.com/user/veyb",
- "type": "docs"
- },
- {
- "name": "Fee Data (ValueVerse)",
- "url": "https://yb.valueverse.ai",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
deleted file mode 100644
index 8b8ce8b..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__mechanism.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "status": "positive",
- "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
- "evidence": [
- {
- "name": "Fee Flow Direction",
- "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
- "urls": [
- {
- "name": "MigrationFactoryOwner.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
- "type": "github"
- },
- {
- "name": "Factory.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
- "urls": [
- {
- "name": "vote_for_gauge_weights",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
- "type": "github"
- },
- {
- "name": "GaugeController Contract",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
deleted file mode 100644
index 084ddf2..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__offchain.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
- "tags": [
- "Reference"
- ],
- "evidence": []
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json b/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
deleted file mode 100644
index ed8c75a..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/val-accrual/val-accrual__treasury.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "status": "at_risk",
- "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
- "evidence": [
- {
- "name": "Ecosystem Reserve",
- "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
- "urls": [
- {
- "name": "Ecosystem Reserve",
- "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
- "type": "explorer"
- },
- {
- "name": "Ecosystem Reserve Owner (EOA)",
- "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
- "type": "explorer"
- },
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
deleted file mode 100644
index df29e57..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/_metric.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
- "tags": [
- "Metric 3"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
deleted file mode 100644
index 57de733..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__protocol-source.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status": "positive",
- "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
- "evidence": [
- {
- "name": "Verification and Audits",
- "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
- "urls": [
- {
- "name": "yb-core GitHub Repository",
- "url": "https://github.com/yield-basis/yb-core",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
- "type": "docs"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json b/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
deleted file mode 100644
index fe6d309..0000000
--- a/tests/fixtures/content-6b17fa7/evaluations/yb/verifiability/verifiability__token-source.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "status": "positive",
- "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB Token Verified on Etherscan",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "YB.vy Source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/faq.json b/tests/fixtures/content-6b17fa7/faq.json
deleted file mode 100644
index 64170db..0000000
--- a/tests/fixtures/content-6b17fa7/faq.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "topics": [
- {
- "id": "basics",
- "name": "Basics",
- "about": "Core definitions and how to use the framework.",
- "questions": [
- {
- "id": "basics__ownership-token",
- "question": "What is an ownership token?",
- "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
- },
- {
- "id": "basics__how-to-use",
- "question": "How can I use the Ownership Token Framework?",
- "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
- }
- ]
- },
- {
- "id": "methodology",
- "name": "Methodology",
- "about": "How evaluation, sourcing, and verification work.",
- "questions": [
- {
- "id": "methodology__evaluation",
- "question": "How do you evaluate tokens?",
- "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- },
- {
- "id": "methodology__evidence",
- "question": "How do you source and verify evidence?",
- "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- }
- ]
- },
- {
- "id": "participation",
- "name": "Participation",
- "about": "How tokens are selected and how to get involved.",
- "questions": [
- {
- "id": "participation__selection",
- "question": "How do you choose which tokens to feature?",
- "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
- },
- {
- "id": "participation__listing",
- "question": "How can I get a token listed?",
- "answer": "Submit a request (or refer a token) using this [here](submit-token)."
- },
- {
- "id": "participation__contribute",
- "question": "How can I contribute to this initiative?",
- "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
- }
- ]
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/_meta.json b/tests/fixtures/content-6b17fa7/framework/_meta.json
deleted file mode 100644
index 2f58a3f..0000000
--- a/tests/fixtures/content-6b17fa7/framework/_meta.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "baseUrl": "https://github.com/aragon/ownership-token-framework/blob/development/README.md",
- "order": [
- "onchain-ctrl",
- "val-accrual",
- "verifiability",
- "distribution",
- "offchain"
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/distribution.json b/tests/fixtures/content-6b17fa7/framework/distribution.json
deleted file mode 100644
index 52be47f..0000000
--- a/tests/fixtures/content-6b17fa7/framework/distribution.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "id": "distribution",
- "name": "Metric 4: Token Distribution",
- "displayName": "Token Distribution",
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "anchor": "#metric-4-token-distribution",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/offchain.json b/tests/fixtures/content-6b17fa7/framework/offchain.json
deleted file mode 100644
index 9dc3d8d..0000000
--- a/tests/fixtures/content-6b17fa7/framework/offchain.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "id": "offchain",
- "name": "Offchain Dependencies",
- "displayName": "Offchain Dependencies",
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "anchor": "#offchain-dependencies",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json b/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
deleted file mode 100644
index 57f816a..0000000
--- a/tests/fixtures/content-6b17fa7/framework/onchain-ctrl.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "id": "onchain-ctrl",
- "name": "Metric 1: Onchain Control",
- "displayName": "Onchain Control",
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "anchor": "#metric-1-onchain-control",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/val-accrual.json b/tests/fixtures/content-6b17fa7/framework/val-accrual.json
deleted file mode 100644
index 676fa1a..0000000
--- a/tests/fixtures/content-6b17fa7/framework/val-accrual.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "id": "val-accrual",
- "name": "Metric 2: Value Accrual",
- "displayName": "Value Accrual",
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "anchor": "#metric-2-value-accrual",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/framework/verifiability.json b/tests/fixtures/content-6b17fa7/framework/verifiability.json
deleted file mode 100644
index 9e0f5b8..0000000
--- a/tests/fixtures/content-6b17fa7/framework/verifiability.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "id": "verifiability",
- "name": "Metric 3: Verifiability",
- "displayName": "Verifiability",
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "anchor": "#metric-3-verifiability",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/testimonials.json b/tests/fixtures/content-6b17fa7/testimonials.json
deleted file mode 100644
index 2846926..0000000
--- a/tests/fixtures/content-6b17fa7/testimonials.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "title": "Evidence-backed due diligence for investors",
- "testimonials": [
- {
- "id": "miles-a16z",
- "name": "Miles Jennings",
- "organization": "a16z",
- "avatar": "/images/testimonials/miles-jennings.png",
- "url": "https://a16zcrypto.com/",
- "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
- },
- {
- "id": "f5-crypto",
- "name": "Paul Otto",
- "organization": "F5 Crypto",
- "avatar": "/images/testimonials/paul-otto.png",
- "url": "https://f5crypto.com/en/",
- "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
- }
- ]
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/aave.json b/tests/fixtures/content-6b17fa7/tokens/aave.json
deleted file mode 100644
index 96d8e46..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/aave.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "aave",
- "coingeckoId": "aave",
- "name": "AAVE",
- "symbol": "AAVE",
- "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
- "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
- "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aave.com/",
- "twitter": "https://twitter.com/aave",
- "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
- },
- "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/aero.json b/tests/fixtures/content-6b17fa7/tokens/aero.json
deleted file mode 100644
index fe193fc..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/aero.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "aero",
- "coingeckoId": "aerodrome-finance",
- "name": "AERO",
- "symbol": "AERO",
- "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
- "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
- "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
- "network": "base",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aerodrome.finance/",
- "twitter": "https://twitter.com/Aerodrome",
- "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
- },
- "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/crv.json b/tests/fixtures/content-6b17fa7/tokens/crv.json
deleted file mode 100644
index 7db7514..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/crv.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "crv",
- "coingeckoId": "curve-dao-token",
- "name": "CRV",
- "symbol": "CRV",
- "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
- "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
- "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://curve.finance/",
- "twitter": "https://twitter.com/curvefinance",
- "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
- },
- "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ena.json b/tests/fixtures/content-6b17fa7/tokens/ena.json
deleted file mode 100644
index 5b0151f..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/ena.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ena",
- "coingeckoId": "ethena",
- "name": "ENA",
- "symbol": "ENA",
- "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
- "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
- "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ethena.fi/",
- "twitter": "https://twitter.com/ethena",
- "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
- },
- "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ethfi.json b/tests/fixtures/content-6b17fa7/tokens/ethfi.json
deleted file mode 100644
index 1e86fa1..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/ethfi.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ethfi",
- "coingeckoId": "ether-fi",
- "name": "ETHFI",
- "symbol": "ETHFI",
- "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
- "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
- "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ether.fi/",
- "twitter": "https://twitter.com/ether_fi",
- "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
- },
- "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ldo.json b/tests/fixtures/content-6b17fa7/tokens/ldo.json
deleted file mode 100644
index 386c487..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/ldo.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ldo",
- "coingeckoId": "lido-dao",
- "name": "LDO",
- "symbol": "LDO",
- "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
- "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
- "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
- "network": "ethereum",
- "lastUpdated": 1777631939,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://lido.fi/",
- "twitter": "https://twitter.com/lidofinance",
- "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
- },
- "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/lqty.json b/tests/fixtures/content-6b17fa7/tokens/lqty.json
deleted file mode 100644
index 406fd2f..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/lqty.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "lqty",
- "coingeckoId": "liquity",
- "name": "LQTY",
- "symbol": "LQTY",
- "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
- "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
- "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
- "network": "ethereum",
- "lastUpdated": 1778064256,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://www.liquity.org/",
- "twitter": "https://twitter.com/LiquityProtocol",
- "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
- },
- "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/ondo.json b/tests/fixtures/content-6b17fa7/tokens/ondo.json
deleted file mode 100644
index fa64d38..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/ondo.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "ondo",
- "name": "ONDO",
- "symbol": "ONDO",
- "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
- "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
- "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
- "network": "ethereum",
- "lastUpdated": 1778674909,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ondo.finance/",
- "twitter": "https://twitter.com/OndoFinance",
- "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
- },
- "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
- "coingeckoId": "ondo-finance"
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/sky.json b/tests/fixtures/content-6b17fa7/tokens/sky.json
deleted file mode 100644
index bd377b7..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/sky.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "sky",
- "coingeckoId": "sky",
- "name": "SKY",
- "symbol": "SKY",
- "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
- "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
- "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://sky.money/",
- "twitter": "https://twitter.com/SkyEcosystem",
- "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
- },
- "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/uni.json b/tests/fixtures/content-6b17fa7/tokens/uni.json
deleted file mode 100644
index f3142e2..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/uni.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "uni",
- "coingeckoId": "uniswap",
- "name": "UNI",
- "symbol": "UNI",
- "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
- "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
- "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
- "network": "ethereum",
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://uniswap.org/",
- "twitter": "https://twitter.com/uniswap",
- "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
- },
- "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
-}
diff --git a/tests/fixtures/content-6b17fa7/tokens/yb.json b/tests/fixtures/content-6b17fa7/tokens/yb.json
deleted file mode 100644
index 7f9c298..0000000
--- a/tests/fixtures/content-6b17fa7/tokens/yb.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "id": "yb",
- "coingeckoId": "yield-basis",
- "name": "YB",
- "symbol": "YB",
- "address": "0x01791F726B4103694969820be083196cC7c045fF",
- "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
- "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
- "network": "ethereum",
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://yieldbasis.com/",
- "twitter": "https://x.com/yieldbasis",
- "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
- },
- "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
-}
diff --git a/tests/freshness.test.ts b/tests/freshness.test.ts
deleted file mode 100644
index 1598d93..0000000
--- a/tests/freshness.test.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Freshness gate: the committed src/data/generated/ output must equal what
- * the composer produces from the current content/ atoms. Fails when someone
- * edits atoms without re-running `node scripts/compose-data.mjs`.
- */
-import { readFileSync } from "node:fs"
-import { join } from "node:path"
-import { describe, expect, it } from "vitest"
-// @ts-expect-error untyped .mjs module
-import { composeAll } from "../scripts/compose-data.mjs"
-
-const generated = join(__dirname, "..", "src", "data", "generated")
-const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
-
-describe("generated read models are fresh", () => {
- const composed = composeAll()
-
- it("index.json", () => {
- expect(readJson(join(generated, "index.json"))).toEqual(composed.index)
- })
-
- it("token docs", () => {
- for (const doc of composed.tokenDocs) {
- expect(
- readJson(join(generated, "tokens", `${doc.id}.json`)),
- doc.id
- ).toEqual(doc)
- }
- })
-
- it("framework.json", () => {
- expect(readJson(join(generated, "framework.json"))).toEqual(
- composed.frameworkDoc
- )
- })
-
- it("faq + testimonials", () => {
- expect(readJson(join(generated, "faq.json"))).toEqual(composed.faq)
- expect(readJson(join(generated, "testimonials.json"))).toEqual(
- composed.testimonials
- )
- })
-
- it("manifest.json (snapshot identity)", () => {
- expect(readJson(join(generated, "manifest.json"))).toEqual(
- composed.manifest
- )
- })
-})
diff --git a/tests/generated-valid.test.ts b/tests/generated-valid.test.ts
new file mode 100644
index 0000000..52da824
--- /dev/null
+++ b/tests/generated-valid.test.ts
@@ -0,0 +1,55 @@
+/**
+ * The committed read models (src/data/generated/ — produced by otf-cms's
+ * composer, synced here until the Blob/Edge Config backing lands) must parse
+ * against the vendored schema contract.
+ */
+import { readdirSync, readFileSync } from "node:fs"
+import { join } from "node:path"
+import { describe, expect, it } from "vitest"
+import {
+ faqSchema,
+ frameworkDocSchema,
+ indexSchema,
+ manifestSchema,
+ testimonialsSchema,
+ tokenDocSchema,
+} from "@/lib/schemas"
+
+const generated = join(__dirname, "..", "src", "data", "generated")
+const readJson = (p: string) => JSON.parse(readFileSync(p, "utf8"))
+
+describe("src/data/generated/ parses against the vendored schema contract", () => {
+ it("index", () => {
+ expect(() =>
+ indexSchema.parse(readJson(join(generated, "index.json")))
+ ).not.toThrow()
+ })
+
+ it("token docs (one per manifest entry)", () => {
+ const manifest = manifestSchema.parse(
+ readJson(join(generated, "manifest.json"))
+ )
+ const files = readdirSync(join(generated, "tokens"))
+ expect(files.map((f) => f.replace(/\.json$/, "")).sort()).toEqual(
+ [...manifest.tokens].sort()
+ )
+ for (const id of manifest.tokens) {
+ expect(
+ () => tokenDocSchema.parse(readJson(join(generated, "tokens", `${id}.json`))),
+ id
+ ).not.toThrow()
+ }
+ })
+
+ it("framework, faq, testimonials", () => {
+ expect(() =>
+ frameworkDocSchema.parse(readJson(join(generated, "framework.json")))
+ ).not.toThrow()
+ expect(() =>
+ faqSchema.parse(readJson(join(generated, "faq.json")))
+ ).not.toThrow()
+ expect(() =>
+ testimonialsSchema.parse(readJson(join(generated, "testimonials.json")))
+ ).not.toThrow()
+ })
+})
diff --git a/tests/golden/faq.json b/tests/golden/faq.json
deleted file mode 100644
index dde2743..0000000
--- a/tests/golden/faq.json
+++ /dev/null
@@ -1,58 +0,0 @@
-[
- {
- "id": "basics",
- "name": "Basics",
- "about": "Core definitions and how to use the framework.",
- "questions": [
- {
- "id": "basics__ownership-token",
- "question": "What is an ownership token?",
- "answer": "An ownership token is a token whose holders have enforceable, onchain rights--directly or via tokenholder-governed execution--over the assets and value flows that determine economic outcomes."
- },
- {
- "id": "basics__how-to-use",
- "question": "How can I use the Ownership Token Framework?",
- "answer": "The framework is intended for reviewing and verifying the programmatic economic rights associated with a token using primary evidence. It evaluates both onchain mechanisms and relevant offchain dependencies that may reinforce or undermine expectations of ownership rights.\n\nThe Ownership Token Framework is not an endorsement of any project and is not investment advice. The Framework evaluates tokenholder rights and related dependencies, not whether a project generates value. It provides structure and primary evidence that can inform fundamental analysis and help market participants reach their own conclusions, but it is not sufficient on its own."
- }
- ]
- },
- {
- "id": "methodology",
- "name": "Methodology",
- "about": "How evaluation, sourcing, and verification work.",
- "questions": [
- {
- "id": "methodology__evaluation",
- "question": "How do you evaluate tokens?",
- "answer": "Our token reports include metrics, criteria, and evidence.\n\nEach of our four metrics contain a checklist of criteria. For each criteria we provide primary evidence, including:\nOnchain: active deployments, permissions/roles, parameters, execution history.\nOffchain (where relevant): public filings/registrations, published legal terms, and other public documentation.\n\nYou can read the full metric definitions and methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- },
- {
- "id": "methodology__evidence",
- "question": "How do you source and verify evidence?",
- "answer": "All evidence used by the Framework is public and linked in the findings. For onchain criteria, we use active deployments and execution history. For offchain criteria, we use public registrations and legal disclaimers (where available).\n\nInitial research and sourcing is done by the Aragon team. Protocol teams, investors, and community members can also submit public primary evidence to support, correct, or challenge specific findings.\n\nYou can learn more about the methodology [here](https://github.com/aragon/ownership-token-framework/blob/development/README.md)."
- }
- ]
- },
- {
- "id": "participation",
- "name": "Participation",
- "about": "How tokens are selected and how to get involved.",
- "questions": [
- {
- "id": "participation__selection",
- "question": "How do you choose which tokens to feature?",
- "answer": "We started with a set of established projects to validate the framework. Ongoing inclusion is request-driven: anyone can request a token be reviewed for possible inclusion."
- },
- {
- "id": "participation__listing",
- "question": "How can I get a token listed?",
- "answer": "Submit a request (or refer a token) using this [here](submit-token)."
- },
- {
- "id": "participation__contribute",
- "question": "How can I contribute to this initiative?",
- "answer": "If you want to provide feedback, propose improvements, or explore collaboration, reach out [here](submit-token)."
- }
- ]
- }
-]
diff --git a/tests/golden/framework.json b/tests/golden/framework.json
deleted file mode 100644
index 6070e77..0000000
--- a/tests/golden/framework.json
+++ /dev/null
@@ -1,127 +0,0 @@
-[
- {
- "id": "onchain-ctrl",
- "name": "Metric 1: Onchain Control",
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions."
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders."
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders."
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance."
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes."
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users."
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers."
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Metric 2: Value Accrual",
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed."
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance."
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing."
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?"
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Metric 3: Verifiability",
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode."
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments."
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Metric 4: Token Distribution",
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply."
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?"
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?"
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?"
- }
- ]
- }
-]
diff --git a/tests/golden/metrics.json b/tests/golden/metrics.json
deleted file mode 100644
index 3e39ee3..0000000
--- a/tests/golden/metrics.json
+++ /dev/null
@@ -1,6311 +0,0 @@
-{
- "aave": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "AAVE, stkAAVE and aAAVE holders control the protocol through onchain governance with Timelock execution. The token has fixed 16M supply with no mint function. Delegated steward roles exist but are elected and revocable by governance.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "AAVE, stkAAVE and aAAVE holders vote onchain with execution through Timelock.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://aave.com/docs/ecosystem/governance",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "The Governance Emergency Guardian is a 5/9 multisig elected by holders to protect the protocol from governance takeover attacks by vetoing onchain payloads.",
- "evidence": [
- {
- "name": "Governance Emergency Guardian",
- "urls": [
- {
- "name": "Onchain address",
- "url": "https://etherscan.io/address/0xCe52ab41C40575B072A18C9700091Ccbe4A06710#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Detailed Governance Permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#governance-v3-contracts",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Holders control implementation upgrades for all v3 market deployments.",
- "evidence": [
- {
- "name": "Upgrade Documentation",
- "summary": "Pool (upgradeable proxy) → Admin is PoolAddressProvider → onlyOwner is Executor → owner is PayloadsController → controlled by Governance.",
- "urls": [
- {
- "name": "Upgradability per contract",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Ownership Chain",
- "summary": "Pool → PoolAddressProvider → Executor → PayloadsController → Governance.\n\nFor PayloadsController to call Executor, MESSAGE_ORIGINATOR must equal Governance.",
- "urls": [
- {
- "name": "Pool",
- "url": "https://etherscan.io/address/0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#code",
- "type": "explorer"
- },
- {
- "name": "Governance",
- "url": "https://etherscan.io/address/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The AAVE token is upgradeable but controlled by token holders.",
- "evidence": [
- {
- "name": "Ownership Chain",
- "summary": "ERC-1967 Transparent proxy owned by ProxyAdmin, controlled by token holders.\n\nAAVE (Proxy) → ProxyAdmin → Executor → PayloadsController → Token Holders",
- "urls": [
- {
- "name": "AAVE Proxy",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "ProxyAdmin",
- "url": "https://etherscan.io/address/0x86c3FfEE349A7cFf7cA88C449717B1b133bfb517#code",
- "type": "explorer"
- },
- {
- "name": "PayloadsController",
- "url": "https://etherscan.io/address/0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5#readProxyContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "Fixed 16m AAVE token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only AAVE token minting transactions ever, amounting to 16m AAVE tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "Roles can be broadly classified into **Core Protocol Roles** and **Delegated Steward Roles**. AAVE holders elect and revoke all these roles with their standard governance procedure.",
- "evidence": [
- {
- "name": "Core",
- "summary": "Core Protocol Roles: EMERGENCY_ADMIN, RISK_ADMIN, POOL_ADMIN, ASSET_LISTING_ADMIN. These live in ACLManager, owned by ACLAdmin (verifiable in PoolAddressesProvider). ACLAdmin is owned by PayloadsController, controlled by token holders.",
- "urls": [
- {
- "name": "Core Protocol Role addresses",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#admins",
- "type": "github"
- },
- {
- "name": "Core Protocol Roles in ACLManager",
- "url": "https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0",
- "type": "explorer"
- },
- {
- "name": "EMERGENCY_ADMIN_ROLE: GnosisSafeProxy",
- "url": "https://etherscan.io/address/0x2cfe3ec4d5a6811f4b8067f0de7e47dfa938aa30#code",
- "type": "explorer"
- },
- {
- "name": "POOL_ADMIN_ROLE: Executor",
- "url": "https://etherscan.io/address/0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Delegated Steward Roles",
- "summary": "\n\nRisk Stewards → Risk Parameters\nFinance Stewards → Treasury\nAave Guardians → Emergency",
- "urls": [
- {
- "name": "Stewards (docs)",
- "url": "https://aave.com/help/governance/aave-community",
- "type": "docs"
- },
- {
- "name": "Stewards (addresses)",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts-upgradeability",
- "type": "github"
- }
- ]
- },
- {
- "name": "Protocol Emergency Guardian",
- "summary": "A separate multisig that executes limited emergency operations for the protocol.",
- "urls": [
- {
- "name": "Protocol Emergency Guardian",
- "url": "https://aave.com/docs/ecosystem/governance#community-guardians-protocol-emergency-guardian",
- "type": "docs"
- },
- {
- "name": "Detailed protocol permissions",
- "url": "https://github.com/aave-dao/aave-permissions-book/blob/main/out/ETHEREUM-V3.md#contracts",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the AAVE token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token's implementation code",
- "url": "https://etherscan.io/address/0x5d4aa78b08bc7c530e21bf7447988b1be7991322#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "Protocol fees flow to a governance-controlled treasury. Holders can stake as stkAAVE in Safety Module for yield. Treasury composed of reserve factor from borrower interest + liquidation fees + flashloan premiums.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "Alongside the protocol fees going to the AAVE token-holder controlled treasury as an important source of value accrual, holders can stake their AAVE tokens as stkAAVE in Aave's Safety module, getting additional AAVE tokens as yield from the treasury for bearing the risk of slashing in case of protocol insolvency.\n\n**Caveat:** This Safety Module is in the transitional phase of being sunset in favour of aToken staking as part of the Umbrella release for automated bad debt coverage, which is live already.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Safety Module - Incentives",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#safety-module",
- "type": "docs"
- },
- {
- "name": "Umbrella Transition",
- "url": "https://aave.com/help/umbrella/stake",
- "type": "docs"
- },
- {
- "name": "Umbrella Activation Proposal",
- "url": "https://vote.onaave.com/proposal/?proposalId=320",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "AAVE holders control treasury usage. Composed of reserve factor (borrower interest), liquidation fees, and flashloan premiums.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "Token holders direct treasury via governance.",
- "urls": [
- {
- "name": "Treasury docs",
- "url": "https://aave.com/docs/aave-v3/concepts/incentives#incentives",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Fee Sources",
- "summary": "Reserve factor (interest), liquidation fees, flashloan premiums all route to treasury via mintToTreasury().",
- "urls": [
- {
- "name": "mintToTreasury (PoolLogic)",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/PoolLogic.sol#L105",
- "type": "github"
- },
- {
- "name": "Flashloan premium",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/pool/Pool.sol#L653",
- "type": "github"
- },
- {
- "name": "Liquidation fee",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L392",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "Token holders control fee levers (Reserve Factor, liquidation fees) via ACL-gated admin roles. Emergency actions are delegated, but economic controls are governance-owned through ACLManager.",
- "evidence": [
- {
- "name": "ACL Control",
- "summary": "ACLManager gates admin roles (POOL_ADMIN, RISK_ADMIN) which control fee parameters. ACLManager itself is controlled by governance.",
- "urls": [
- {
- "name": "POOL_ADMIN role",
- "url": "https://aave.com/docs/aave-v3/smart-contracts/acl-manager#roles-pool-admin",
- "type": "docs"
- },
- {
- "name": "ACLManager",
- "url": "https://github.com/aave-dao/aave-v3-origin/blob/main/src/contracts/protocol/configuration/ACLManager.sol#L45",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AAVE token",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "AAVE token proxy and implementation are verified on Etherscan. Aave V3 protocol contracts are open source and verified.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The AAVE token contract source code is publicly available and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AAVE token",
- "url": "https://etherscan.io/address/0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Aave V3 protocol contracts are open source on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aave V3 Origin (GitHub)",
- "url": "https://github.com/aave-dao/aave-v3-origin",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Aragon has not verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if any 3rd party controls a majority share of the voting power of AAVE or derivatives.",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the AAVE token",
- "evidence": []
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "US AAVE trademark is held by Quantum Swan OU (Estonia). Primary interface terms identify Aave Labs (a separate entity from the Aave DAO) as the contracting party.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "A US AAVE trademark filing lists Quantum Swan OU (Estonia) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Trademark filing",
- "url": "https://tsdr.uspto.gov/#caseNumber=79251290&caseSearchType=US_APPLICATION&caseType=DEFAULT&searchType=statusSearch",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The primary interface terms identify Aave Labs as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://aave.com/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AAVE token or the corresponding protocol and assets",
- "evidence": []
- }
- ]
- }
- ],
- "aero": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "Aerodrome's core contracts are largely immutable with control of emissions given to veAERO holders via the gauge voting system. There are some minor areas in which privileged parties can control specific areas of the protocol, which are detailed below.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "veAERO holders control emissions through epoch-based gauge voting. An EmergencyCouncil exists for crisis handling with limited emergency powers.",
- "evidence": [
- {
- "name": "Voting System",
- "summary": "AERO holders lock AERO in VotingEscrow to receive veAERO. veAERO holders vote each epoch on gauge weights via the Voter contract, and the Minter distributes emissions proportionally.",
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "VotingEscrow",
- "url": "https://basescan.org/address/0xeBf418Fe2512e7E6bd9b87a8F0f294aCDC67e6B4#code",
- "type": "explorer"
- },
- {
- "name": "Voter",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Council",
- "summary": "Exists to handle contingencies. It can kill or revive gauges, update pool name and symbol metadata, and rotate the EmergencyCouncil itself.",
- "urls": [
- {
- "name": "EmergencyCouncil",
- "url": "https://aerodrome.limited/pages/security.html",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "veAERO holders indirectly control AERO emissions through epoch-based gauge voting executed by the Voter and Minter.",
- "evidence": [
- {
- "name": "Emergency Council",
- "summary": "Exists but is not elected by veAERO holders. It holds limited emergency powers, including killing or reviving gauges and managing pool metadata. This role exists explicitly for crisis handling and sits outside direct tokenholder election.",
- "urls": [
- {
- "name": "Voter: emergencyCouncil",
- "url": "https://basescan.org/address/0x16613524e02ad97eDfeF371bC883F2F5d6C480A5#readContract",
- "type": "explorer"
- },
- {
- "name": "EmergencyCouncil",
- "url": "https://basescan.org/address/0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013D#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Core Aerodrome protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contract Addresses",
- "url": "https://aerodrome.finance/security",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The AERO token contract is immutable and does not use a proxy pattern. The Minter contract, which is authorized to mint AERO, is also non-upgradeable.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "AERO minting is fully programmatic and epoch-based (1 epoch = 1 week), enforced by the non-upgradeable Minter contract.",
- "evidence": [
- {
- "name": "Minter Contract",
- "summary": "The non-upgradeable Minter contract enforces programmatic emission rules.",
- "urls": [
- {
- "name": "Minter",
- "url": "https://basescan.org/address/0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Can be increased/decreased by governance but only in fixed, small, weekly increments of +/-0.01%.",
- "urls": [
- {
- "name": "Minter Emission Increase (Epochs 1-14)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L182",
- "type": "github"
- },
- {
- "name": "Minter Emission Decay",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L184",
- "type": "github"
- }
- ]
- },
- {
- "name": "Growth Emissions",
- "summary": "Mints growth emissions for veAERO holders using the formula: weeklyEmissions * (1 - veAERO.totalSupply / AERO.totalSupply)^2 * 0.5. This creates a counter-cyclical incentive where veAERO rewards decrease as more AERO is locked.",
- "urls": [
- {
- "name": "Growth Emissions Formula",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L135",
- "type": "github"
- }
- ]
- },
- {
- "name": "Team Emission Rate",
- "summary": "Currently set to 0% of total weekly emissions.",
- "urls": [
- {
- "name": "Team Emission Rate",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L192",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "warning",
- "notes": "The feeManager role exists which is controlled by a Safe multisig, not veAERO holders. This role can modify fee parameters across both pool types.",
- "evidence": [
- {
- "name": "Fee Manager Role",
- "summary": "The feeManager role is controlled by a Safe multisig and can modify fee parameters.",
- "urls": [
- {
- "name": "Safe (Fee Manager)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-SlipStream Fees",
- "summary": "Fees are set on the PoolFactory which can be changed by the feeManager.",
- "urls": [
- {
- "name": "PoolFactory: FeeManager",
- "url": "https://basescan.org/address/0x420DD381b31aEf6683db6B902084cB0FFECe40Da#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "SlipStream Fees",
- "summary": "For CLPoolFactory, fees are set inside the SwapFeeModule which allows feeManager to change fees.",
- "urls": [
- {
- "name": "SlipStream: CLFactory (uses SwapFeeModule for fees)",
- "url": "https://basescan.org/address/0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A#code",
- "type": "explorer"
- },
- {
- "name": "SwapFeeModule: setCustomFee",
- "url": "https://basescan.org/address/0xF4171B0953b52Fa55462E4d76ecA1845Db69af00#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "The AERO token has no blacklist, pause, or seizure mechanisms.",
- "evidence": [
- {
- "name": "Team Rate",
- "summary": "The team rate (share of weekly emissions allocated to the team) can be modified by a Safe controlled by the Aerodrome team.",
- "urls": [
- {
- "name": "Safe (Team)",
- "url": "https://basescan.org/address/0xBDE0c70BdC242577c52dFAD53389F82fd149EA5a#code",
- "type": "explorer"
- },
- {
- "name": "Team Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L129",
- "type": "github"
- }
- ]
- },
- {
- "name": "Emission Rate",
- "summary": "Changes to the weekly emission rate (+/-0.01% or unchanged) are controlled by Governor (a multisig), soon to be handed over to governance contracts controlled by veAERO holders.",
- "urls": [
- {
- "name": "Governor (Safe)",
- "url": "https://basescan.org/address/0xE6A41fE61E7a1996B59d508661e3f524d6A32075",
- "type": "explorer"
- },
- {
- "name": "Emission Rate Change",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L145",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "veAERO holders receive growth emissions and trading fees from staked LP positions. There is no protocol treasury - all trading fees are distributed. Offchain brand controlled by Aerodrome Foundation.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "veAERO holders receive rewards from growth emissions and trading fees from staked LP positions.",
- "evidence": [
- {
- "name": "Growth Emissions",
- "summary": "veAERO holders receive rewards from growth emissions transferred to RewardDistributor, claimable in proportion to ve balance.",
- "urls": [
- {
- "name": "Growth Transfer to RewardDistributor",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Minter.sol#L201",
- "type": "github"
- },
- {
- "name": "RewardsDistributor Claim",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/RewardsDistributor.sol#L126",
- "type": "github"
- }
- ]
- },
- {
- "name": "Non-Slipstream Trading Fees",
- "summary": "For normal pools, swap fees from LPs who have staked their LP tokens in gauges go to veAERO holders.",
- "urls": [
- {
- "name": "Gauge Deposit Logic",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L155",
- "type": "github"
- },
- {
- "name": "Swap Fee Accrued",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L378",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Pool.sol#L143",
- "type": "github"
- },
- {
- "name": "Voter calling Gauge to claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/Voter.sol#L492",
- "type": "github"
- },
- {
- "name": "Swap Fee Claimed by Gauge on PoolFees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/gauges/Gauge.sol#L82",
- "type": "github"
- }
- ]
- },
- {
- "name": "Slipstream Trading Fees",
- "summary": "For Slipstream (CL) pools, swap fees from staked LP positions go to veAERO holders.",
- "urls": [
- {
- "name": "Fees Split",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844",
- "type": "github"
- },
- {
- "name": "Gauge Fees calculated separately",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L844C37-L844C46",
- "type": "github"
- },
- {
- "name": "Non Staked LP Fees collected",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/core/CLPool.sol#L483",
- "type": "github"
- },
- {
- "name": "Gauge Fees to feesVotingReward",
- "url": "https://github.com/aerodrome-finance/slipstream/blob/7844368af8f83459b5056ff5f3334ff041232382/contracts/gauge/CLGauge.sol#L340",
- "type": "github"
- },
- {
- "name": "veAERO voters claim fees",
- "url": "https://github.com/aerodrome-finance/contracts/blob/1ba30815bba620f7e9faa34769ffd00c214c9b82/contracts/rewards/Reward.sol#L225",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "There is no protocol treasury. All trading fees from swapping pools are distributed to veAERO holders and LPs.",
- "evidence": []
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "veAERO holders control:\n\n1. The AERO rewards they receive by locking AERO tokens in VotingEscrow\n\n2. The AERO emissions going into gauges by voting for them in Voter\n\n**Note:** Fee parameters are controlled by the feeManager (a Safe multisig), not by veAERO holders directly.",
- "evidence": [
- {
- "name": "Locking Control",
- "summary": "veAERO holders control their rewards by locking AERO in VotingEscrow.",
- "urls": [
- {
- "name": "VotingEscrow create_lock",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/VotingEscrow.sol#L555",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veAERO holders direct emissions by voting for gauges in the Voter contract.",
- "urls": [
- {
- "name": "Voter vote function",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Voter.sol#L249",
- "type": "github"
- },
- {
- "name": "Gauge getReward",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/gauges/Gauge.sol#L179",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the AERO token",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "AERO token source is publicly available on GitHub and verified on Basescan. Aerodrome protocol contracts are open source and verified.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The AERO token contract source code (Aero.sol) is publicly available on GitHub and verified on Basescan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "AERO Token (Basescan)",
- "url": "https://basescan.org/address/0x940181a94A35A4569E4529A3CDfB74e38FD98631#code",
- "type": "explorer"
- },
- {
- "name": "Aero.sol Source (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts/blob/main/contracts/Aero.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Aerodrome protocol contracts (including Slipstream) are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Contracts (GitHub)",
- "url": "https://github.com/aerodrome-finance/contracts",
- "type": "github"
- },
- {
- "name": "Aerodrome Slipstream (GitHub)",
- "url": "https://github.com/aerodrome-finance/slipstream",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Distribution of AERO and veAERO voting power outside of the core team has not been independently verified.",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "positive",
- "notes": "Future AERO unlocks are determined by the supply schedule and the veAERO system detailed above. Aragon is not aware of any significant vesting cliffs.",
- "evidence": []
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "US AERODROME trademark is held by Perpetual Cyclist Services LLC (Delaware). Primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "A US AERODROME trademark filing lists Perpetual Cyclist Services LLC (Delaware) as the applicant/owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "USPTO Report",
- "url": "https://uspto.report/TM/99083103",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The primary interface terms identify the Aerodrome Foundation as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aerodrome Legal",
- "url": "https://aero.drome.eth.link/legal",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the AERO token or the corresponding protocol and assets",
- "evidence": []
- }
- ]
- }
- ],
- "crv": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "veCRV holders control all protocol operations through Aragon v1's Voting Contract and Agent. The CRV token is immutable with programmatic inflation and no censorship capabilities. Core protocol and pool contracts are immutable.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "Governance is enforced through Aragon v1's Voting Contract, which authorizes execution via the Agent contract. The Agent contract is set as the owner for all protocol-gated functions, ensuring veCRV holders control all operations.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Aragon Voting Contract",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356",
- "type": "explorer"
- },
- {
- "name": "Agent Contract",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968",
- "type": "explorer"
- },
- {
- "name": "CRV Token: Admin is set to Agent",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "All protocol roles are controlled by the Agent contract, ensuring veCRV holders maintain control over gauges, fees, and protocol expansion.",
- "evidence": [
- {
- "name": "Gauge Addition",
- "summary": "Only the Agent can add new gauges via add_gauge on GaugeController.",
- "urls": [
- {
- "name": "GaugeController: admin is Agent",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Pool Factory Ownership",
- "summary": "New pools are deployed by Factory contracts controlled by OwnerProxy. Agent is responsible for adding new pools, giving veCRV holders control over protocol expansion.",
- "urls": [
- {
- "name": "Curve Pool Factory: admin is OwnerProxy",
- "url": "https://etherscan.io/address/0xB9fc157394Af804a3578134A6585C0dC9cc990d4#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Core protocol and pool contracts are immutable. Governance contracts (Agent, Voting) are upgradeable only by veCRV holders.",
- "evidence": [
- {
- "name": "Core Contracts",
- "summary": "Core protocol and pool contracts are immutable. The CRV Token and GaugeController have admin set to Agent but cannot be upgraded.",
- "urls": [
- {
- "name": "CRV Token (Admin: Agent)",
- "url": "https://etherscan.io/address/0xd533a949740bb3306d119cc777fa900ba034cd52",
- "type": "explorer"
- },
- {
- "name": "GaugeController (Admin: Agent)",
- "url": "https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent Contract",
- "summary": "Can be upgraded by calling setApp(Agent, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Agent contract through governance voting.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x40907540d8a6C65c637785e8f8B742ae6b0b9968#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Voting Contract",
- "summary": "Can be upgraded by calling setApp(Voting, ...) on the Kernel contract, which is only allowed by the Agent itself. Only veCRV holders can upgrade the Voting contract through governance voting.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The CRV token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Source",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "CRV has a programmatic inflation schedule with yearly epochs and decreasing emission rate. All minting flows through the Minter contract based on gauge participation.",
- "evidence": [
- {
- "name": "Supply Schedule",
- "summary": "CRV inflation is released in yearly epochs: each year allows a fixed maximum amount to be minted linearly over time, and at the end of the year the minting rate is reduced by a factor of 2^(1/4). Any unminted supply from a year is permanently lost.",
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- },
- {
- "name": "ERC20CRV.vy Yearly Epoch Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L115C40-L115C59",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Access",
- "summary": "Mint can only occur through the Minter contract which validates gauge participation. Amount minted depends on veCRV balance and provided LP tokens in a gauge.",
- "urls": [
- {
- "name": "ERC20CRV.vy Mint Access",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L333",
- "type": "github"
- },
- {
- "name": "Minter.vy Gauge Validation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy#L46",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "Core protocol functions are either permissionless or gated by Agent contract (hence veCRV holders). For gate control related to fees/revenues, see accrual section.",
- "evidence": [
- {
- "name": "Add/Kill Gauge",
- "summary": "To add a new gauge in GaugeController, veCRV holders must vote in majority. The admin on GaugeController is set to the Aragon Agent Contract, which sits as the final step in the governance process. Governance starts with the Aragon Voting contract that uses veCRV token for voting. veCRV holders can also kill a gauge, permanently setting its rewards to 0.",
- "urls": [
- {
- "name": "Gauge Kill Implementation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L731",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "The CRV token has no transfer restrictions, blacklist functionality, or pausable transfers. There's Admin set (Agent) on the CRV token, but it can only update token's name and symbol.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ERC20CRV.vy Standard Transfer",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy#L272",
- "type": "github"
- },
- {
- "name": "ERC20CRV.vy Metadata Logic",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/ERC20CRV.vy#L365",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards. Value flows are programmatic through the gauge system. Offchain structure shows Swiss Stake AG controls the interface and trademark.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "veCRV holders receive 50% of all trading fees distributed as crvUSD rewards, plus boosted CRV emissions for liquidity provision. They also receive 80% of the accrued interest from all crvUSD markets.",
- "evidence": [
- {
- "name": "CRV Emissions Rewards",
- "summary": "Liquidity Providers deposit LP tokens into Gauge Contracts. Once the gauge receives CRV emissions, LPs can claim proportional rewards. LPs can boost rewards up to 2.5x by locking CRV for veCRV.",
- "urls": [
- {
- "name": "working_balance reward calculation",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/fa127b1cb7bf83e4f3d605f7244b7b4ed5ebe053/contracts/gauges/LiquidityGaugeV5.vy#L210",
- "type": "github"
- }
- ]
- },
- {
- "name": "Pool Rewards in crvUSD",
- "summary": "Pools have swap fees with an admin portion collected by StableSwapProxy. Fees flow through burner contracts to FeeCollector, which converts all tokens to crvUSD via CowSwapBurner and sends to FeeDistributor for veCRV holders to claim.",
- "urls": [
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Borrow Rewards in crvUSD",
- "summary": "Borrowing interest (paid in crvUSD) from controllers are sent to FeeSplitter. FeeCollector receives proportional crvUSD and sends to FeeDistributor for veCRV holders.",
- "urls": [
- {
- "name": "FeeSplitter",
- "url": "https://etherscan.io/address/0x2dfd89449faff8a532790667bab21cf733c064f2",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "50% of all trading fees are distributed to veCRV holders through crvUSD rewards, while the remaining 50% goes to the respective liquidity providers of the pools. Only veCRV holders can change this behaviour, hence Curve has no separate treasury. All revenue to the people.",
- "evidence": [
- {
- "urls": [
- {
- "name": "veCRV Revenue Share (Docs)",
- "url": "https://docs.curve.finance/user/vecrv/revenue",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "Gauge weights are determined programmatically by veCRV votes, not discretionary decisions.",
- "evidence": [
- {
- "name": "Pool Fee Control",
- "summary": "Pool fee changes are executed via commit_new_fee, which can only be called by the pool owner (StableSwapProxy) which in turn is restricted to parameter_admin (Agent contract).",
- "urls": [
- {
- "name": "DAI/USDC/USDT Pool: commit_new_fee",
- "url": "https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burner Attachment",
- "summary": "set_burner on StableSwapProxy is gated by ownership_admin (Agent contract).",
- "urls": [
- {
- "name": "StableSwapProxy: set_burner",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Burn Execution",
- "summary": "The burn function invokes each coin's attached burner contract. Can be disabled by either the Agent contract or the emergency Safe multisig.",
- "urls": [
- {
- "name": "StableSwapProxy: burn",
- "url": "https://etherscan.io/address/0xeCb456EA5365865EbAb8a2661B0c503410e9B347#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the CRV token",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "CRV token source (Vyper) is publicly available on GitHub and verified on Etherscan. Curve DAO contracts are open source and verified.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The CRV token contract source code (ERC20CRV.vy) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Token (Etherscan)",
- "url": "https://etherscan.io/token/0xd533a949740bb3306d119cc777fa900ba034cd52#code",
- "type": "explorer"
- },
- {
- "name": "ERC20CRV.vy Source (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/ERC20CRV.vy",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Curve DAO protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve DAO Contracts (GitHub)",
- "url": "https://github.com/curvefi/curve-dao-contracts",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Aragon has not verified if the majority of veCRV voting power lies with a single party.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified if the majority of veCRV voting power lies with a single party",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "positive",
- "notes": "Future CRV unlocks are determined by the programmatic supply schedule and veCRV system. Emissions decrease yearly by 2^(1/4). Aragon is not aware of any significant vesting cliffs.",
- "evidence": [
- {
- "urls": [
- {
- "name": "CRV Emission Schedule (Docs)",
- "url": "https://docs.curve.finance/user/curve-tokens/crv#emission-schedule",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Swiss CRV trademark is held by Swiss Stake AG. Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The Swiss CRV trademark registration lists Swiss Stake AG as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Swiss Trademark Registry",
- "url": "https://www.swissreg.ch/database-client/register/detail?lang=de&no=16098%2F2020&type=trademark",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The Curve interface terms identify Swiss Stake AG (Zug, Switzerland) as the contracting party.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Curve Legal",
- "url": "https://www.curve.finance/dex/ethereum/legal",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified all the licensing criteria associated with the CRV token or the corresponding protocol and assets",
- "evidence": []
- }
- ]
- }
- ],
- "ena": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "ENA governance is advisory only. Tokenholders vote via Snapshot, but the Dev Multisig executes all decisions. There is no onchain governance workflow, no timelock, and ENA holders cannot elect or remove multisig signers. The ENA token itself is non-upgradeable, but sENA and rsENA are upgradeable proxies controlled by separate multisigs. Staking contracts include blacklist capabilities with seizure powers.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "warning",
- "notes": "ENA governance is **offchain Snapshot signaling only**. Votes do not trigger onchain transactions. The Dev Multisig decides whether to execute proposals, making tokenholder votes advisory rather than binding. There is no timelock on multisig actions.",
- "evidence": [
- {
- "name": "Snapshot Governance",
- "summary": "ENA holders vote via Snapshot at ethenagovernance.eth. All passed votes require manual multisig execution. Per docs: \"fully on-chain governance is not a practical or viable option at present.\"",
- "urls": [
- {
- "name": "Snapshot Space",
- "url": "https://snapshot.org/#/ethenagovernance.eth",
- "type": "docs"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Multisig Execution",
- "summary": "The Dev Multisig owns all core contracts. Verified onchain: `getThreshold()` returns 5, `getOwners()` returns 11 addresses. Documentation claims 4/8, but onchain reality is 5/11.",
- "urls": [
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "warning",
- "notes": "All privileged roles are controlled by Ethena Labs multisigs or EOAs, **NOT** by ENA tokenholders. The Risk Committee is elected via Snapshot but has no onchain authority. No mechanism exists for ENA holders to remove or replace multisig signers.",
- "evidence": [
- {
- "name": "Multisig Control Matrix",
- "summary": "**Dev Multisig:** All contract ownership, upgrades, minting, parameter changes. Signers NOT elected by ENA holders.\n\n**Hot Swap:** Protocol revenue flow, USDe conversion. Signers NOT elected.\n\n**sUSDe Payout:** Staker reward distribution. Signers NOT elected.\n\n**Trading Operations:** Onchain operational activities. Signers NOT elected.\n\n**Reserve Fund:** Emergency reserve deployment. Signers NOT elected.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "Dev Multisig",
- "url": "https://etherscan.io/address/0x3b0aaf6e6fcd4a7ceef8c92c32dfea9e64dc1862",
- "type": "explorer"
- },
- {
- "name": "Hot Swap Multisig",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "Trading Operations Multisig",
- "url": "https://etherscan.io/address/0x0a0b96A730ED5CDa84bcB63c1Ee2edCb6B7764d6",
- "type": "explorer"
- },
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "EOA Control Points",
- "summary": "**StakingRewardsDistributor Operator** (EOA): Can trigger `transferInRewards()` to distribute USDe to sUSDe stakers.\n\n**Minters** (20 EOAs): Can mint USDe via EthenaMinting.\n\n**Redeemers** (20 EOAs): Can redeem USDe.\n\n**Gatekeepers** (3+ EOAs): Can disable USDe mint/redeem globally.",
- "urls": [
- {
- "name": "StakingRewardsDistributor Operator (EOA)",
- "url": "https://etherscan.io/address/0xe3880B792F6F0f8795CbAACd92E7Ca78F5d3646e",
- "type": "explorer"
- },
- {
- "name": "Multisig Matrix (Minter/Redeemer/Gatekeeper docs)",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "warning",
- "notes": "**sENA is upgradeable** via proxy controlled by Dev Multisig. **rsENA is also upgradeable** but controlled by a different multisig. Neither upgrade path involves tokenholder approval. ENA, USDe, sUSDe, and EthenaMinting are non-upgradeable.",
- "evidence": [
- {
- "name": "Non-Upgradeable Contracts",
- "summary": "ENA, USDe, sUSDe, and EthenaMinting V2 are not proxy contracts.",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Upgradeable Contracts (sENA and rsENA)",
- "summary": "**sENA:** Uses EIP-1967 proxy. Dev Multisig can upgrade without tokenholder approval. No timelock.\n\n**rsENA:** Uses EIP-1967 proxy with a different upgrade controller. Controlled by a separate multisig with signers not publicly identified. No timelock.",
- "urls": [
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "sENA Implementation",
- "url": "https://etherscan.io/address/0x7fd57b46ae1a7b14f6940508381877ee03e1018b#code",
- "type": "explorer"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Implementation",
- "url": "https://etherscan.io/address/0x09bba67c316e59840699124a8dc0bbda6a2a9d59#code",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xa59b36aca119a30c527eddaa386eb130bcf1939f",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "warning",
- "notes": "The ENA token itself is **NOT upgradeable**. It uses Ownable2Step, not a proxy pattern. Token behavior is immutable. However, the owner (Dev Multisig) retains mint authority subject to rate limits.",
- "evidence": [
- {
- "name": "ENA Non-Upgradeability Verification",
- "summary": "The ENA token inherits Ownable2Step, ERC20Burnable, ERC20Permit. No upgrade mechanism exists in the contract.",
- "urls": [
- {
- "name": "ENA.sol Source",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "warning",
- "notes": "ENA has rate-limited but discretionary minting controlled by the Dev Multisig. Maximum 10% of total supply per mint, with 365-day cooldown between mints. No tokenholder approval required. Total supply is 15 billion ENA.",
- "evidence": [
- {
- "name": "Mint Function",
- "summary": "The `mint()` function allows the owner to create new tokens subject to two constraints:\n\n**MAX_INFLATION = 10** (10% of total supply per mint)\n\n**MINT_WAIT_PERIOD = 365 days** (minimum time between mints)\n\nOwner (Dev Multisig) can invoke without tokenholder approval.",
- "urls": [
- {
- "name": "ENA.sol `mint()` function (lines 42-49)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol#L42-L49",
- "type": "github"
- },
- {
- "name": "ENA Token totalSupply",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "warning",
- "notes": "Gatekeepers can disable USDe minting/redemption globally. Only the Owner can re-enable. The StakingRewardsDistributor operator (a single EOA) controls when rewards are distributed to sUSDe stakers.",
- "evidence": [
- {
- "name": "Privileged Roles (per Multisig Matrix)",
- "summary": "**Owner (EthenaMinting):** Can set max mint/redeem limits for USDe, add/remove collateral assets and custodians.\n\n**Admin (EthenaMinting):** Can grant/revoke Minter, Redeemer, Gatekeeper roles.\n\n**Gatekeeper:** Can call `disableMintRedeem()` to halt USDe operations globally.\n\n**Operator (StakingRewardsDistributor):** Single EOA that controls `transferInRewards()` to distribute USDe to sUSDe stakers.",
- "urls": [
- {
- "name": "Multisig Matrix Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-trust-assumptions/matrix-of-multisig-and-timelocks",
- "type": "docs"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Gatekeeper Powers",
- "summary": "Gatekeepers can halt but **only the Owner can re-enable**. This creates asymmetric power.",
- "urls": [
- {
- "name": "`disableMintRedeem()` (line 278)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L278",
- "type": "github"
- },
- {
- "name": "`removeMinterRole()` (line 339)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L339",
- "type": "github"
- },
- {
- "name": "`removeRedeemerRole()` (line 345)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/EthenaMinting.sol#L345",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "warning",
- "notes": "The ENA base token has no blacklist capability. However, sENA and sUSDe staking contracts include BLACKLIST_MANAGER_ROLE with freeze and seizure powers. FULL_RESTRICTED addresses cannot transfer tokens, and `redistributeLockedAmount()` allows admin to seize frozen assets.",
- "evidence": [
- {
- "name": "sENA/sUSDe Blacklist Capabilities",
- "summary": "StakedUSDe.sol defines three restriction roles:\n\n**SOFT_RESTRICTED_STAKER_ROLE:** Cannot stake/unstake\n\n**FULL_RESTRICTED_STAKER_ROLE:** Cannot transfer at all (frozen)\n\n**BLACKLIST_MANAGER_ROLE:** Can assign restrictions\n\nThe `redistributeLockedAmount()` function allows admin to seize and redistribute frozen assets.",
- "urls": [
- {
- "name": "StakedUSDe.sol blacklist roles (lines 26-32)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L26-L32",
- "type": "github"
- },
- {
- "name": "`redistributeLockedAmount()` (lines 106-127)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakedUSDe.sol#L106-L127",
- "type": "github"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "No active programmatic value accrual to ENA holders. **sUSDe holders receive USDe yield** from protocol operations; **sENA holders do NOT receive this yield**, only ecosystem airdrops. rsENA holders receive Symbiotic restaking rewards. Treasury flows through multisig-controlled wallets. All accrual mechanisms are controlled by multisigs or EOAs, not tokenholders.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "warning",
- "notes": "**sUSDe holders receive USDe yield; sENA/ENA holders do NOT.** sENA holders receive only ecosystem airdrops from Ethena Network protocols. rsENA (~5.2M supply) earns Symbiotic restaking rewards via Mellow Finance. Fee switch (which would share protocol revenue with sENA) received positive forum signals but awaits Snapshot vote and execution.",
- "evidence": [
- {
- "name": "Fee Switch Status",
- "summary": "Forum posts received positive signals in November 2024. USDe supply ~5.98B (the $6B threshold has **not** been met). Cumulative revenue $500M+ as of Sept 2025. Activation requires Risk Committee sign-off + Snapshot vote + multisig execution.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "USDe Token (verify totalSupply)",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#readContract",
- "type": "explorer"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Ethena Network Airdrops",
- "summary": "Protocols in the Ethena Network commit portions of their token supply to sENA holders. Example: Ethereal committed 15% of tokens to sENA holders.",
- "urls": [
- {
- "name": "Ethena Network Documentation",
- "url": "https://docs.ethena.fi/ethena-network",
- "type": "docs"
- }
- ]
- },
- {
- "name": "rsENA (Restaked ENA via Symbiotic)",
- "summary": "rsENA (~5.2M supply) provides economic security for USDe cross-chain transfers using LayerZero DVN messaging via Symbiotic partnership. rsENA holders receive rewards in **ENA and USDe** per docs. Available via **Mellow Finance vault**.",
- "urls": [
- {
- "name": "rsENA Contract",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#readContract",
- "type": "explorer"
- },
- {
- "name": "ENA Staking Documentation",
- "url": "https://docs.ethena.fi/ena",
- "type": "docs"
- },
- {
- "name": "Mellow Finance rsENA Vault",
- "url": "https://app.mellow.finance/vaults/ethereum-rsena",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "warning",
- "notes": "Protocol revenue flows through multisig-controlled wallets. **Treasury is NOT tokenholder-controlled.** Revenue flows: Hot Swap → sUSDe Payout → StakingRewardsDistributor → sUSDe stakers. ENA tokenholders do NOT control treasury flows.",
- "evidence": [
- {
- "name": "Revenue Flow",
- "summary": "Protocol Operations (delta-neutral strategies)\n→ **Hot Swap Multisig** (receives revenue, converts to USDe)\n→ **sUSDe Payout Multisig**\n→ **StakingRewardsDistributor**\n→ sUSDe Stakers\n\nENA/sENA holders are NOT in this flow unless fee switch activates.",
- "urls": [
- {
- "name": "Key Addresses Documentation",
- "url": "https://docs.ethena.fi/solution-design/key-addresses",
- "type": "docs"
- },
- {
- "name": "Hot Swap Multisig (revenue receiver)",
- "url": "https://etherscan.io/address/0x4423198f26764a8ce9ac8f1683c476854c885d9d",
- "type": "explorer"
- },
- {
- "name": "sUSDe Payout Multisig",
- "url": "https://etherscan.io/address/0x71e4f98e8f20c88112489de3dded4489802a3a87",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Reserve Fund (Negative Funding Backup)",
- "summary": "Separate from revenue treasury. Used only for negative funding emergencies. NOT tokenholder-controlled.",
- "urls": [
- {
- "name": "Reserve Fund Multisig",
- "url": "https://etherscan.io/address/0x2b5ab59163a6e93b4486f6055d33ca4a115dd4d5",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "warning",
- "notes": "All ENA value accrual mechanisms are controlled by multisigs or EOAs, **NOT** by ENA tokenholders. Fee switch requires discretionary multisig execution. Ecosystem airdrops are Foundation-negotiated. sENA/rsENA can be upgraded without tokenholder vote.",
- "evidence": [
- {
- "name": "ENA Value Accrual Controls",
- "summary": "**Fee Switch Activation:** Dev Multisig + Risk Committee. Snapshot votes are advisory only.\n\n**Ethena Network Airdrops:** Ethena Foundation negotiates allocations.\n\n**sENA Upgrade:** Dev Multisig via ProxyAdmin. Unilateral, no timelock.\n\n**rsENA Upgrade:** Separate multisig. Unilateral, no timelock.\n\n**rsENA Restaking Rewards:** Symbiotic integration.\n\n**Upgrade Risk:** Contract upgrades could modify or eliminate value accrual mechanisms without tokenholder approval.",
- "urls": [
- {
- "name": "Fee Switch Parameters Proposal",
- "url": "https://gov.ethenafoundation.com/t/ena-fee-switch-parameters/396",
- "type": "docs"
- },
- {
- "name": "sENA ProxyAdmin",
- "url": "https://etherscan.io/address/0xf849d7792ff9b30a57656ee10a2776bcb49f4fe4",
- "type": "explorer"
- },
- {
- "name": "rsENA ProxyAdmin Owner (5-of-8 Multisig)",
- "url": "https://etherscan.io/address/0x27a907d1f809e8c03d806dc31c8e0c545a3187fc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Tokenholder Cannot Force Activation",
- "summary": "Even with majority sENA/ENA support, tokenholders cannot force fee switch activation or change airdrop terms. Snapshot votes signal preference but the Dev Multisig decides execution. No onchain mechanism exists for binding governance over value accrual.",
- "urls": [
- {
- "name": "Governance Documentation",
- "url": "https://docs.ethena.fi/solution-overview/governance",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "warning",
- "notes": "USDe yield comes from three sources: CEX funding rates (unverifiable), ETH staking (~3-4%), and Treasury/BUIDL (~4-5%). **This yield flows to sUSDe stakers only; ENA/sENA holders receive none of it.** Revenue is controlled by multisigs, not programmatic.",
- "evidence": [
- {
- "name": "USDe Yield Sources",
- "summary": "**CEX Funding Rates:** Delta-neutral hedging (long spot, short perps). Variable 5-20%+ yield. Not verifiable onchain (CEX positions).\n\n**ETH Staking:** stETH/wBETH collateral earns validator rewards (~3-4%). Partially verifiable (collateral visible).\n\n**Treasury/BUIDL:** USDtb backed by BlackRock BUIDL fund (~4-5%). Partially verifiable (USDtb holdings).",
- "urls": [
- {
- "name": "Coin Metrics Analysis (USDe Yield Sources)",
- "url": "https://coinmetrics.substack.com/p/state-of-the-network-issue-335",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Yield Distribution Flow",
- "summary": "1. Yield generated offchain (CEX funding) and onchain (staking, treasury)\n2. Revenue settles through Copper ClearLoop custody (offchain)\n3. Hot Swap multisig receives and converts to USDe\n4. sUSDe Payout multisig transfers to StakingRewardsDistributor\n5. Operator EOA calls `transferInRewards()` to distribute to **sUSDe stakers only**\n\n**ENA/sENA holders do NOT receive USDe yield.**",
- "urls": [
- {
- "name": "`transferInRewards()` (lines 88-94)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/StakingRewardsDistributor.sol#L88-L94",
- "type": "github"
- },
- {
- "name": "DefiLlama - Ethena Fees",
- "url": "https://defillama.com/protocol/ethena",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "All core contracts are verified on Etherscan and open source on GitHub. Multiple security audits completed.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The ENA token contract is verified on Etherscan and matches the source code on GitHub. Solidity version 0.8.20, GPL-3.0 license.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ENA Token (Etherscan)",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "ENA.sol Source (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan. Most have open source GitHub repos. **sENA is verified on Etherscan but no public GitHub repo has been identified.** Multiple audits completed.",
- "evidence": [
- {
- "name": "Verified Contracts",
- "urls": [
- {
- "name": "ENA Token",
- "url": "https://etherscan.io/address/0x57e114B691Db790C35207b2e685D4A43181e6061#code",
- "type": "explorer"
- },
- {
- "name": "sENA Proxy",
- "url": "https://etherscan.io/address/0x8bE3460A480c80728a8C4D7a5D5303c85ba7B3b9#code",
- "type": "explorer"
- },
- {
- "name": "rsENA Proxy",
- "url": "https://etherscan.io/address/0xc65433845ecd16688eda196497fa9130d6c47bd8#code",
- "type": "explorer"
- },
- {
- "name": "USDe Token",
- "url": "https://etherscan.io/address/0x4c9edd5852cd905f086c759e8383e09bff1e68b3#code",
- "type": "explorer"
- },
- {
- "name": "sUSDe Token",
- "url": "https://etherscan.io/address/0x9d39a5de30e57443bff2a8307a4256c8797a3497#code",
- "type": "explorer"
- },
- {
- "name": "EthenaMinting V2",
- "url": "https://etherscan.io/address/0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3#code",
- "type": "explorer"
- },
- {
- "name": "StakingRewardsDistributor",
- "url": "https://etherscan.io/address/0xf2fa332bd83149c66b09b45670bce64746c6b439#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "GitHub Repository",
- "urls": [
- {
- "name": "Ethena Public Assets (GitHub)",
- "url": "https://github.com/ethena-labs/bbp-public-assets",
- "type": "github"
- }
- ]
- },
- {
- "name": "Audits",
- "urls": [
- {
- "name": "Code4rena 2023 Audit",
- "url": "https://github.com/code-423n4/2023-10-ethena",
- "type": "github"
- },
- {
- "name": "Code4rena 2024 Audit",
- "url": "https://github.com/code-423n4/2024-11-ethena-labs",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "70% insider allocation. Vesting unlocks continue through April 2028 for all categories. Circulating supply is approximately 55% of total.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "warning",
- "notes": "Initial allocation heavily favors insiders: Core Contributors (30%), Investors (25%), Foundation (15%), Ecosystem Development (28%), Binance Launchpool (2%). The combined insider bloc (Contributors + Investors + Foundation) controls **70%** of total supply.",
- "evidence": [
- {
- "name": "Token Allocation",
- "summary": "Total supply: 15 billion ENA.\nCirculating: ~8.2 billion (55%).\nLocked: ~6.8 billion (45%).\n\n**Insider bloc:** Contributors (30%) + Investors (25%) + Foundation (15%) = 70%",
- "urls": [
- {
- "name": "Tokenomist.ai - ENA",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- },
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "warning",
- "notes": "Monthly unlocks continue for all vesting categories through April 2028. Contributors, Investors, and Ecosystem receive linear monthly unlocks. Foundation allocation has no disclosed vesting.",
- "evidence": [
- {
- "name": "Vesting Schedules",
- "summary": "**Core Contributors** (30%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Investors** (25%): 1-year cliff (25%), then 3-year linear monthly. Full unlock ~April 2028.\n\n**Ecosystem Development** (28%): Linear over 4 years. Full unlock ~April 2028.\n\n**Foundation** (15%): Discretionary, no vesting disclosed.\n\nNext unlock: March 2, 2026 (~40.6M ENA to Contributors).",
- "urls": [
- {
- "name": "ENA Tokenomics Documentation",
- "url": "https://docs.ethena.fi/ena/tokenomics",
- "type": "docs"
- },
- {
- "name": "Tokenomist.ai - ENA Vesting",
- "url": "https://tokenomist.ai/ethena",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Trademarks and IP owned by Ethena (BVI) Limited, not controlled by ENA tokenholders. Primary interfaces operate under BVI law. Code is open source but copyright belongs to Ethena Labs.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Trademarks and brand assets are owned by **Ethena (BVI) Limited** (Registration number 2127704), a British Virgin Islands entity. Per Terms of Service: \"The Company's name, trademarks and logos... are trademarks of the Company or its affiliates.\" This entity is NOT controlled by ENA tokenholders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The primary interface domain (ethena.fi) and Terms of Service identify **Ethena (BVI) Limited** as the contracting party, governed by British Virgin Islands law. ENA holders have no legal claim or control over the primary interface.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Smart contract code is licensed under GPL-3.0, making it open source. However, per Terms of Service: \"the Company and/or its licensors own all right, title and interest in and to the Services.\" Copyright belongs to Ethena Labs. ENA holders do NOT control IP or licensing rights.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Ethena GitHub License",
- "url": "https://github.com/ethena-labs/bbp-public-assets/blob/main/contracts/contracts/ENA.sol",
- "type": "github"
- },
- {
- "name": "Ethena Terms of Service",
- "url": "https://docs.ethena.fi/resources/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "ldo": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "LDO holders exercise ultimate control through a multi-step governance flow with stETH holder veto protection via Dual Governance. All critical roles flow through governance-controlled contracts. The token has unbounded supply controlled by governance, with token behavior modifiable through controller upgrades.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "LDO holders exercise control through multiple governance paths with stETH holder veto protection via Dual Governance.",
- "evidence": [
- {
- "name": "Governance 1A",
- "summary": "Voting (LDO holders) → DualGovernance (stETH challenge window) → EmergencyProtectedTimeLock (time delay) → Executor → Agent → Protocol Contracts. LDO holders have ultimate control, constrained by stETH right to exit when disagreeing. This flow is used for protocol-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- },
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Governance 1B",
- "summary": "Voting (LDO holders) → Protocol Contracts. This flow is used for DAO-related contracts.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Easy Track",
- "summary": "An optimistic governance system where certain operations can be vetoed by LDO holders but are assumed to pass. Used for granting, treasury operations, and staking module management. Motions pass automatically unless ≥0.5% LDO objects within 72 hours. Permissionless execution post-timelock if unopposed; rejected motions escalate to full Aragon vote.",
- "urls": [
- {
- "name": "Easy Track Interface",
- "url": "https://easytrack.lido.fi/",
- "type": "docs"
- },
- {
- "name": "Easy Track Guide",
- "url": "https://docs.lido.fi/guides/easy-track-guide",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring LDO holders maintain ultimate control over the protocol.",
- "evidence": [
- {
- "name": "Voting",
- "summary": "CREATE_VOTES_ROLE allows proposing votes. All LDO holders can vote on proposals. The Voting contract controls the Agent via Governance 1A flow.",
- "urls": [
- {
- "name": "Voting",
- "url": "https://etherscan.io/address/0xe478de485ad2fe566d49342cbd03e49ed7db3356#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Agent",
- "summary": "EXECUTE_ROLE is given to Executor. Executor is owned by EmergencyProtectedTimeLock, which is controlled by Governance 1A, which is controlled by Voting contract.",
- "urls": [
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "TokenManager",
- "summary": "MINT_ROLE is given to Voting contract. BURN_ROLE is given to no one, but its permission manager is Voting contract.",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "StakingRouter",
- "summary": "STAKING_MODULE_MANAGE_ROLE is given to Agent contract. Since Agent is only callable by Governance 1, all operations are controlled by LDO holders.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Protocol contracts are upgradeable by LDO holders. Core governance contracts (DualGovernance, Executor, EmergencyProtectedTimeLock) are non-upgradeable.",
- "evidence": [
- {
- "name": "Upgradeable Contracts",
- "summary": "StakingRouter: proxy_getAdmin is set to Agent.\n\nAgent: Uses Aragon v1 Proxy. Upgrading requires calling setApp(Agent, ...) on the Kernel, which requires APP_MANAGER_ROLE (currently given to Agent itself).",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- },
- {
- "name": "Agent",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Non-upgradeable Contracts",
- "summary": "DualGovernance, Executor, and EmergencyProtectedTimeLock are immutable contracts that cannot be upgraded.",
- "urls": [
- {
- "name": "DualGovernance",
- "url": "https://etherscan.io/address/0xC1db28B3301331277e307FDCfF8DE28242A4486E#code",
- "type": "explorer"
- },
- {
- "name": "Executor",
- "url": "https://etherscan.io/address/0x23E0B465633FF5178808F4A75186E2F2F9537021#code",
- "type": "explorer"
- },
- {
- "name": "EmergencyProtectedTimeLock",
- "url": "https://etherscan.io/address/0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "LDO token is immutable but **partially upgradeable** in practice due to its controller (TokenManager) being upgradeable via Aragon proxy.",
- "evidence": [
- {
- "name": "Token Contract",
- "summary": "The LDO token contract is immutable with no proxy pattern. However, it has a controller address (TokenManager) that can call privileged functions (generateTokens, destroyTokens, enableTransfers, claimTokens). The token's doTransfer function includes a hook that calls the controller.",
- "urls": [
- {
- "name": "LDO Token",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Controller Upgrade Path",
- "summary": "TokenManager is upgradeable via Aragon proxy. Upgrading requires calling setApp(tokenManager, ...) on the Kernel, protected by APP_MANAGER_ROLE, which is assigned to the Agent contract (hence LDO holders).",
- "urls": [
- {
- "name": "TokenManager (Aragon App V1 proxy)",
- "url": "https://etherscan.io/address/0xf73a1260d222f447210581DDf212D915c09a3249",
- "type": "explorer"
- },
- {
- "name": "Kernel",
- "url": "https://etherscan.io/address/0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "No supply cap exists, but all mints require LDO tokenholder approval through the Voting contract.",
- "evidence": [
- {
- "name": "Minting Path",
- "summary": "The LDO token's controller (TokenManager) can mint unlimited tokens. However, minting requires MINT_ROLE on TokenManager, which is held by the Voting contract.\n\nMinting path: Voting (LDO holders) → TokenManager → Token.generateTokens()",
- "urls": [
- {
- "name": "MiniMeToken.generateTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L385",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "Deposits are operationally executed by Guardians (node operators + LDO dev team), but Guardians are fully accountable to LDO holders and cannot control protocol parameters.",
- "evidence": [
- {
- "name": "Guardian Role",
- "summary": "User funds deposited into Lido are accumulated in the buffer and can only be deposited into a staking module by DepositSecurityModule, controlled by Guardians. Guardians use automated software for deposit operations.",
- "urls": [
- {
- "name": "DepositSecurityModule",
- "url": "https://etherscan.io/address/0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD#code",
- "type": "explorer"
- },
- {
- "name": "Lido.sol deposit logic",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L641",
- "type": "github"
- },
- {
- "name": "Guardians use automated software",
- "url": "https://docs.lido.fi/guides/deposit-security-manual/#tldr",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Guardian Accountability",
- "summary": "Guardians are fully accountable to LDO holders—they can be rotated, replaced, or their mandate changed through onchain voting. Guardians do not control protocol parameters or economic risk (staking ratios, fee splits, module shares, or risk parameters).",
- "urls": [
- {
- "name": "Guardian Committee Membership",
- "url": "https://docs.lido.fi/guides/deposit-security-manual#committee-membership",
- "type": "docs"
- },
- {
- "name": "Guardians cannot control stake allocation",
- "url": "https://github.com/lidofinance/core/blob/d5d92266b5bb305044c5dcf3e407463f776a4def/contracts/0.4.24/Lido.sol#L647",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "Controller has burn and transfer-disable capabilities, but BURN_ROLE is currently unassigned. Enabling burning requires LDO governance approval.",
- "evidence": [
- {
- "name": "Burn Capability",
- "summary": "Controller can burn tokens from any address via destroyTokens. Currently, BURN_ROLE on TokenManager is given to no one, but permission manager is Voting contract. To enable burning, proposal must go through Governance 1B to call setPermission on ACL.",
- "urls": [
- {
- "name": "MiniMeToken.destroyTokens",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L401",
- "type": "github"
- },
- {
- "name": "Aragon ACL",
- "url": "https://etherscan.io/address/0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Transfer Control",
- "summary": "Controller can enable/disable transfers globally via enableTransfers function.",
- "urls": [
- {
- "name": "MiniMeToken.enableTransfers",
- "url": "https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L419",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "Protocol revenue flows to the LDO-controlled DAO treasury, and a newly approved manual buyback program (up to 10,000 stETH, held by the treasury) creates net buy pressure on LDO, though not a direct distribution. Treasury is controlled by LDO holders; offchain IP is held by DAO-controlled BORG foundations.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "**Protocol fee flow to treasury:**\n- Lido charges a 10% protocol fee on all ETH staking rewards, split onchain by the StakingRouter into a module fee (to node operators) and a treasury fee (to the LDO-controlled DAO Agent).\n- Calling `getStakingFeeAggregateDistribution()` on the StakingRouter currently returns an aggregated treasury fee of ~6.15% and module fees of ~3.85% (basePrecision = 100), meaning ~6.15% of all ETH staking rewards accrue to the DAO treasury on every oracle report.\n\n**Buyback program:**\n- Governance has authorized the Lido Growth Committee to buy back LDO using up to 10,000 stETH (from the accumulated fee described above), in 1,000 stETH batches via Easy Track motions (3-day objection window for LDO holders, 3% max slippage) while a favorable LDO/stETH ratio persists. Execution spans onchain (CoW, 1inch, Uniswap) and offchain venues (Binance, Bybit, OKX, Gate, Bitget).\n- This is independent of the anticipated automated NEST buybacks in Q2 2026. Value accrues to the LDO-controlled DAO treasury (buyback-and-hold), but is not directly distributed to LDO holders.",
- "evidence": [
- {
- "name": "Treasury Fee Flow",
- "urls": [
- {
- "name": "StakingRouter (read contract)",
- "url": "https://etherscan.io/address/0xFdDf38947aFB03C621C71b06C9C70bce73f12999#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "StakingRouter.sol#L1051 (getStakingFeeAggregateDistribution)",
- "url": "https://github.com/lidofinance/core/blob/master/contracts/0.8.9/StakingRouter.sol#L1051",
- "type": "github"
- }
- ]
- },
- {
- "name": "Buyback Program",
- "urls": [
- {
- "name": "stETH/LDO Buyback Proposal",
- "url": "https://research.lido.fi/t/utilizing-market-opportunities-steth-ldo-trade/11358",
- "type": "docs"
- },
- {
- "name": "stETH/LDO Buyback Snapshot Vote",
- "url": "https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x43be9ee8ce820d444f706e9dd763a223ebabf37be27931cc056888e6c2e48814",
- "type": "vote"
- },
- {
- "name": "NEST",
- "url": "https://research.lido.fi/t/nest-network-economic-support-tokenomics/10648",
- "type": "docs"
- },
- {
- "name": "Liquid buybacks research",
- "url": "https://research.lido.fi/t/liquid-buybacks-nest-execution-with-ldo-wsteth-liquidity/10894",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "Treasury is the Agent contract, fully controlled by LDO holders. Treasury decisions are excluded from Governance 1 scope (stETH holders cannot challenge).",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The Lido DAO Treasury is the Agent contract itself. The Treasury Management Committee proposes and enacts strategies via Governance 2 (Easy Track). All treasury decisions are controlled by LDO holders.",
- "urls": [
- {
- "name": "Agent (Treasury)",
- "url": "https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "LDO holders, via Governance 1A, control treasury revenue by approving staking modules and setting each module's treasury fee in the StakingRouter. This fee determines the portion of staking rewards routed to the Lido treasury.",
- "urls": [
- {
- "name": "StakingRouter",
- "url": "https://etherscan.io/address/0xfddf38947afb03c621c71b06c9c70bce73f12999#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "To add a new staking module or update it with new fees, full governance flow required, hence controlled by LDO holders.",
- "evidence": [
- {
- "urls": [
- {
- "name": "StakingRouter add/update",
- "url": "https://github.com/lidofinance/core/blob/cca04b42123735714d8c60a73c2f7af949e989db/contracts/0.8.9/StakingRouter.sol#L227",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon has not verified additional offchain value accrual flows to the LDO token",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "LDO token source is publicly available and verified on Etherscan. Lido core protocol contracts are open source and verified.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The LDO token contract source code is publicly available on GitHub (MiniMeToken) and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LDO Token (Etherscan)",
- "url": "https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32#code",
- "type": "explorer"
- },
- {
- "name": "MiniMeToken Source (GitHub)",
- "url": "https://github.com/aragon/minime",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Lido core protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Core Contracts (GitHub)",
- "url": "https://github.com/lidofinance/core",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Aragon has not yet verified the distribution of LDO holders outside of the core team.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the distribution of LDO holders outside of the core team is greater than 50%",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified the supply schedule criteria for the LDO token",
- "evidence": []
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "European trademark registrations for LIDO list Lido Labs Foundation as the owner. Lido Labs, Ecosystem, and Alliance BORG Foundations are DAO-controlled entities managing offchain IP and distribution.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "positive",
- "notes": "European trademark registrations for LIDO list Lido Labs Foundation as the owner.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UK IPO Trademark Journal",
- "url": "https://www.ipo.gov.uk/types/tm/t-os/t-tmj/tm-journals/2025-045/UK00004285645.html",
- "type": "docs"
- },
- {
- "name": "Lido Logo",
- "url": "https://euipo.europa.eu/eSearch/#details/trademarks/019182074",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "positive",
- "notes": "Lido Labs BORG Foundation, Lido Ecosystem BORG Foundation, Lido Alliance BORG Foundation is a memberless DAO-adjacent foundation companies under which the Lido DAO has defined governance controls (including appointing/removing directors and overseeing BORG structures).",
- "evidence": [
- {
- "urls": [
- {
- "name": "Lido Labs BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xdf648307e68415e7b5cf96c6afbabd696c1731839f4b4a7cf5cb7efbc44ee9d6",
- "type": "docs"
- },
- {
- "name": "Lido Ecosystem BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0x7f72f12d72643c20cd0455c603d344050248e75ed1074c8391fae4c30f09ca15",
- "type": "docs"
- },
- {
- "name": "Lido Alliance BORG Foundation",
- "url": "https://snapshot.org/#/s:lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "lqty": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "LQTY holders' onchain power is voting on V2 Protocol Incentivized Liquidity (PIL) emissions. The rest of the protocol is described as \"Governance Free\" with immutable contracts and no admin keys, upgrade paths, or privileged roles.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "Neither LQTY holders nor the protocol team can influence core protocol execution - all core protocol parameters are immutable after launch. LQTY holders' onchain governance role is limited to voting on Protocol Incentivized Liquidity (PIL) emissions, directing a portion of V2 revenue to community-chosen liquidity initiatives.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "There are no privileged roles in the core protocol. All core protocol contracts are immutable after launch with no admin functions, owners, or upgrade keys.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Core Liquity protocol contracts are non-upgradeable and do not use proxy patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The LQTY token contract is immutable with no proxy patterns or upgrade mechanisms.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token Source",
- "url": "https://etherscan.io/token/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "Fixed 100M LQTY token supply. No mint() function or inflation pathway in the bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "The only LQTY token minting transactions ever, amounting to 100M LQTY tokens",
- "url": "https://etherscan.io/advanced-filter?tkn=0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d&txntype=2&fadd=0x0000000000000000000000000000000000000000",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "No privileged roles. The only thing LQTY holders can do is vote for PIL emissions.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity - Governance-Free",
- "url": "https://www.liquity.org/features/governance-free",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "No Guardian or blacklist capabilities exist in the LQTY token contract.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY token's implementation code",
- "url": "https://etherscan.io/address/0x6dea81c8171d0ba574754ef6f8b412f2ed88c54d#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "Stakers earn two live onchain streams: V1 protocol fees (ETH redemption fees + LUSD borrowing fees) routed directly to LQTYStaking, and V2 bribes paid pro-rata to voters who allocate their voting power to initiatives. There is no protocol treasury - V2 sends 100% of revenue straight to users. Fee parameters and revenue routing are immutable and cannot be modified by governance or the team.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "LQTY holders receive two live, onchain value streams.\n\nLiquity V1 - protocol revenue to stakers. Staked LQTY earns fees routed directly to the V1 LQTYStaking contract: redemption fees (paid in ETH) are forwarded by TroveManager, and borrowing fees (paid in LUSD) are forwarded by BorrowerOperations. Every staker accrues a pro-rata share via the F_ETH and F_LUSD accumulators - no voting required.\n\nLiquity V2 - bribes to voters. V2 governance is built on top of V1 staking, so V2 participants automatically receive the V1 fee streams above. Stakers who additionally allocate their voting power to an initiative can claim a pro-rata share of bribes (BOLD plus an initiative-specific token) deposited by external parties for that epoch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "TroveManager.sol - V1 redemption fee → increaseF_ETH",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/TroveManager.sol#L1011-L1012",
- "type": "github"
- },
- {
- "name": "BorrowerOperations.sol - V1 borrowing fee → increaseF_LUSD",
- "url": "https://github.com/liquity/dev/blob/3e64ee1b52c50d51587c64c1cf75e0ba82934979/packages/contracts/contracts/BorrowerOperations.sol#L370",
- "type": "github"
- },
- {
- "name": "Liquity docs - LQTY staking (V1 revenue + V2 bribes)",
- "url": "https://docs.liquity.org/v2-faq/lqty-staking",
- "type": "docs"
- },
- {
- "name": "V2-gov Governance.sol - depositLQTY (V2 deposit stakes into V1)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L162",
- "type": "github"
- },
- {
- "name": "V2-gov Governance.sol - allocateLQTY (vote on initiatives)",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/Governance.sol#L584",
- "type": "github"
- },
- {
- "name": "V2-gov BribeInitiative.sol - depositBribe / claimBribes",
- "url": "https://github.com/liquity/V2-gov/blob/main/src/BribeInitiative.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "There is no protocol treasury. Liquity V2 skips the concept of a centralized treasury and sends 100% of its revenue straight to its users.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Docs",
- "url": "https://www.liquity.org/blog/liquity-v2-is-live",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "The V1 fee accrual mechanism is immutable - neither the core team nor LQTY holders can change the fee parameters or the routing of fees to the LQTYStaking contract, since the core protocol contracts are non-upgradeable and expose no admin or governance hooks over these parameters. V2 governance (PIL + bribes) lets LQTY voters direct a separate slice of V2 revenue to liquidity initiatives, but explicitly has no control over core protocol parameters, which are immutable after launch.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity v2 Technical Docs and Audits",
- "url": "https://docs.liquity.org/v2-documentation/technical-docs-and-audits",
- "type": "docs"
- },
- {
- "name": "Directing Protocol Incentivized Liquidity with LQTY",
- "url": "https://www.liquity.org/blog/directing-protocol-incentivized-liquidity-with-lqty",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "The protocol is entirely onchain - Aragon is not aware of any offchain entities towards which value accrues to the LQTY token or otherwise.",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "Both the LQTY token and core Liquity protocol contracts (V1 and V2) are open source on GitHub and source-verified against their onchain deployments - no closed-source components or unverified bytecode.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The LQTY token contract source code (LQTYToken.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LQTY Token (Etherscan)",
- "url": "https://etherscan.io/address/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D#code",
- "type": "explorer"
- },
- {
- "name": "LQTYToken.sol Source (GitHub)",
- "url": "https://github.com/liquity/dev/blob/main/packages/contracts/contracts/LQTY/LQTYToken.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Liquity protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity V2 Core (GitHub)",
- "url": "https://github.com/liquity/bold",
- "type": "github"
- },
- {
- "name": "Liquity V2 Governance (GitHub)",
- "url": "https://github.com/liquity/V2-gov",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "LQTY supply is fully circulating - team and investor lockups ended in 2022, leaving only the immutable Stability Pool emission schedule for V1 depositors. Concentration among third parties has not yet been independently verified.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "positive",
- "notes": "It's all circulating - vesting ended in 2022, which can be verified by looking at the events emitted by the `LockupContractFactory`. The only remaining non-circulating LQTY is what the contract releases on an immutable schedule to Stability Pool depositors in V1.",
- "evidence": [
- {
- "urls": [
- {
- "name": "LockupContractFactory (Etherscan)",
- "url": "https://etherscan.io/address/0x2eBeF24dA09489218Ba2BECb01867F6DaAeDcD4B#code",
- "type": "explorer"
- },
- {
- "name": "CommunityIssuance (Etherscan)",
- "url": "https://etherscan.io/address/0xD8c9D9071123a059C6E0A945cF0e0c82b508d816#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Offchain dependencies for LQTY (trademark/brand, primary domain, and core software licensing) are controlled by Liquity AG, a Swiss company. LQTY tokenholders have no governance rights or control over Liquity AG. The core V1 protocol is immutable and governance-free, but brand, distribution, and V2 IP rights remain with the company.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "fail",
- "notes": "The Liquity brand and related trademarks are owned and controlled by Liquity AG (Swiss company). No tokenholder-controlled legal entity is involved.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity AG - Crunchbase Company Profile",
- "url": "https://www.crunchbase.com/organization/liquity-1d3e",
- "type": "website"
- },
- {
- "name": "Liquity - Tracxn Company Profile",
- "url": "https://tracxn.com/d/companies/liquity/__jQEYCp-QRDCuYvGmSSmUBbFIO6piP9rk6HEjxXEsrH0",
- "type": "website"
- },
- {
- "name": "Team Page - Liquity.org",
- "url": "https://www.liquity.org/team",
- "type": "website"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "partial",
- "notes": "Liquity AG controls the primary domain liquity.org and the frontend registry. However, the company explicitly does not run any user-facing frontend. All frontends are operated by independent third parties. No tokenholder-controlled entity controls distribution.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Liquity Runs on Decentralized Frontends - Official Blog",
- "url": "https://www.liquity.org/blog/liquity-runs-on-decentralized-frontends",
- "type": "website"
- },
- {
- "name": "Frontend Operators Page",
- "url": "https://www.liquity.org/frontend-operators",
- "type": "website"
- },
- {
- "name": "Liquity Launch Details (AG does not run frontend)",
- "url": "https://www.liquity.org/blog/liquity-launch-details",
- "type": "website"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "fail",
- "notes": "Core protocol software and IP (V2) is owned by Liquity AG and released under a multi-year Business Source License (BUSL). Commercial deployments before ~September 2027 require approval from Liquity AG.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Licensing Liquity V2 - Official Blog",
- "url": "https://www.liquity.org/blog/licensing-liquity-v2-may-the-fork-be-with-you",
- "type": "website"
- },
- {
- "name": "Liquity V2 Core LICENSE File (GitHub)",
- "url": "https://github.com/liquity/bold/blob/main/contracts/LICENSE",
- "type": "github"
- },
- {
- "name": "What's New in Liquity V2 - Bankless",
- "url": "https://www.bankless.com/read/whats-new-in-liquity-v2",
- "type": "website"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "uni": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "UNI holders maintain ultimate control through onchain voting. The token is immutable with a hardcoded 2% annual inflation cap. All core contracts (V2, V3, V4) are non-upgradeable with no pause/freeze functions.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "UNI holders vote onchain via GovernorBravoDelegator, with execution through Timelock after a time delay.",
- "evidence": [
- {
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- },
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "All critical roles flow through governance-controlled contracts, ensuring UNI holders maintain ultimate control.",
- "evidence": [
- {
- "name": "V2 Factory",
- "summary": "feeToSetter is Timelock. Only feeToSetter can call setFeeTo() to change fee destination.",
- "urls": [
- {
- "name": "V2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Factory",
- "summary": "Owner is V3FeeAdapter, whose feeSetter is Timelock. Only Timelock can change V3 protocol fees.",
- "urls": [
- {
- "name": "V3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V4 PoolManager",
- "summary": "Owner is Timelock. Only owner can call setProtocolFeeController().",
- "urls": [
- {
- "name": "V4PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "UNI Token",
- "summary": "Minter is set to Timelock. Since Timelock is controlled by GovernorBravoDelegator, all minting operations are controlled by UNI holders.",
- "urls": [
- {
- "name": "UNI Token",
- "url": "https://etherscan.io/address/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984#code",
- "type": "explorer"
- },
- {
- "name": "Timelock (deployed minter)",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "All Uniswap protocol contracts (V2 Pairs, V3 Pools, V4 PoolManager, Timelock) are non-upgradeable. Only GovernorBravoDelegator is upgradeable, controlled by Timelock.",
- "evidence": [
- {
- "name": "Non-upgradeable Protocol Contracts",
- "summary": "V2 Pairs use Create2 deployment. V3 Pools use NoDelegateCall protection. V4 PoolManager uses Singleton design. All are immutable once deployed.",
- "urls": [
- {
- "name": "V2 Factory Create2",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L28-L31",
- "type": "github"
- },
- {
- "name": "V3 Pool Protection",
- "url": "https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L30",
- "type": "github"
- },
- {
- "name": "V4 PoolManager: Singleton",
- "url": "https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol#L93",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Governance Contract",
- "summary": "GovernorBravoDelegator is upgradeable, with the Admin role held by the Timelock. Any upgrade would require a governance vote by UNI holders.",
- "urls": [
- {
- "name": "GovernorBravoDelegator",
- "url": "https://etherscan.io/address/0x408ed6354d4973f66138c91495f2f2fcbd8724c3#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "Token contract is immutable with no proxy patterns, no delegatecall, no EIP-1967/UUPS patterns.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol Source",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- },
- {
- "name": "Etherscan",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "UNI has a hardcoded 2% annual inflation cap that cannot be changed. Minting is controlled by Timelock (hence UNI holders).",
- "evidence": [
- {
- "name": "Inflation Cap",
- "summary": "Mint can be called once per year, minting maximum 2% of total supply. mintCap is constant and cannot be changed.",
- "urls": [
- {
- "name": "Mint once per year logic",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L116",
- "type": "github"
- },
- {
- "name": "2% mint cap",
- "url": "https://github.com/Uniswap/governance/blob/eabd8c71ad01f61fb54ed6945162021ee419998e/contracts/Uni.sol#L120",
- "type": "github"
- }
- ]
- },
- {
- "name": "Minting Control",
- "summary": "Minter is set to Timelock, governed by UNI token holders through GovernorBravoDelegator.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "No pause/freeze functions in V2 Pair, V3 Pool, or V4 PoolManager core contracts. No admin backdoors to steal funds. No emergency withdrawal or sweep functions.",
- "evidence": []
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "No blacklist, whitelist, or pause functions in UNI token contract. Transfers cannot be censored. Standard ERC20 with no admin controls over transfers.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uni.sol",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol#L6",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "Protocol fees flow to governance-controlled destinations through TokenJar and FirePit burn mechanism. Treasury is entirely controlled by token holders.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "Protocol fees across all Uniswap versions flow to governance-controlled destinations (TokenJar). Value accrual is via burn mechanism - a burn can be initiated by anyone who chooses to burn 4,000 UNI to claim accumulated protocol fees from TokenJar via FirePit.",
- "evidence": [
- {
- "name": "V2 Fees",
- "summary": "All V2 pools are active. Fees go to FeeTo address which is set to TokenJar.",
- "urls": [
- {
- "name": "UniswapV2Pool: feeTo",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f#readContract",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Pool: Fee Destination",
- "url": "https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "V3 Fees",
- "summary": "V3FeeAdapter collects protocol fees by calling collectProtocol and sends them to TokenJar. The 4,000 UNI threshold can be changed by governance via Timelock in FirePit. Only select V3 pools are currently active.",
- "urls": [
- {
- "name": "V3FeeAdapter",
- "url": "https://etherscan.io/address/0x5E74C9f42EEd283bFf3744fBD1889d398d40867d#code",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: collectProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L848",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fees",
- "summary": "V4 fees have not been activated yet, but in the future fees can be activated via governance process as described in Onchain Governance Workflow. To activate fees, Timelock will set the PoolManager's ProtocolFeeController address to a V4FeeAdapter contract which contains logic for fee collection and distribution.",
- "urls": [
- {
- "name": "V4 PoolManager",
- "url": "https://etherscan.io/address/0x000000000004444c5dc75cB358380D2e3dE08A90#code",
- "type": "explorer"
- },
- {
- "name": "V4 PoolManager: CollectProtocolFees",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L48",
- "type": "github"
- }
- ]
- },
- {
- "name": "Burn Mechanism",
- "summary": "The 4,000 UNI threshold can be changed by governance via Timelock in FirePit.",
- "urls": [
- {
- "name": "FirePit 4000 UNI Requirement",
- "url": "https://github.com/Uniswap/protocol-fees/blob/8604e4b9aed88bdd6be3a322e19722c40f94be2c/src/releasers/ExchangeReleaser.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The Uniswap Governance Timelock, often referred to as the Treasury, is entirely controlled by token holders. At the time of writing, it held approximately 264m UNI tokens. Funds held in Timelock require UNI governance proposals to execute transfers, ensuring tokenholder control.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "Token holders control fee routing and burn threshold across all versions through Timelock-governed ownership.",
- "evidence": [
- {
- "name": "V2 Fee Control",
- "summary": "feeToSetter is set to Timelock on UniswapV2Factory. Only feeToSetter can call setFeeTo to change the fee destination. Protocol fees can only be enabled or disabled, not adjusted. Protocol fees on V2 pools cannot be adjusted on a per pool basis.",
- "urls": [
- {
- "name": "Timelock",
- "url": "https://etherscan.io/address/0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
- "type": "explorer"
- },
- {
- "name": "UniswapV2Factory",
- "url": "https://etherscan.io/address/0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "V3 Fee Control",
- "summary": "Owner of UniswapV3Factory is V3FeeAdapter, whose owner is Timelock. V3FeeAdapter's owner can call setOwner on V3FeeAdapter, which passes the call through to UniswapV3Factory. Using this method, V3FeeAdapter's owner can change the owner of the UniswapV3Factory to a new V3FeeAdapter. The pools collecting protocol fees as well as the protocol fee percentage per pool can be changed by the pool owner via setFeeProtocol",
- "urls": [
- {
- "name": "UniswapV3Factory",
- "url": "https://etherscan.io/address/0x1f98431c8ad98523631ae4a59f267346ea31f984",
- "type": "explorer"
- },
- {
- "name": "UniswapV3Pool: setFeeProtocol",
- "url": "https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L837",
- "type": "github"
- }
- ]
- },
- {
- "name": "V4 Fee Control",
- "summary": "Owner of V4PoolManager is set to Timelock. Only owner can call setProtocolFeeController to change the fee controller. Protocol fees can be modified by the ProtocolFeeController through setProtocolFee.",
- "urls": [
- {
- "name": "PoolManager(V4): setProtocolFee",
- "url": "https://github.com/Uniswap/v4-core/blob/d153b048868a60c2403a3ef5b2301bb247884d46/src/ProtocolFees.sol#L35",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "DUNI (Decentralized Unincorporated Nonprofit Association) provides legal capacity for the DAO to engage in off-chain activities such as tax compliance, legal defense, and contract execution. At the time of writing, there are no specific offchain value accrual mechanisms explicitly defined.",
- "evidence": [
- {
- "urls": [
- {
- "name": "DUNI Proposal",
- "url": "https://gov.uniswap.org/t/governance-proposal-establish-uniswap-governance-as-duni-a-wyoming-duna/25770",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "UNI token source is publicly available on GitHub and verified on Etherscan. Uniswap V2, V3, V4, and UniswapX protocol contracts are open source and verified.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The UNI token contract source code (Uni.sol) is publicly available on GitHub and verified on Etherscan.",
- "evidence": [
- {
- "urls": [
- {
- "name": "UNI Token (Etherscan)",
- "url": "https://etherscan.io/token/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984#code",
- "type": "explorer"
- },
- {
- "name": "Uni.sol Source (GitHub)",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/Uni.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Uniswap V2, V3, V4, and UniswapX protocol contracts are open source on GitHub.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap V2 Core (GitHub)",
- "url": "https://github.com/Uniswap/v2-core",
- "type": "github"
- },
- {
- "name": "Uniswap V3 Core (GitHub)",
- "url": "https://github.com/Uniswap/v3-core",
- "type": "github"
- },
- {
- "name": "Uniswap V4 Core (GitHub)",
- "url": "https://github.com/Uniswap/v4-core",
- "type": "github"
- },
- {
- "name": "UniswapX (GitHub)",
- "url": "https://github.com/Uniswap/UniswapX",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not yet verified that 3rd parties do not hold more than 50% of voting power",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "positive",
- "notes": "Four vesting contracts distributed UNI to the Governance Timelock over four years, ending in September 2024. There are no future unlocks.",
- "evidence": [
- {
- "name": "TreasuryVester Contracts",
- "summary": "UNI tokens were initially minted to an EOA, which transferred the Treasury's portion to four vesting contracts in varying amounts. Each TreasuryVester contract was configured with: uni, recipient, vestingAmount, vestingBegin, vestingCliff, vestingEnd.",
- "urls": [
- {
- "name": "TreasuryVester Code",
- "url": "https://github.com/Uniswap/governance/blob/master/contracts/TreasuryVester.sol",
- "type": "github"
- },
- {
- "name": "TreasuryVester 1",
- "url": "https://etherscan.io/address/0x4750c43867ef5f89869132eccf19b9b6c4286e1a",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 2",
- "url": "https://etherscan.io/address/0xe3953d9d317b834592ab58ab2c7a6ad22b54075d",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 3",
- "url": "https://etherscan.io/address/0x4b4e140d1f131fdad6fb59c13af796fd194e4135",
- "type": "explorer"
- },
- {
- "name": "TreasuryVester 4",
- "url": "https://etherscan.io/address/0x3d30b1ab88d487b0f3061f40de76845bec3f1e94",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Core trademark rights (UNISWAP, UNI, UNISWAP LABS) are held by Universal Navigation Inc. (Uniswap Labs). DUNI has a limited, non-exclusive trademark license but no ownership transfer has occurred. Uniswap Labs operates a user interface and API, but the permissionless smart contracts allow anybody to operate one.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Core trademark rights related to Uniswap Labs, including UNISWAP, UNI, and UNISWAP LABS, are held and enforceable by Universal Navigation Inc. d/b/a Uniswap Labs (\"Labs\").\n\nAfter the passing of the UNIfication proposal, in which Uniswap Labs entered into a service provider agreement with DUNI (formerly Uniswap Governance), Labs grants DUNI a non-exclusive, royalty-free, worldwide trademark license to use the UNISWAP mark solely in connection with DUNI's business, subject to Labs' trademark usage guidelines and limited to the term of the agreement.\n\nThe agreement does not transfer ownership of the UNISWAP mark or Labs' other trademarks to DUNI or token holders.\n\nAny broader assignment, or permanent or exclusive license, of Labs' trademarks to DUNI is explicitly deferred and would require a separate written agreement negotiated in the future.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Trademark Guidelines",
- "url": "https://support.uniswap.org/hc/en-us/articles/30934762216973-Uniswap-Labs-Trademark-Guidelines/",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Uniswap Labs operates a user interface and API, both of which are subject to Terms of Service. The permissionless nature of the Uniswap Protocol’s smart contracts means that any person or firm can operate an interface or API.",
- "evidence": [
- {
- "urls": [
- {
- "name": "Uniswap Labs Terms of Service",
- "url": "https://support.uniswap.org/hc/en-us/articles/30935100859661-Uniswap-Labs-Terms-of-Service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Uniswap Labs retains ownership of its pre-existing IP and trademarks. DUNI holds a limited, non-exclusive license to use the UNISWAP trademark for DUNI-related purposes, and generally receives rights to new deliverables under open-source licenses. No transfer of core Labs' IP has occurred; any broader licensing or assignment would require a separate agreement.",
- "evidence": []
- }
- ]
- }
- ],
- "yb": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "veYB holders control the protocol through Aragon governance. The YB token is non-upgradeable with renounced ownership. Protocol upgrades are controlled by the DAO through MigrationFactoryOwner. The veYB contract owner (_yb.eth) can change transfer clearance rules, but this does not constitute censorship—users remain custodians of their locked YB.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "veYB holders vote onchain via Aragon governance DAO. Proposals require **30% participation**, **55% support**, and a **7-day voting period**. Proposals can be executed before the full voting period concludes when mathematical certainty is achieved (thresholds met, remaining votes cannot change outcome). Minimum 1 veYB required to create proposals.",
- "evidence": [
- {
- "name": "Governance System",
- "summary": "Aragon governance DAO with TokenVoting Plugin. veYB implements standard IVotes interface for Aragon compatibility.",
- "urls": [
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- },
- {
- "name": "veYB (VotingEscrow)",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "TokenVoting Plugin",
- "url": "https://etherscan.io/address/0x2be6670DE1cCEC715bDBBa2e3A6C1A05E496ec78",
- "type": "explorer"
- },
- {
- "name": "Governance Documentation",
- "url": "https://docs.yieldbasis.com/user/governance",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "**DAO-controlled:** GaugeController, FeeDistributor, MigrationFactoryOwner (ADMIN immutable = DAO).\n\n**EOA-controlled:** veYB owner (_yb.eth) can change transfer clearance rules. However, transfer restrictions do not constitute censorship—users remain custodians of their locked YB and can always withdraw after lock expiry.",
- "evidence": [
- {
- "name": "DAO-Controlled Contracts",
- "summary": "GaugeController.owner() = DAO. FeeDistributor.owner() = DAO. MigrationFactoryOwner.ADMIN = DAO (immutable).",
- "urls": [
- {
- "name": "GaugeController",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- },
- {
- "name": "FeeDistributor",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "MigrationFactoryOwner",
- "url": "https://etherscan.io/address/0xa68343ed4d517a277cfa1f2fc2b51f7a6794b6ad",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "veYB Owner (_yb.eth)",
- "summary": "Can call set_transfer_clearance_checker() to change veYB transfer rules. This restricts veNFT transfers, NOT custody—users remain owners of their locked YB.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "set_transfer_clearance_checker",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L640-L647",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "The DAO controls protocol upgrades through MigrationFactoryOwner. This constitutes ownership—the indirection through governance is the standard mechanism for tokenholder control.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Factory.set_implementations() requires Factory admin = MigrationFactoryOwner. MigrationFactoryOwner requires ADMIN (immutable) = DAO.",
- "urls": [
- {
- "name": "Factory Contract",
- "url": "https://etherscan.io/address/0x370a449FeBb9411c95bf897021377fe0B7D100c0",
- "type": "explorer"
- },
- {
- "name": "Factory.set_implementations",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L389-L410",
- "type": "github"
- },
- {
- "name": "MigrationFactoryOwner ADMIN immutable",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L47",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "YB token is a **non-upgradeable** Vyper contract. Ownership has been **renounced** (owner = 0x0). No proxy pattern. Only GaugeController (set before renouncement) can mint via emit().",
- "evidence": [
- {
- "name": "Token Ownership",
- "summary": "owner() returns 0x0. Token uses standard ERC-20 implementation with renounced ownership at deployment.",
- "urls": [
- {
- "name": "YB Token Contract",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "renounce_ownership",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L90-L100",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "**1B max supply** with programmatic emission. Only GaugeController can mint. Emission rate determined by gauge staking levels: get_adjustment() returns sqrt(staked / totalSupply), so higher LP staking = higher emission rate (up to 100% of max rate).",
- "evidence": [
- {
- "name": "Emission Mechanism",
- "summary": "GaugeController calls YB.emit() with rate_factor based on LP staking levels. No discretionary minting possible.",
- "urls": [
- {
- "name": "get_adjustment (minting rate)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/LiquidityGauge.vy#L133-L142",
- "type": "github"
- },
- {
- "name": "YB.emit function",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy#L103-L122",
- "type": "github"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "User exits are **permissionless**: veYB withdrawal after lock expiry, fee claims. Gauge killing is DAO-controlled and affects emissions, not user funds.",
- "evidence": [
- {
- "name": "Exit Paths",
- "summary": "VotingEscrow.withdraw() permissionless after lock expiry. FeeDistributor.claim() has no admin check.",
- "urls": [
- {
- "name": "VotingEscrow.withdraw",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/VotingEscrow.vy#L428-L457",
- "type": "github"
- },
- {
- "name": "FeeDistributor.claim",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L269-L277",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "**No blacklist, freeze, or seizure functions** in YB token. The veYB transfer clearance checker can restrict veNFT transfers, but this does not censor the underlying YB token—users remain custodians and can withdraw after lock expiry.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB.vy full source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "veYB holders receive **protocol admin fees** (a subset of protocol revenue) via FeeDistributor. Fees originate from LT (Liquidity Token) vault admin fees, distributed weekly in yb-LP tokens. DAO controls fee direction via MigrationFactoryOwner, and gauge voting directs YB emissions. The Ecosystem Reserve is controlled by an EOA, not the DAO.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "FeeDistributor is **actively distributing** yb-cbBTC, yb-WBTC, yb-tBTC, and yb-WETH LP tokens to veYB holders.\n\n**Important distinction:** Protocol revenue = LP fees + position rebalancing expenses. What veYB holders receive is the **protocol admin fee** (admin_fee)—a subset of protocol revenue, not the total.\n\n**Fee flow:** LT vaults accrue admin fees → anyone calls withdraw_admin_fees() → mints LT to fee_receiver (FeeDistributor) → fill_epochs() distributes over 4 weeks → veYB holders claim pro-rata.\n\n**Data source:** [ValueVerse](https://yb.valueverse.ai)",
- "evidence": [
- {
- "name": "Fee Flow",
- "summary": "Admin fees from LT vaults flow to FeeDistributor via Factory.fee_receiver. Distribution is automatic and weekly over 4 epochs.",
- "urls": [
- {
- "name": "LT.withdraw_admin_fees",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/LT.vy#L866-L896",
- "type": "github"
- },
- {
- "name": "Factory.fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L98",
- "type": "github"
- },
- {
- "name": "FeeDistributor._fill_epochs (OVER_WEEKS=4)",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/FeeDistributor.vy#L86-L107",
- "type": "github"
- },
- {
- "name": "FeeDistributor Contract",
- "url": "https://etherscan.io/address/0xD11b416573EbC59b6B2387DA0D2c0D1b3b1F7A90",
- "type": "explorer"
- },
- {
- "name": "veYB Documentation",
- "url": "https://docs.yieldbasis.com/user/veyb",
- "type": "docs"
- },
- {
- "name": "Fee Data (ValueVerse)",
- "url": "https://yb.valueverse.ai",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "at_risk",
- "notes": "The **Ecosystem Reserve** is a VestingEscrow controlled by an EOA, not the DAO. This is the largest pool of discretionary YB outside the vesting contracts. The DAO holds a small amount of YB directly.",
- "evidence": [
- {
- "name": "Ecosystem Reserve",
- "summary": "Ecosystem Reserve is a VestingEscrow controlled by an EOA, not the DAO.",
- "urls": [
- {
- "name": "Ecosystem Reserve",
- "url": "https://etherscan.io/address/0x7aC5922776034132D9ff5c7889d612d98e052Cf2",
- "type": "explorer"
- },
- {
- "name": "Ecosystem Reserve Owner (EOA)",
- "url": "https://etherscan.io/address/0xC1671c9efc9A2ecC347238BeA054Fc6d1c6c28F9",
- "type": "explorer"
- },
- {
- "name": "DAO Contract",
- "url": "https://etherscan.io/address/0x42F2A41A0D0e65A440813190880c8a65124895Fa",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "veYB holders control both the **direction of automated value flows** and **emission routing**:\n\n**Fee direction:** DAO controls Factory.fee_receiver via MigrationFactoryOwner, determining where admin fees are routed.\n\n**Gauge voting = fee control by veYB:** veYB holders vote on gauge weights. Higher weight = more YB emissions to that pool's stakers, incentivizing LP staking which generates the admin fees distributed back to veYB holders. 10-day vote lock prevents manipulation.",
- "evidence": [
- {
- "name": "Fee Flow Direction",
- "summary": "DAO controls Factory.fee_receiver via MigrationFactoryOwner.set_fee_receiver(). This determines where admin fees are routed.",
- "urls": [
- {
- "name": "MigrationFactoryOwner.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/MigrationFactoryOwner.vy#L143-L145",
- "type": "github"
- },
- {
- "name": "Factory.set_fee_receiver",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/Factory.vy#L358-L364",
- "type": "github"
- }
- ]
- },
- {
- "name": "Gauge Voting",
- "summary": "veYB holders vote on gauge weights to direct YB emissions. This incentivizes LP staking, generating admin fees that flow back to veYB holders.",
- "urls": [
- {
- "name": "vote_for_gauge_weights",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/GaugeController.vy#L206-L287",
- "type": "github"
- },
- {
- "name": "GaugeController Contract",
- "url": "https://etherscan.io/address/0x1Be14811A3a06F6aF4fA64310a636e1Df04c1c21",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify whether YieldBasis AG (operating entity) provides any offchain value to YB token holders. No evidence of equity linkage, offchain revenue sharing, or legal commitments to tokenholders.",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "All core contracts are verified on Etherscan with matching GitHub source (Vyper 0.4.3). Protocol has undergone 6 independent security audits (Statemind, Chainsecurity, Quantstamp, Mixbytes, Electisec, Pashov).",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "YB token is **verified on Etherscan** (Vyper 0.4.3, AGPL v3.0 license). Source code available on GitHub with matching bytecode.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YB Token Verified on Etherscan",
- "url": "https://etherscan.io/address/0x01791F726B4103694969820be083196cC7c045fF#code",
- "type": "explorer"
- },
- {
- "name": "YB.vy Source",
- "url": "https://github.com/yield-basis/yb-core/blob/41137e5837e411c9d60be8705ca74304b082fa92/contracts/dao/YB.vy",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "All core contracts (Factory, veYB, GaugeController, FeeDistributor) are **verified on Etherscan**. **6 independent security audits** completed between March-August 2025.",
- "evidence": [
- {
- "name": "Verification and Audits",
- "summary": "Audited by Statemind (Feb-May 2025), Chainsecurity (Jul 2025), Quantstamp (Apr 2025), Mixbytes (Aug 2025), Electisec (Aug 2025), and Pashov (Mar-Apr 2025).",
- "urls": [
- {
- "name": "yb-core GitHub Repository",
- "url": "https://github.com/yield-basis/yb-core",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://docs.yieldbasis.com/user/audits-bug-bounties",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "~77M YB locked as veYB (~10% of minted supply). Team (25%) + Investors (12.1%) have 24-month vesting with a 6-month cliff ending March 2026, after which 25% unlocks and the remaining 75% vests linearly over 18 months.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "warning",
- "notes": "~77M veYB locked from ~722M minted YB (~10% participation). Post-cliff, **Team (250M) + Investors (121M) = 371M YB (37%)** could potentially influence governance if coordinated, given low current veYB participation.",
- "evidence": [
- {
- "name": "veYB Supply",
- "summary": "veYB supply ~77M tokens locked. Low participation rate means large token holders have outsized influence.",
- "urls": [
- {
- "name": "veYB Contract",
- "url": "https://etherscan.io/address/0x8235c179E9e84688FBd8B12295EfC26834dAC211",
- "type": "explorer"
- },
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "warning",
- "notes": "**24-month vesting** with **6-month cliff** ending ~March 15, 2026.\n\n**During cliff:** Cannot sell, but **can lock into veYB**. ~35M YB was locked by team and investors during the cliff, choosing protocol fees over liquidity.\n\n**At cliff end:** 25% unlocks (6/24 months).\n\n**Post-cliff:** Remaining 75% vests linearly over 18 months until September 2027.\n\n**Affected:** Team (250M) + Investors (121M) = 371M YB (37% of max supply). Tokens release gradually—they cannot be instantly used to influence governance.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "summary": "Start: Sept 15, 2025. Cliff: 6 months = March 15, 2026 (25% unlocks). Linear vesting: 18 months post-cliff (75% remaining). Full vest: Sept 15, 2027.",
- "urls": [
- {
- "name": "Tokenomics",
- "url": "https://docs.yieldbasis.com/user/tokenomics",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Aragon has not been able to verify trademark ownership. Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels. DAO contracts use AGPL v3.0 (open source), but Factory uses proprietary license.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify trademark ownership.",
- "evidence": []
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Aragon has not been able to identify published terms of service or a contracting entity for the primary distribution channels.",
- "evidence": [
- {
- "urls": [
- {
- "name": "YieldBasis Website",
- "url": "https://yieldbasis.com/",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "**Mixed licensing**: YB.vy, VotingEscrow.vy, GaugeController.vy use AGPL v3.0 (open source). **Factory.vy uses 'Copyright (c) 2025'** (proprietary).",
- "evidence": [
- {
- "name": "License Analysis",
- "summary": "DAO contracts (YB, veYB, GaugeController, FeeDistributor): AGPL v3.0. Factory, MigrationFactoryOwner: 'Copyright (c) 2025' (proprietary).",
- "urls": [
- {
- "name": "yb-core contracts directory",
- "url": "https://github.com/yield-basis/yb-core/tree/41137e5837e411c9d60be8705ca74304b082fa92/contracts",
- "type": "github"
- },
- {
- "name": "Curve Licensing Vesting",
- "url": "https://etherscan.io/address/0x36e36D5D588D480A15A40C7668Be52D36eb206A8",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "sky": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "SKY holders exercise binding governance through an approval-based voting workflow with a 24-hour timelock before any changes take effect. The token is non-upgradeable with no censorship capabilities. All privileged roles trace back to governance.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "positive",
- "notes": "SKY holders vote to elect \"spells\" (upgrade contracts). The winning spell must wait 24 hours before it can execute changes. This creates binding, verifiable onchain governance.",
- "evidence": [
- {
- "name": "Governance Workflow",
- "summary": "How votes become protocol changes:\n\n1. Lock SKY tokens in voting contract\n2. Vote for a \"spell\" (upgrade contract)\n3. Winning spell schedules execution via plot()\n4. 24-hour delay enforced (eta >= now + 86400s)\n5. After delay, anyone can trigger exec()\n\nThe plot() function enforces the delay — no spell can execute without waiting.",
- "urls": [
- {
- "name": "Voting Contract",
- "url": "https://etherscan.io/address/0x929d9A1435662357F54AdcF64DcEE4d6b867a6f9#code",
- "type": "explorer"
- },
- {
- "name": "plot() delay enforcement (L111-116)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L111-L116",
- "type": "github"
- }
- ]
- },
- {
- "name": "Timelock Contract",
- "summary": "All governance actions execute through a timelock (Pause Proxy). The 24-hour delay gives users time to exit before changes take effect.",
- "urls": [
- {
- "name": "Pause Proxy (Etherscan)",
- "url": "https://etherscan.io/address/0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB#code",
- "type": "explorer"
- },
- {
- "name": "exec() function (L124-136)",
- "url": "https://github.com/sky-ecosystem/ds-pause/blob/master/src/pause.sol#L124-L136",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "positive",
- "notes": "All privileged roles trace back to SKY governance. A single \"Pause Proxy\" contract holds admin rights on all core contracts. Only governance-approved spells can act through it.",
- "evidence": [
- {
- "name": "Core Contracts Controlled by Governance",
- "summary": "The Pause Proxy holds admin rights on all key contracts. Verify by calling wards(0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB) on each contract — returns 1 if authorized.",
- "urls": [
- {
- "name": "Vat wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B#readContract",
- "type": "explorer"
- },
- {
- "name": "Vow wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- },
- {
- "name": "SKY wards() — verify Pause Proxy",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Emergency Controls",
- "summary": "\"Mom\" contracts can adjust parameters without the 24hr delay for emergencies. These are governance-controlled via the authority pattern.",
- "urls": [
- {
- "name": "Mom authority pattern (source)",
- "url": "https://github.com/sky-ecosystem/osm-mom/blob/master/src/OsmMom.sol#L55",
- "type": "github"
- },
- {
- "name": "OSM_MOM — verify authority()",
- "url": "https://etherscan.io/address/0x76416A4d5190d071bfed309861527431304aA14f#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "positive",
- "notes": "Core accounting contracts are immutable — their code cannot change. Newer stablecoin contracts (USDS, sUSDS) can be upgraded, but only through governance.",
- "evidence": [
- {
- "name": "Immutable Core",
- "summary": "Core accounting contracts have no upgrade mechanism. The deployed code is permanent.",
- "urls": [
- {
- "name": "Vat source code",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vat.sol",
- "type": "github"
- },
- {
- "name": "SKY token source code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- }
- ]
- },
- {
- "name": "Upgradeable Stablecoins",
- "summary": "USDS and sUSDS use proxy contracts. Upgrades require governance approval through the standard voting process.",
- "urls": [
- {
- "name": "USDS upgrade authorization",
- "url": "https://github.com/sky-ecosystem/usds/blob/master/src/Usds.sol#L73",
- "type": "github"
- },
- {
- "name": "sUSDS source code",
- "url": "https://github.com/sky-ecosystem/stusds/blob/master/src/StUsds.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The SKY token cannot be upgraded. Its code is permanent with no admin backdoors.",
- "evidence": [
- {
- "name": "Non-Upgradeable Token",
- "summary": "Standard ERC-20 contract with no proxy pattern. The deployed code cannot be changed.",
- "urls": [
- {
- "name": "SKY Token Contract",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "Only governance can mint new SKY. The primary source is conversion from legacy MKR tokens at a fixed 24,000:1 ratio. Anyone can burn their own tokens.",
- "evidence": [
- {
- "name": "Minting Restricted to Governance",
- "summary": "The mint() function requires authorization. Only governance-controlled contracts can call it.",
- "urls": [
- {
- "name": "mint() function (L146-154)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L146-L154",
- "type": "github"
- }
- ]
- },
- {
- "name": "MKR Conversion",
- "summary": "Legacy MKR tokens convert to SKY at a fixed 24,000:1 ratio. The rate is immutable in the contract.",
- "urls": [
- {
- "name": "rate() returns 24000",
- "url": "https://etherscan.io/address/0xA1Ea1bA18E88C381C724a75F23a130420C403f9a#readContract",
- "type": "explorer"
- },
- {
- "name": "Immutable rate declaration",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/MkrSky.sol#L36",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "positive",
- "notes": "No admin can arbitrarily pause the protocol or restrict user access. Emergency shutdown exists but requires burning a significant amount of tokens.",
- "evidence": [
- {
- "name": "Emergency Shutdown",
- "summary": "The only way to \"pause\" the protocol is Emergency Shutdown, which requires burning tokens past a threshold. This is a nuclear option, not an admin switch.",
- "urls": [
- {
- "name": "ESM source code",
- "url": "https://github.com/sky-ecosystem/esm/blob/master/src/ESM.sol",
- "type": "github"
- },
- {
- "name": "ESM contract on Etherscan",
- "url": "https://etherscan.io/address/0x09e05fF6142F2f9de8B6B65855A1d56B6cfE4c58#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "No Arbitrary Pause",
- "summary": "Core contracts have no pause function. Users can always interact with the protocol.",
- "urls": []
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "SKY has no blacklist, freeze, or admin-controlled transfer blocking. Tokens cannot be seized or frozen by anyone.",
- "evidence": [
- {
- "name": "No Censorship Functions",
- "summary": "The contract has no blacklist, freeze, or pause functions. Transfer functions are standard ERC-20 with no admin intervention points.",
- "urls": [
- {
- "name": "Transfer Functions (L96-135)",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol#L96-L135",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "Protocol revenue flows to SKY holders through automated buybacks. When the protocol earns fees, it uses them to buy SKY on the open market. All fee parameters are governance-controlled.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "A portion of protocol revenue (interest on loans, liquidation penalties) automatically flows to buybacks. The \"Smart Burn Engine\" purchases SKY using accumulated fees.",
- "evidence": [
- {
- "name": "Smart Burn Engine",
- "summary": "Automated buyback system. When protocol surplus exceeds the buffer threshold, the Splitter routes fees to the Flapper, which purchases SKY on UniswapV2.",
- "urls": [
- {
- "name": "Splitter contract",
- "url": "https://etherscan.io/address/0xBF7111F13386d23cb2Fba5A538107A73f6872bCF#code",
- "type": "explorer"
- },
- {
- "name": "Flapper (buyback executor)",
- "url": "https://etherscan.io/address/0x374D9c3d5134052Bc558F432Afa1df6575f07407#code",
- "type": "explorer"
- },
- {
- "name": "Flapper source code",
- "url": "https://github.com/sky-ecosystem/dss-flappers/blob/master/src/FlapperUniV2.sol",
- "type": "github"
- },
- {
- "name": "Smart Burn Engine Dashboard",
- "url": "https://info.sky.money/smart-burn-engine",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Revenue Flow",
- "summary": "Protocol revenue flows: Stability Fees → Vow (surplus) → Splitter → Flapper → SKY buybacks.\n\nRevenue sources:\n- Interest on loans (stability fees)\n- Liquidation penalties\n- Stablecoin swap fees (PSM)",
- "urls": [
- {
- "name": "Stability fee accrual",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L122-L128",
- "type": "github"
- },
- {
- "name": "Surplus routing to flapper",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L148-L152",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "positive",
- "notes": "All treasury assets are held onchain and controlled by governance. There is no offchain treasury or multi-sig.",
- "evidence": [
- {
- "name": "Onchain Treasury",
- "summary": "Protocol surplus is held in the Vow contract. Only governance can access these funds.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "positive",
- "notes": "Governance controls all fee rates and revenue parameters. SKY holders decide how much the protocol charges and how revenue is distributed.",
- "evidence": [
- {
- "name": "Fee Rate Control",
- "summary": "Governance sets stability fee rates via the Jug contract. Each collateral type has its own rate, updated through governance spells.",
- "urls": [
- {
- "name": "Jug fee configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/jug.sol#L107-L111",
- "type": "github"
- },
- {
- "name": "Jug contract",
- "url": "https://etherscan.io/address/0x19c0976f590D67707E62397C87829d896Dc0f1F1#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Surplus Buffer Control",
- "summary": "The surplus buffer (\"hump\") determines when buybacks trigger. Governance can adjust this threshold to control the pace of buybacks.",
- "urls": [
- {
- "name": "Vow hump configuration",
- "url": "https://github.com/sky-ecosystem/dss/blob/master/src/vow.sol#L96-L103",
- "type": "github"
- },
- {
- "name": "Vow contract — read hump",
- "url": "https://etherscan.io/address/0xA950524441892A31ebddF91d3cEEFa04Bf454466#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "No verified offchain revenue streams flow to SKY holders. The DAI Foundation is an independent non-profit that does not distribute profits.",
- "evidence": [
- {
- "name": "Foundation Independence",
- "summary": "The DAI Foundation operates independently under Danish law. It holds trademarks but does not distribute value to tokenholders.",
- "urls": [
- {
- "name": "Foundation Mandate",
- "url": "https://daifoundation.org/mandate",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "All code is open source (AGPL-3.0) and verified on Etherscan. Anyone can audit the contracts.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "SKY token source code is open source and verified on Etherscan. Anyone can audit the code.",
- "evidence": [
- {
- "name": "Verified Source",
- "summary": "Source code matches deployed bytecode. Licensed under AGPL-3.0.",
- "urls": [
- {
- "name": "Source Code",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/src/Sky.sol",
- "type": "github"
- },
- {
- "name": "Verified on Etherscan",
- "url": "https://etherscan.io/address/0x56072C95FAA701256059aa122697B133aDEd9279#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "Every protocol contract is open source. A \"chainlog\" provides a registry of all deployed contract addresses.",
- "evidence": [
- {
- "name": "Open Source Repositories",
- "summary": "All protocol code is open source under AGPL-3.0. Core contracts, governance, and stablecoins all have public repositories.",
- "urls": [
- {
- "name": "Core Protocol",
- "url": "https://github.com/sky-ecosystem/dss",
- "type": "github"
- },
- {
- "name": "Contract Registry",
- "url": "https://github.com/sky-ecosystem/spells-mainnet/blob/master/src/test/addresses_mainnet.sol",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Aragon has not been able to verify the concentration of holdings.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "unevaluated",
- "notes": "Aragon has not been able to verify the concentration of holdings.",
- "evidence": []
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "unevaluated",
- "notes": "Vesting contracts exist but specific unlock schedules were not enumerated in this analysis.",
- "evidence": [
- {
- "name": "Vesting Contracts",
- "summary": "Vesting contracts exist for token distributions. Governance controls these schedules.",
- "urls": [
- {
- "name": "Vest Contract",
- "url": "https://etherscan.io/address/0x67eaDb3288cceDe034cE95b0511DCc65cf630bB6#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Current Sky branding is not controlled by SKY tokenholders. Skybase International's terms reserve trademarks, service marks, logos, and trade names associated with the Services, including the Sky name, to the service operator or its licensors, and the DAI Foundation independently holds the legacy Maker and DAI trademarks. All code is open source (AGPL-3.0).",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Official Skybase International terms state that trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name. Aragon has not found evidence that current Sky / USDS branding is owned by a tokenholder-controlled legal entity. Separately, the DAI Foundation holds the legacy Maker and DAI trademarks outside token governance.",
- "evidence": [
- {
- "name": "Skybase International Terms of Use",
- "summary": "Skybase International's terms say trademarks, service marks, logos, and trade names associated with the Services are proprietary to Skybase International or its licensors, and explicitly include the Sky name.",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://docs.sky.money/legal/skybase-international/terms-of-use",
- "type": "docs"
- }
- ]
- },
- {
- "name": "DAI Foundation",
- "summary": "Holds the legacy Maker and DAI trademarks. Operates under Danish law, independent of token governance.",
- "urls": [
- {
- "name": "Foundation Website",
- "url": "https://daifoundation.org",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Domain ownership not verified. Open source frontends exist that anyone can deploy.",
- "evidence": [
- {
- "name": "Open Source Frontends",
- "summary": "Multiple open source frontends exist. Anyone can deploy their own interface.",
- "urls": [
- {
- "name": "Governance Portal Source",
- "url": "https://github.com/sky-ecosystem/governance-portal-v2",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "positive",
- "notes": "All code is AGPL-3.0 licensed. Anyone can fork and deploy the protocol. The license requires source disclosure.",
- "evidence": [
- {
- "name": "AGPL-3.0 License",
- "summary": "Copyleft license. Anyone can fork and deploy, but must share source code of modifications.",
- "urls": [
- {
- "name": "License File",
- "url": "https://github.com/sky-ecosystem/sky/blob/master/LICENSE",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "ethfi": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "ETHFI tokenholders do not have binding onchain control. Governance uses offchain voting with multisig execution.\n\nThe protocol uses a two-timelock system for upgrades and operations. A multisig controls the Upgrade Timelock, which owns the RoleRegistry and authorizes protocol upgrades.\n\nThe mainnet token is not upgradeable. L2 tokens on Arbitrum and Base are upgradeable by multisigs with no timelock.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "at_risk",
- "notes": "No onchain Governor contract deployed. Governance uses offchain voting with a 4-day voting period and 1M ETHFI quorum. Execution is handled by multisig, meaning tokenholders can signal preference but cannot force execution.\n\nThe protocol has published a multi-stage decentralisation roadmap and is currently in Phase 0, which focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "evidence": [
- {
- "name": "Governance Structure",
- "summary": "Phase 0 focuses on launching the token and establishing the initial voter base. Phase 1 targets full Governor deployment with treasury access.",
- "urls": [
- {
- "name": "Governance Info",
- "url": "https://vote.ether.fi/info",
- "type": "docs"
- },
- {
- "name": "Governance Resources",
- "url": "https://governance.ether.fi/t/ether-fi-governance-official-resources/2140",
- "type": "docs"
- },
- {
- "name": "Governance Roadmap",
- "url": "https://etherfi.gitbook.io/gov/governance-roadmap",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "warning",
- "notes": "The protocol uses a two-timelock system. The Upgrade Timelock owns the RoleRegistry and controls protocol upgrades. The Operating Timelock handles day-to-day operations.\n\nTokenholders do not elect or control the multisig signers. Team-controlled multisigs propose all timelock operations.",
- "evidence": [
- {
- "name": "RoleRegistry Owner (Upgrade Timelock)",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock (72h delay). Role changes require timelock approval.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock (72h)",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Two-Timelock System",
- "summary": "Upgrade Timelock (72h delay, 4-of-7 proposer) for upgrades. Operating Timelock (8h delay, 3-of-5 proposer) for routine operations.",
- "urls": [
- {
- "name": "Upgrade Admin (4-of-7)",
- "url": "https://etherscan.io/address/0xcdd57d11476c22d265722f68390b036f3da48c21",
- "type": "explorer"
- },
- {
- "name": "Operating Timelock (8h)",
- "url": "https://etherscan.io/address/0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a",
- "type": "explorer"
- },
- {
- "name": "Operating Admin (3-of-5)",
- "url": "https://etherscan.io/address/0x2aCA71020De61bb532008049e1Bd41E451AE8AdC",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "warning",
- "notes": "Core protocol contracts (LiquidityPool, eETH, weETH, EtherFiAdmin) are owned by the Upgrade Timelock, which enforces a delay before upgrades execute.\n\nBoring Vaults (sETHFI, eUSD, weETHs, weETHk) use a different pattern: they are non-upgradeable but controlled via RolesAuthority contracts owned by multisigs. L2 ETHFI tokens can be upgraded instantly by multisigs with no timelock.",
- "evidence": [
- {
- "name": "Upgrade Path",
- "summary": "Core contracts are owned by the Upgrade Timelock (72h delay). Boring Vaults are non-upgradeable but controlled via RolesAuthority.",
- "urls": [
- {
- "name": "RoleRegistry Upgrade Check",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/RoleRegistry.sol#L76-L78",
- "type": "github"
- },
- {
- "name": "LiquidityPool Upgrade Authorization",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529-L531",
- "type": "github"
- }
- ]
- },
- {
- "name": "RoleRegistry Owner",
- "summary": "The RoleRegistry is owned by the Upgrade Timelock. Core contract upgrades require a 72-hour delay.",
- "urls": [
- {
- "name": "RoleRegistry Contract",
- "url": "https://etherscan.io/address/0x62247D29B4B9BECf4BB73E0c722cf6445cfC7cE9",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "warning",
- "notes": "The Ethereum mainnet ETHFI token is not upgradeable. L2 ETHFI tokens on Arbitrum and Base are upgradeable by multisigs with no timelock protection.\n\nL2 token holders face higher risk due to the ability to instantly upgrade the token contract.",
- "evidence": [
- {
- "name": "Mainnet Token (Not Upgradeable)",
- "summary": "The Ethereum mainnet ETHFI token is not upgradeable. No EIP-1967 implementation slot exists.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "L2 Tokens (Upgradeable, No Timelock)",
- "summary": "L2 ETHFI tokens are upgradeable proxies owned by 3-of-6 multisigs. No timelock protects L2 upgrades.",
- "urls": [
- {
- "name": "Arbitrum ETHFI",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Arbitrum Admin (3-of-6)",
- "url": "https://arbiscan.io/address/0x0c6ca434756eedf928a55ebeaf0019364b279732",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- },
- {
- "name": "Base Admin (3-of-6)",
- "url": "https://basescan.org/address/0x7a00657a45420044bc526b90ad667affaee0a868",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "positive",
- "notes": "ETHFI has a fixed supply of 1 billion tokens with no mint function. All tokens were minted at deployment. Supply can only decrease through the ERC20Burnable function. Approximately 1.46M tokens have been burned.",
- "evidence": [
- {
- "name": "Fixed Supply",
- "summary": "No mint function exists in the contract. Holders can burn their own tokens via ERC20Burnable.",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "warning",
- "notes": "Protocol contracts can be paused by addresses holding the PROTOCOL_PAUSER role, which is assigned via the RoleRegistry (owned by Upgrade Timelock). The ETHFI token itself has no pause function.\n\neETH holders could be temporarily blocked from withdrawing to ETH if LiquidityPool is paused.",
- "evidence": [
- {
- "name": "Pause Authority",
- "summary": "The EtherFiAdmin contract can pause protocol operations including the oracle, staking manager, auction manager, nodes manager, liquidity pool, and membership manager.",
- "urls": [
- {
- "name": "EtherFiAdmin Pause Function",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/EtherFiAdmin.sol#L102-L127",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "warning",
- "notes": "The mainnet ETHFI token contains no blacklist, freeze, or transfer restriction mechanisms. L2 ETHFI tokens are upgradeable by multisigs with no timelock, which could allow introducing censorship functions through an upgrade.\n\nL1 token has no censorship risk. L2 tokens have potential censorship risk due to instant upgrade capability.",
- "evidence": [
- {
- "name": "Token Analysis",
- "summary": "L1 token has no censorship capabilities. L2 tokens are upgradeable, creating a potential censorship vector on Arbitrum and Base.",
- "urls": [
- {
- "name": "ETHFI Token Contract",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- },
- {
- "name": "Arbitrum ETHFI (Upgradeable)",
- "url": "https://arbiscan.io/address/0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27",
- "type": "explorer"
- },
- {
- "name": "Base ETHFI (Upgradeable)",
- "url": "https://basescan.org/address/0x6C240DDA6b5c336DF09A4D011139beAAa1eA2Aa2",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "An active buyback program distributes purchased ETHFI to sETHFI holders. eETH withdrawal fees fund buybacks, while any additional funding from broader protocol revenue is currently Foundation-discretionary. The Treasury is a multisig controlled by the team.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "positive",
- "notes": "An ETHFI buyback program is operational, distributing purchased tokens to sETHFI holders. Buybacks are funded by eETH withdrawal fees weekly, and any additional contribution from broader protocol revenue is currently Foundation-discretionary.\n\nBuyback execution is controlled by a multisig where any single signer can execute. Distribution is announced via Foundation communications, not enforced by smart contract.",
- "evidence": [
- {
- "name": "Buyback Program",
- "summary": "Buybacks documented in governance materials. The buyback wallet is a 1-of-5 multisig (any single signer can execute).",
- "urls": [
- {
- "name": "ETHFI Buyback Program",
- "url": "https://etherfi.gitbook.io/gov/ethfi-buyback-program",
- "type": "docs"
- },
- {
- "name": "Buyback History (Dune)",
- "url": "https://dune.com/ether_fi/ethfi-buybacks-and-protocol-revenue-sources",
- "type": "docs"
- },
- {
- "name": "sETHFI Staking",
- "url": "https://www.ether.fi/app/ethfi",
- "type": "docs"
- },
- {
- "name": "Buyback Wallet (1-of-5)",
- "url": "https://etherscan.io/address/0x2f5301a3D59388c509C65f8698f521377D41Fd0F",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "warning",
- "notes": "The primary Treasury is a multisig controlled by the team. The ETHFI Allocations documentation mentions multiple Safes under 'Treasury' — this analysis verified the main Treasury contract. Tokenholders have no direct control over treasury assets.",
- "evidence": [
- {
- "name": "Treasury Control",
- "summary": "The verified Treasury is a 3-of-8 Gnosis Safe. Additional Treasury addresses may exist per ETHFI Allocations documentation.",
- "urls": [
- {
- "name": "Treasury Contract",
- "url": "https://etherscan.io/address/0x0c83EAe1FE72c390A02E426572854931EefF93BA",
- "type": "explorer"
- },
- {
- "name": "Upgrade Timelock",
- "url": "https://etherscan.io/address/0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "warning",
- "notes": "The percentage of protocol revenue allocated to buybacks is stated in documentation only — it is not hardcoded in any contract or set by an on-chain parameter. The Foundation has full discretion over actual buyback amounts and timing.\n\nFee recipients are set by admin roles via the RoleRegistry. Tokenholders cannot modify the fee structure through binding governance.",
- "evidence": [
- {
- "name": "Fee Configuration",
- "summary": "Buyback percentages are stated in docs only, not enforced on-chain. Fee parameters are controlled by admin roles.",
- "urls": [
- {
- "name": "LiquidityPool Fee Functions",
- "url": "https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L434-L439",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "unevaluated",
- "notes": "Aragon developers have not verified additional offchain value accrual mechanisms. No legally binding revenue sharing arrangements or licensing revenue documented.",
- "evidence": []
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "The ETHFI token contract is verified on Etherscan but not published to a public GitHub repository. All core protocol contracts are verified and open source under MIT license with multiple security audits and formal verification through Certora.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "warning",
- "notes": "The ETHFI token contract is verified on Etherscan but is not published to a public GitHub repository. Protocol contracts are public, but the token contract is Etherscan-only.",
- "evidence": [
- {
- "name": "Token Verification",
- "summary": "Token source verified on Etherscan. Compiler: Solidity 0.8.20, License: MIT.",
- "urls": [
- {
- "name": "Etherscan Verified Source",
- "url": "https://etherscan.io/address/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "All core protocol contracts are verified on Etherscan and match the public GitHub repository. The code is MIT licensed with formal verification via Certora and multiple audits available.",
- "evidence": [
- {
- "name": "Protocol Source & Audits",
- "urls": [
- {
- "name": "etherfi-protocol/smart-contracts",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Audit Reports",
- "url": "https://github.com/etherfi-protocol/smart-contracts/tree/master/audits",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "Over 55% of tokens are allocated to Investors (33.74%) and Core Contributors (21.47%), subject to transparent vesting schedules published in official documentation. Vesting completion is expected by end of 2030.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "warning",
- "notes": "Token allocation includes Investors at 33.74% (2-year vest, 1-year cliff), Treasury at 21.62%, Core Contributors at 21.47% (3-year vest, 1-year cliff), User Airdrops at 19.27%, and Partnerships at 3.9%. Vesting mitigates immediate concentration, and schedules are transparently documented.",
- "evidence": [
- {
- "name": "Token Allocation",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "warning",
- "notes": "Continuous unlocks from team and investor allocations occur according to published vesting schedules. Core Contributors have 3-year vesting with a 1-year cliff, while Investors have 2-year vesting with a 1-year cliff. Full vesting completion is expected by end of 2030.",
- "evidence": [
- {
- "name": "Vesting Schedule",
- "urls": [
- {
- "name": "ETHFI Allocations",
- "url": "https://etherfi.gitbook.io/gov/ethfi-allocations",
- "type": "docs"
- },
- {
- "name": "DefiLlama Unlocks",
- "url": "https://defillama.com/unlocks/ether.fi",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The ether.fi domain and platform are operated by this company. Protocol smart contracts are MIT licensed, but non-contract IP has restricted licensing.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Trademarks are owned by Ether.Fi SEZC (Cayman Islands company), not a tokenholder-controlled entity. The Terms of Use state that company names, logos, and related designs are trademarks of the Company or its affiliates.",
- "evidence": [
- {
- "name": "Trademark Ownership",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "The ether.fi domain and platform are operated by Ether.Fi SEZC, a Cayman Islands Special Economic Zone Company. There is no documented relationship between the company and DAO, and the company operates with unilateral control over terms and services.",
- "evidence": [
- {
- "name": "Legal Entity",
- "urls": [
- {
- "name": "Terms of Use",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Smart contracts are MIT licensed, allowing unrestricted use and modification. However, non-contract IP including website content, documentation, and brand assets is restricted. Users receive only a non-transferable, non-sublicensable, non-exclusive, revocable license for personal use.",
- "evidence": [
- {
- "name": "License",
- "urls": [
- {
- "name": "GitHub Repository",
- "url": "https://github.com/etherfi-protocol/smart-contracts",
- "type": "github"
- },
- {
- "name": "Terms of Use (Non-Contract IP)",
- "url": "https://etherfi.gitbook.io/etherfi/ether.fi-legal/terms-of-use",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "ondo": [
- {
- "id": "onchain-ctrl",
- "name": "Onchain Control",
- "tags": [
- "Metric 1"
- ],
- "about": "This metric evaluates whether economically material outcomes are mediated through tokenholder governance, or whether admins, multisigs, security councils, or other privileged roles retain onchain powers that can change the rules or selectively restrict use and exit. Concretely, it maps who can upgrade core logic, change parameters, invoke emergency actions, modify token behavior or supply, freeze/blacklist/seize/force-transfer assets, or limit protocol actions and exit paths.",
- "summary": "Core Ondo products are controlled by team multisigs. ONDO governance controls Flux Finance, but Flux appears small relative to Ondo's other product TVL. The ONDO token contract has team-held admin and minting roles. Supply is 10B with active mint capability.",
- "criteria": [
- {
- "id": "onchain-ctrl__governance-workflow",
- "name": "Onchain Governance Workflow",
- "about": "Evaluates whether an onchain process exists that grants tokenholders ultimate authority over protocol decisions.",
- "status": "at_risk",
- "notes": "ONDO tokenholders have no governance control over Ondo's core products (OUSG, USDY, Global Markets). These products represent ~$3.5B TVL (98.8% of total) and are controlled by company multisigs.",
- "evidence": [
- {
- "name": "OUSG/USDY/Global Markets Governance (Company-Controlled)",
- "summary": "All core products are controlled by company multisigs with no tokenholder involvement:\n\n1. OUSG: Management Multisig holds DEFAULT_ADMIN_ROLE and ProxyAdmin ownership.\n\n2. USDY: Team Multisig holds ProxyAdmin ownership.\n\n3. Global Markets: TimelockController with 2-hour delay, controlled by company multisigs.\n\nNo forum discussion required. No onchain tokenholder vote. Changes proposed and executed by multisig signers.",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (OUSG admin)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin owner",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__role-accountability",
- "name": "Role Accountability",
- "about": "Determines whether all privileged or value-impacting roles are governed, revocable, and accountable to tokenholders.",
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are entirely controlled by company multisigs. The ONDO token itself has DEFAULT_ADMIN_ROLE and MINTER_ROLE held by team multisigs, not the DAO.",
- "evidence": [
- {
- "name": "Team-Controlled Roles (ONDO Token)",
- "summary": "DEFAULT_ADMIN_ROLE: Team Multisig (4-of-7).\n\nMINTER_ROLE: Team Multisig (4-of-7).\n\nThe team can grant/revoke roles and mint new ONDO tokens without DAO approval.",
- "urls": [
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (OUSG/USDY)",
- "summary": "OUSG DEFAULT_ADMIN_ROLE: Management Multisig (4-of-7).\n\nOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nrOUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nUSDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nrUSDY ProxyAdmin owner: Team Multisig (4-of-7).",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92",
- "type": "explorer"
- },
- {
- "name": "Management Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "rOUSG",
- "url": "https://etherscan.io/address/0x54043c656F0FAd0652D9Ae2603cDF347c5578d00",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (4-of-7)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "rUSDY",
- "url": "https://etherscan.io/address/0xaf37c1167910ebC994e266949387d2c7C326b879",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Team-Controlled Roles (Global Markets)",
- "summary": "GMTokenManager/USDon DEFAULT_ADMIN_ROLE: TimelockController (2-hour delay).\n\nTimelockController PROPOSER_ROLE: Multisig (4-of-7).\n\nTimelockController EXECUTOR_ROLE: Multisig (1-of-8) + EOA.\n\nTimelockController DEFAULT_ADMIN_ROLE: Multisig (5-of-9).",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#readContract",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- },
- {
- "name": "PROPOSER_ROLE holder (Multisig 4-of-7)",
- "url": "https://etherscan.io/address/0x71A4d411b5f7941Dee020417fca30413712f1646",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (Multisig 1-of-8)",
- "url": "https://etherscan.io/address/0x2e55b738F5969Eea10fB67e326BEE5e2fA15A2CC",
- "type": "explorer"
- },
- {
- "name": "EXECUTOR_ROLE holder (EOA)",
- "url": "https://etherscan.io/address/0xfF1621Ee754512B34a6Bd62A941Cc4d5E4d0b85B",
- "type": "explorer"
- },
- {
- "name": "DEFAULT_ADMIN_ROLE holder (Multisig 5-of-9)",
- "url": "https://etherscan.io/address/0xcD35671dCAb88d05EE29dC4D360181529390B17f",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__protocol-upgrade",
- "name": "Protocol Upgrade Authority",
- "about": "Determines whether core protocol logic can be upgraded and whether such upgrades are controlled by tokenholders.",
- "status": "at_risk",
- "notes": "OUSG, USDY, and Global Markets are upgradeable contracts controlled by team multisigs on all chains. ONDO tokenholders have no upgrade control over any core products.",
- "evidence": [
- {
- "name": "OUSG/USDY (Team-Controlled)",
- "summary": "Ethereum OUSG ProxyAdmin owner: Management Multisig (4-of-7).\n\nEthereum USDY ProxyAdmin owner: Team Multisig (4-of-7).\n\nPolygon OUSG ProxyAdmin owner: 3-of-6 Multisig.\n\nMantle USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nArbitrum USDY ProxyAdmin owner: 4-of-7 Multisig.\n\nThe DAO has no upgrade authority over OUSG or USDY on any chain.",
- "urls": [
- {
- "name": "OUSG Proxy",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "OUSG ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0xAEd4caF2E535D964165B4392342F71bac77e8367",
- "type": "explorer"
- },
- {
- "name": "USDY Proxy",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#readProxyContract",
- "type": "explorer"
- },
- {
- "name": "USDY ProxyAdmin Owner (Ethereum)",
- "url": "https://etherscan.io/address/0x1a694A09494E214a3Be3652e4B343B7B81A73ad7",
- "type": "explorer"
- },
- {
- "name": "Polygon OUSG ProxyAdmin Owner",
- "url": "https://polygonscan.com/address/0x4413073440A568790c1b2b06B47F7D0a443574d0",
- "type": "explorer"
- },
- {
- "name": "Mantle USDY ProxyAdmin Owner",
- "url": "https://mantlescan.xyz/address/0xC8A7870fFe41054612F7f3433E173D8b5bFcA8E3",
- "type": "explorer"
- },
- {
- "name": "Arbitrum USDY ProxyAdmin Owner",
- "url": "https://arbiscan.io/address/0xC4ac5c2fA461901b4D91832d03A7018092eDCb4D",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Global Markets (Team-Controlled via TimelockController)",
- "summary": "USDon is an upgradeable proxy. Upgrade authority resides with TimelockController (2-hour delay) which is controlled by company multisigs. ONDO tokenholders have no upgrade control.",
- "urls": [
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__token-upgrade",
- "name": "Token Upgrade Authority",
- "about": "Assesses whether token behavior can be modified and, if so, whether such changes are controlled by tokenholder governance.",
- "status": "positive",
- "notes": "The ONDO token is not upgradeable (no proxy pattern). It uses AccessControl with DEFAULT_ADMIN_ROLE and MINTER_ROLE held by a team multisig, not the DAO.",
- "evidence": [
- {
- "name": "ONDO Token Roles",
- "summary": "DEFAULT_ADMIN_ROLE holder: Team Multisig.\nMINTER_ROLE holder: Team Multisig.\n\nThe team can grant/revoke roles and mint new tokens. The DAO has no control over these roles.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Team Multisig",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "Contract Source Note",
- "summary": "The deployed ONDO token uses AccessControl. The public ondo-v1 repository shows a simpler Ownable-based contract, indicating the deployed contract differs from the public repo.",
- "urls": [
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__supply",
- "name": "Supply Control",
- "about": "Evaluates whether token supply changes are programmatic or subject exclusively to tokenholder-approved governance processes.",
- "status": "at_risk",
- "notes": "ONDO has a total supply of 10B tokens. MINTER_ROLE exists and is held by a team multisig. The supply is not immutably fixed.",
- "evidence": [
- {
- "name": "Current Supply",
- "summary": "Total supply: 10,000,000,000 ONDO (verified onchain).\nTeam Multisig balance: ~5.9B ONDO (~59% of supply).\n\nDocumentation states \"no scheduled or planned inflation\" but this is a policy statement, not code enforcement.",
- "urls": [
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Mint Function Exists",
- "summary": "The deployed ONDO token includes a `mint()` function restricted to MINTER_ROLE holders. Team multisig holds MINTER_ROLE and can mint new tokens without DAO approval.",
- "urls": [
- {
- "name": "ONDO Token (verified source)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Team Multisig (MINTER_ROLE holder)",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__access-gating",
- "name": "Privileged Access Gating",
- "about": "Assesses whether any bounded actor set can block or selectively restrict economically meaningful protocol actions or exit paths, versus access that is permissionless and symmetric for similarly situated users.",
- "status": "at_risk",
- "notes": "OUSG and USDY have extensive transfer restrictions (KYC requirements, blocklists, sanctions checks) enforced by Ondo Finance, not the DAO. The company controls who can hold these products.",
- "evidence": [
- {
- "name": "OUSG Transfer Restrictions",
- "summary": "KYC required via KYCRegistry. The `_beforeTokenTransfer` hook enforces three-way checks: sender, receiver, and msg.sender must all be KYC-approved. The DAO does not control the KYC registry.",
- "urls": [
- {
- "name": "OUSG Contract (KYC enforcement)",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "OUSG KYC check (source)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousg.sol#L62-L89",
- "type": "github"
- },
- {
- "name": "KYCRegistry",
- "url": "https://etherscan.io/address/0x56A5D911052323D688C731d516530878557463e7",
- "type": "explorer"
- }
- ]
- },
- {
- "name": "USDY Transfer Restrictions",
- "summary": "USDY has blocklist, allowlist, and sanctions list checks. Transfers require passing all three checks. These are controlled by the company, not the DAO.",
- "urls": [
- {
- "name": "USDY restrictions (source)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L84-L115",
- "type": "github"
- },
- {
- "name": "USDY Contract",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "onchain-ctrl__censorship",
- "name": "Token Censorship",
- "about": "Examines whether any roles exist that can freeze, blacklist, seize, or otherwise censor token balances or transfers.",
- "status": "positive",
- "notes": "The ONDO token has no blocklist, freeze, or seizure functions. Transfers are permissionless. Transfers were enabled in January 2024.",
- "evidence": [
- {
- "name": "No Censorship Capability",
- "summary": "`transferAllowed = true` (verified onchain, enabled January 2024).\nNo blacklist mapping.\nNo pause function for transfers.\nNo force transfer or seize functions.\n\nThe token contract has a `whenTransferAllowed` modifier but transfers are permanently enabled.",
- "urls": [
- {
- "name": "ONDO Token",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- },
- {
- "name": "Source code (ondo-v1)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual",
- "name": "Value Accrual",
- "tags": [
- "Metric 2"
- ],
- "about": "This metric evaluates whether the system's operation produces observable, onchain value flows (or token-scarcity effects) that accrue value to tokenholders under rule-based constraints that do not rely on manual transfers, trusted executors, or other unenforced expectations. It focuses on whether a real value engine exists and is active.",
- "summary": "No active value accrual mechanism was identified for ONDO holders. Ondo has multiple products with documented product-level economics, including yield, fees, expenses, and spreads, but no identified flow from those economics to ONDO holders or an ONDO-controlled treasury. Flux is ONDO-governed but small relative to Ondo's other product TVL, so it does not materially change the assessment.",
- "criteria": [
- {
- "id": "val-accrual__active",
- "name": "Accrual Active",
- "about": "Assesses whether value flows to tokenholders are currently active rather than merely theoretical or proposed.",
- "status": "at_risk",
- "notes": "No active value accrual mechanism for ONDO tokenholders was identified. Ondo products have documented product-level economics, but Aragon did not identify a fee distributor, staking reward, buyback program, DAO treasury, or other mechanism routing product economics to ONDO holders.",
- "evidence": [
- {
- "name": "Product Economics vs ONDO Holder Accrual",
- "summary": "Ondo has products with documented product-level economics, including yield, fees, expenses, and spreads. Those mechanics do not identify an ONDO-holder accrual mechanism.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__treasury",
- "name": "Treasury Ownership",
- "about": "Determines whether protocol treasury assets are programmatically controlled by tokenholder governance.",
- "status": "at_risk",
- "notes": "Aragon has not been able to identify a DAO treasury address for ONDO governance. No FeeDistributor or Treasury contract exists.",
- "evidence": [
- {
- "name": "No Treasury Identified",
- "summary": "No DAO treasury contract identified. No fee distribution mechanism was identified for Ondo product economics. No governance proposals for treasury creation were identified.",
- "urls": [
- {
- "name": "Ondo DAO Proposals",
- "url": "https://www.tally.xyz/gov/ondo-dao",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__mechanism",
- "name": "Accrual Mechanism Control",
- "about": "Evaluates whether only tokenholders can modify parameters governing value capture, such as fees or revenue routing.",
- "status": "at_risk",
- "notes": "ONDO holders have no identified control over revenue routing for Ondo's core products. Core product parameters are controlled by company-held roles and multisigs. Flux is ONDO-governed but represents a small share of Ondo TVL.",
- "evidence": [
- {
- "name": "OUSG/USDY Price Oracles (Company-Controlled)",
- "summary": "The price oracles that determine OUSG/USDY NAV are controlled by SETTER_ROLE-restricted `setPrice()` functions. ONDO tokenholders cannot control these oracle price-update roles.",
- "urls": [
- {
- "name": "OUSG Oracle",
- "url": "https://etherscan.io/address/0x0502c5ae08E7CD64fe1AEDA7D6e229413eCC6abe",
- "type": "explorer"
- },
- {
- "name": "USDY Oracle",
- "url": "https://etherscan.io/address/0xA0219AA5B31e65Bc920B5b6DFb8EdF0988121De0",
- "type": "explorer"
- },
- {
- "name": "RWAOracleExternalComparisonCheck.sol (setPrice)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleExternalComparisonCheck.sol#L147",
- "type": "github"
- },
- {
- "name": "RWAOracleRateCheck.sol (setPrice rate limit)",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/rwaOracles/RWAOracleRateCheck.sol#L81-L90",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets (Company-Controlled via TimelockController)",
- "summary": "GMTokenManager admin is TimelockController (2-hour delay). ONDO tokenholders have no control over Global Markets fee parameters.",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c",
- "type": "explorer"
- },
- {
- "name": "Global Markets TimelockController",
- "url": "https://etherscan.io/address/0x3715B2154d2FF4C5B027C7a1f734B53F27bc34f1",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "val-accrual__offchain",
- "name": "Offchain Value Accrual",
- "tags": [
- "Reference"
- ],
- "about": "Are there additional offchain value accrual flows that benefit tokenholders?",
- "status": "warning",
- "notes": "Ondo product economics may accrue through product-holder yield, issuer/operator fees, spreads, expenses, or service revenue, but no documented offchain value-accrual flow to ONDO holders was identified.",
- "evidence": [
- {
- "name": "Ondo Product Economics",
- "summary": "Ondo products have documented product-level economics, including yield, fees, expenses, and spreads. These mechanics describe product economics, not ONDO-holder accrual. No onchain mechanism guarantees that residual issuer/operator economics flow to ONDO holders.",
- "urls": [
- {
- "name": "OUSG Fees",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/fees-and-taxes",
- "type": "docs"
- },
- {
- "name": "OUSG Yield",
- "url": "https://docs.ondo.finance/qualified-access-products/ousg/yield",
- "type": "docs"
- },
- {
- "name": "USDY Product Economics",
- "url": "https://docs.ondo.finance/general-access-products/usdy/comparison-stablecoins",
- "type": "docs"
- },
- {
- "name": "USDY Issuer / Ondo Finance Relationship",
- "url": "https://docs.ondo.finance/general-access-products/usdy/important-notes",
- "type": "docs"
- },
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- },
- {
- "name": "Global Markets Revenue",
- "summary": "Global Markets documentation describes fees and quote spreads retained by Ondo Global Markets. Aragon did not identify a mechanism routing those fees or spreads to ONDO holders or an ONDO-controlled treasury.",
- "urls": [
- {
- "name": "Global Markets Fees",
- "url": "https://docs.ondo.finance/ondo-global-markets/fees-and-taxes",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability",
- "name": "Verifiability",
- "tags": [
- "Metric 3"
- ],
- "about": "This metric measures whether a token's economically material code and deployments are independently verifiable from primary evidence without relying on insider assurances. In practice, it answers: what code is running, where it is deployed, and whether the deployed bytecode can be credibly matched to publicly available source (including proxy implementations and build inputs where relevant).",
- "summary": "ONDO token is verified on Etherscan. OUSG/USDY/Global Markets contracts are verified with public GitHub and audit code available. The deployed ONDO token uses AccessControl, which differs from the public ondo-v1 repository.",
- "criteria": [
- {
- "id": "verifiability__token-source",
- "name": "Token Contract Source Verification",
- "about": "Determines whether the token contract's source code is publicly available and verifiably matches the deployed bytecode.",
- "status": "positive",
- "notes": "The ONDO token contract is verified on Etherscan. The deployed contract uses AccessControl, which differs from the simpler Ownable-based contract in the public ondo-v1 repository.",
- "evidence": [
- {
- "urls": [
- {
- "name": "ONDO Token (Etherscan verified)",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#code",
- "type": "explorer"
- },
- {
- "name": "Public ondo-v1 repo (differs from deployed)",
- "url": "https://github.com/ondoprotocol/ondo-v1/blob/main/contracts/tokens/Ondo.sol",
- "type": "github"
- }
- ]
- }
- ]
- },
- {
- "id": "verifiability__protocol-source",
- "name": "Protocol Component Source Verification",
- "about": "Determines whether core protocol contracts are publicly accessible and verifiable against their onchain deployments.",
- "status": "positive",
- "notes": "OUSG, USDY, and Global Markets contracts are verified on Etherscan. Public GitHub repositories and audit code available.",
- "evidence": [
- {
- "name": "OUSG/USDY",
- "urls": [
- {
- "name": "OUSG",
- "url": "https://etherscan.io/address/0x1B19C19393e2d034D8Ff31ff34c81252FcBbee92#code",
- "type": "explorer"
- },
- {
- "name": "USDY",
- "url": "https://etherscan.io/address/0x96F6eF951840721AdBF46Ac996b59E0235CB985C#code",
- "type": "explorer"
- },
- {
- "name": "USDY GitHub",
- "url": "https://github.com/ondoprotocol/usdy",
- "type": "github"
- },
- {
- "name": "Audit code (Code4rena)",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance",
- "type": "github"
- }
- ]
- },
- {
- "name": "Global Markets",
- "urls": [
- {
- "name": "GMTokenManager",
- "url": "https://etherscan.io/address/0x2c158BC456e027b2AfFCCadF1BDBD9f5fC4c5C8c#code",
- "type": "explorer"
- },
- {
- "name": "USDon",
- "url": "https://etherscan.io/address/0xAcE8E719899F6E91831B18AE746C9A965c2119F1#code",
- "type": "explorer"
- },
- {
- "name": "USDonManager",
- "url": "https://etherscan.io/address/0x05CCbB4b74854f8A067b83475E8c34f5a413D7e1#code",
- "type": "explorer"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "distribution",
- "name": "Token Distribution",
- "tags": [
- "Metric 4"
- ],
- "about": "This metric evaluates whether ownership and therefore effective voting power in governance is meaningfully distributed. It measures whether any single actor or coordinated group under common control can form a controlling block large enough to determine or constrain tokenholder-governed outcomes.",
- "summary": "~59% of ONDO supply is held by a single team multisig, giving effective governance control. Vesting schedules exist per documentation but specific addresses are not publicly verifiable onchain.",
- "criteria": [
- {
- "id": "distribution__concentration",
- "name": "Ownership Concentration",
- "about": "Measures whether a single actor or coordinated group controls a majority of the voting supply.",
- "status": "at_risk",
- "notes": "~59% of ONDO supply is held by a single team multisig. This gives the team unilateral control over governance. The team can pass any proposal and block any proposal.",
- "evidence": [
- {
- "name": "Team Holdings",
- "summary": "Team Multisig balance: ~5.9B ONDO (~59% of supply).\nTotal supply: 10B ONDO.\nMultisig config: 4-of-7.\n\nThis multisig also holds DEFAULT_ADMIN_ROLE and MINTER_ROLE on the ONDO token. \"Decentralized governance\" is effectively team governance.",
- "urls": [
- {
- "name": "Team Multisig holdings",
- "url": "https://etherscan.io/address/0x677fd4ed8ae623f2f625deb2d64f2070e46ca1a1",
- "type": "explorer"
- },
- {
- "name": "ONDO Token totalSupply",
- "url": "https://etherscan.io/address/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3#readContract",
- "type": "explorer"
- }
- ]
- }
- ]
- },
- {
- "id": "distribution__supply-schedule",
- "name": "Future Token Unlocks",
- "about": "Are there known, future events (such as vesting cliffs) that will materially affect the concentration of tokens?",
- "status": "warning",
- "notes": "Per documentation, unlock schedules exist for team and investors with unclear start dates, but the token being transferrable from Jan 2024 allows an educated guess of many unlocks yet to pan out. Aragon has not been able to verify specific vesting contract addresses from onchain data.",
- "evidence": [
- {
- "name": "Documented Schedule",
- "summary": "CoinList Tranche 1 (~0.3%): 1-year lock, then 18-month linear release. \n\nCoinList Tranche 2 (~1.7%): 1-year lock, then 6-month linear release. \n\nSeed Investors (<7%): 1-year cliff, then 48-month release. \n\nSeries A (<7%): 1-year cliff, then 48-month release. \n\nCore Team: 5-year extended lock-up from the transfer unlock.\n\nAragon has not been able to verify specific vesting contract addresses or unlock schedules from onchain data.",
- "urls": [
- {
- "name": "Token Documentation",
- "url": "https://docs.ondo.foundation/ondo-token",
- "type": "docs"
- },
- {
- "name": "CoinList - ONDO Community Sale",
- "url": "https://coinlist.co/ondo",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "id": "offchain",
- "name": "Offchain Dependencies",
- "tags": [
- "Reference"
- ],
- "about": "Economically material assets and obligations often sit offchain—outside the custody and direct enforcement of a token—while still determining which interfaces and domains most users reach, where fees are charged or captured, who can commercialize or restrict the software, and who can sign contracts or move offchain funds.",
- "summary": "Ondo Finance Inc. operates the primary website, documentation, APIs, dashboards, and technical interfaces under its Terms of Service. The Terms preserve Ondo-related trademark/IP rights and separate interface services from product issuance or economic terms. Certain product source files use BUSL-1.1 SPDX headers, but no tokenholder-controlled licensing right was identified.",
- "criteria": [
- {
- "id": "offchain__trademark",
- "name": "Trademark",
- "about": "Are core trademarks and brand assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Ondo's Terms of Service state that Ondo names, logos, and marks used on the site or services are owned by Ondo, its affiliates, Covered Entities, or applicable licensors.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Proprietary Rights",
- "summary": "The Terms reserve Ondo names, logos, and marks to Ondo, its affiliates, Covered Entities, or applicable licensors, and do not grant users rights in those trademarks.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__distribution",
- "name": "Distribution",
- "about": "Are primary domains and distribution assets owned or controlled by a tokenholder-controlled legal entity?",
- "status": "warning",
- "notes": "Ondo Finance Inc. controls the primary website, documentation, APIs, dashboards, and technical interfaces. The Terms of Service identify Ondo Finance Inc. as the contracting party for those interface services, while product issuance and economic terms are governed separately by Covered Entity terms.",
- "evidence": [
- {
- "name": "Ondo Terms of Service - Interface Services",
- "summary": "Ondo Finance Inc. operates the site and interface services. The Terms also state that Covered Entities are separate legal entities providing their own services under their own terms.",
- "urls": [
- {
- "name": "Terms of Service",
- "url": "https://docs.ondo.finance/legal/terms-of-service",
- "type": "docs"
- }
- ]
- }
- ]
- },
- {
- "id": "offchain__licensing",
- "name": "Licensing",
- "about": "Is core protocol software/IP (and any associated licensing rights, where applicable) owned or controlled by a tokenholder-controlled legal entity?",
- "status": "unevaluated",
- "notes": "Certain USDY/rOUSG source files use SPDX-License-Identifier: BUSL-1.1. BUSL-1.1 is not an open-source license and restricts production/commercial use until the applicable change date or open-source conversion.",
- "evidence": [
- {
- "name": "BUSL-1.1 Source Headers",
- "summary": "USDY and rOUSG source files include BUSL-1.1 SPDX headers. No repo-level license file or tokenholder-controlled license holder was identified.",
- "urls": [
- {
- "name": "USDY source SPDX header",
- "url": "https://github.com/ondoprotocol/usdy/blob/main/contracts/usdy/USDY.sol#L1",
- "type": "github"
- },
- {
- "name": "rOUSG source SPDX header",
- "url": "https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L1",
- "type": "github"
- },
- {
- "name": "BUSL-1.1 license text",
- "url": "https://spdx.org/licenses/BUSL-1.1.html",
- "type": "docs"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
-}
diff --git a/tests/golden/scores.json b/tests/golden/scores.json
deleted file mode 100644
index 48a7426..0000000
--- a/tests/golden/scores.json
+++ /dev/null
@@ -1,585 +0,0 @@
-{
- "aave": {
- "tokenId": "aave",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "aero": {
- "tokenId": "aero",
- "passing": 12,
- "total": 13,
- "percentage": 92.3076923076923,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 6,
- "total": 7,
- "percentage": 85.71428571428571,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "crv": {
- "tokenId": "crv",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "ena": {
- "tokenId": "ena",
- "passing": 2,
- "total": 15,
- "percentage": 13.333333333333334,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 0,
- "total": 7,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 0,
- "total": 4,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "ldo": {
- "tokenId": "ldo",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "lqty": {
- "tokenId": "lqty",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "uni": {
- "tokenId": "uni",
- "passing": 13,
- "total": 13,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 1,
- "total": 1,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "yb": {
- "tokenId": "yb",
- "passing": 11,
- "total": 14,
- "percentage": 78.57142857142857,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 2,
- "total": 3,
- "percentage": 66.66666666666666,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "sky": {
- "tokenId": "sky",
- "passing": 12,
- "total": 12,
- "percentage": 100,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 7,
- "total": 7,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 3,
- "total": 3,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 0,
- "percentage": 0,
- "evaluated": false,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 1,
- "total": 2,
- "percentage": 50,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "ethfi": {
- "tokenId": "ethfi",
- "passing": 3,
- "total": 14,
- "percentage": 21.428571428571427,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 1,
- "total": 7,
- "percentage": 14.285714285714285,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 1,
- "total": 3,
- "percentage": 33.33333333333333,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 1,
- "total": 2,
- "percentage": 50,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 3,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- },
- "ondo": {
- "tokenId": "ondo",
- "passing": 4,
- "total": 15,
- "percentage": 26.666666666666668,
- "metrics": [
- {
- "metricId": "onchain-ctrl",
- "metricName": "Onchain Control",
- "passing": 2,
- "total": 7,
- "percentage": 28.57142857142857,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "val-accrual",
- "metricName": "Value Accrual",
- "passing": 0,
- "total": 4,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "verifiability",
- "metricName": "Verifiability",
- "passing": 2,
- "total": 2,
- "percentage": 100,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "distribution",
- "metricName": "Token Distribution",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": true,
- "reference": false
- },
- {
- "metricId": "offchain",
- "metricName": "Offchain Dependencies",
- "passing": 0,
- "total": 2,
- "percentage": 0,
- "evaluated": false,
- "reference": true
- }
- ]
- }
-}
diff --git a/tests/golden/testimonials.json b/tests/golden/testimonials.json
deleted file mode 100644
index 2846926..0000000
--- a/tests/golden/testimonials.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "title": "Evidence-backed due diligence for investors",
- "testimonials": [
- {
- "id": "miles-a16z",
- "name": "Miles Jennings",
- "organization": "a16z",
- "avatar": "/images/testimonials/miles-jennings.png",
- "url": "https://a16zcrypto.com/",
- "quote": "Aragon's index provides much needed transparency for network tokens. It shows who still has power over a token after it launches, what that means for users and investors, and what risks come with those hidden dependencies."
- },
- {
- "id": "f5-crypto",
- "name": "Paul Otto",
- "organization": "F5 Crypto",
- "avatar": "/images/testimonials/paul-otto.png",
- "url": "https://f5crypto.com/en/",
- "quote": "Aragon's OTF asks important questions about a crypto project's token design. For example, who controls where revenues go, and who can change that? It then answers these in detail with direct links to the source. The insights provided by the OTF have become a vital part in our token analysis at F5 Crypto."
- }
- ]
-}
diff --git a/tests/golden/tokens.json b/tests/golden/tokens.json
deleted file mode 100644
index 6da7a95..0000000
--- a/tests/golden/tokens.json
+++ /dev/null
@@ -1,277 +0,0 @@
-[
- {
- "id": "aave",
- "coingeckoId": "aave",
- "name": "AAVE",
- "symbol": "AAVE",
- "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
- "icon": "https://assets.coingecko.com/coins/images/12645/standard/aave-token-round.png",
- "description": "AAVE is the native token of Aave, the largest lending protocol in DeFi.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 14,
- "neutral": 3,
- "atRisk": 1,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aave.com/",
- "twitter": "https://twitter.com/aave",
- "scan": "https://etherscan.io/token/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
- },
- "infoDescription": "Aave is an Open Source Protocol to create Non-Custodial Liquidity Markets to earn interest on supplying and borrowing assets with a variable interest rate."
- },
- {
- "id": "aero",
- "coingeckoId": "aerodrome-finance",
- "name": "AERO",
- "symbol": "AERO",
- "address": "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
- "icon": "https://assets.coingecko.com/coins/images/31745/standard/token.png",
- "description": "AERO is the native token of the Aerodrome protocol, a ve(3,3) MetaDex on Base with largely immutable contracts and programmatic value flows to veAERO holders.",
- "network": "base",
- "evidenceEntries": 22,
- "positive": 19,
- "neutral": 2,
- "atRisk": 1,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://aerodrome.finance/",
- "twitter": "https://twitter.com/Aerodrome",
- "scan": "https://basescan.org/token/0x940181a94A35A4569E4529A3CDfB74e38FD98631"
- },
- "infoDescription": "Aerodrome is a decentralized exchange where you can execute low-fee swaps, deposit tokens to earn rewards, and actively participate in the onchain economy."
- },
- {
- "id": "crv",
- "coingeckoId": "curve-dao-token",
- "name": "CRV",
- "symbol": "CRV",
- "address": "0xD533a949740bb3306d119CC777fa900bA034cd52",
- "icon": "https://assets.coingecko.com/coins/images/12124/standard/Curve.png",
- "description": "CRV is the native token of the Curve protocol - a leading stablecoin DEX. The veCRV gauge system enables programmatic, onchain value direction by tokenholders.",
- "network": "ethereum",
- "evidenceEntries": 4,
- "positive": 4,
- "neutral": 0,
- "atRisk": 0,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://curve.finance/",
- "twitter": "https://twitter.com/curvefinance",
- "scan": "https://etherscan.io/token/0xD533a949740bb3306d119CC777fa900bA034cd52"
- },
- "infoDescription": "Curve is a decentralized exchange (DEX) and automated market maker (AMM) on Ethereum and EVM-compatible sidechains/L2s, designed for the efficient trading of stablecoins and volatile assets."
- },
- {
- "id": "ena",
- "coingeckoId": "ethena",
- "name": "ENA",
- "symbol": "ENA",
- "address": "0x57e114B691Db790C35207b2e685D4A43181e6061",
- "icon": "https://assets.coingecko.com/coins/images/36530/standard/ethena.png",
- "description": "ENA is the governance token of Ethena, a synthetic dollar protocol. Governance is advisory via Snapshot signaling; the Dev Multisig executes all decisions. Fee switch received positive forum signals but awaits Snapshot vote and onchain execution.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 2,
- "neutral": 0,
- "atRisk": 16,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ethena.fi/",
- "twitter": "https://twitter.com/ethena",
- "scan": "https://etherscan.io/token/0x57e114B691Db790C35207b2e685D4A43181e6061"
- },
- "infoDescription": "Ethena is a synthetic dollar protocol built on Ethereum, offering a crypto-native alternative to traditional stablecoins via its USDe token and yield-bearing sUSDe."
- },
- {
- "id": "ldo",
- "coingeckoId": "lido-dao",
- "name": "LDO",
- "symbol": "LDO",
- "address": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32",
- "icon": "https://assets.coingecko.com/coins/images/13573/standard/Lido_DAO.png",
- "description": "LDO is the native token of Lido, a liquid staking protocol with onchain voting, safeguarded by stETH holders via Dual Governance.",
- "network": "ethereum",
- "evidenceEntries": 12,
- "positive": 8,
- "neutral": 3,
- "atRisk": 1,
- "lastUpdated": 1777631939,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://lido.fi/",
- "twitter": "https://twitter.com/lidofinance",
- "scan": "https://etherscan.io/token/0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
- },
- "infoDescription": "Lido is the leading liquid staking solution for Ethereum."
- },
- {
- "id": "lqty",
- "coingeckoId": "liquity",
- "name": "LQTY",
- "symbol": "LQTY",
- "address": "0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D",
- "icon": "https://assets.coingecko.com/coins/images/14665/standard/logo_V2.png",
- "description": "LQTY is the secondary token of the Liquity protocol - a decentralised, immutable, and governance-free borrowing protocol that issues the LUSD (V1) and BOLD (V2) stablecoins.",
- "network": "ethereum",
- "evidenceEntries": 0,
- "positive": 0,
- "neutral": 0,
- "atRisk": 0,
- "lastUpdated": 1778064256,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://www.liquity.org/",
- "twitter": "https://twitter.com/LiquityProtocol",
- "scan": "https://etherscan.io/token/0x6DEa81C8171D0bA574754EF6F8b412F2Ed88c54D"
- },
- "infoDescription": "Liquity is a decentralised, immutable borrowing protocol that lets users mint stablecoins (LUSD in V1, BOLD in V2) against ETH and LST collateral with no governance over core parameters."
- },
- {
- "id": "uni",
- "coingeckoId": "uniswap",
- "name": "UNI",
- "symbol": "UNI",
- "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
- "icon": "https://assets.coingecko.com/coins/images/12504/standard/uniswap-logo.png",
- "description": "UNI is the governance token of the Uniswap DAO, the DAO governing the Uniswap protocol - the largest decentralised exchange in DeFi.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 13,
- "neutral": 4,
- "atRisk": 1,
- "lastUpdated": 1775651992,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://uniswap.org/",
- "twitter": "https://twitter.com/uniswap",
- "scan": "https://etherscan.io/token/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
- },
- "infoDescription": "Uniswap is the largest onchain marketplace. Buy and sell crypto on Ethereum and 16+ other chains."
- },
- {
- "id": "yb",
- "coingeckoId": "yield-basis",
- "name": "YB",
- "symbol": "YB",
- "address": "0x01791F726B4103694969820be083196cC7c045fF",
- "icon": "https://coin-images.coingecko.com/coins/images/54871/small/yieldbasis_400x400.png",
- "description": "YB is the token of YieldBasis. veYB holders control protocol governance through Aragon, direct YB emissions via gauge voting, and receive protocol admin fees.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 11,
- "neutral": 3,
- "atRisk": 4,
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://yieldbasis.com/",
- "twitter": "https://x.com/yieldbasis",
- "scan": "https://etherscan.io/token/0x01791F726B4103694969820be083196cC7c045fF"
- },
- "infoDescription": "Yield Basis is the liquidity protocol designed to eliminate Impermanent Loss (IL) in AMMs using constantly-maintained 2x leveraged liquidity provision."
- },
- {
- "id": "sky",
- "coingeckoId": "sky",
- "name": "SKY",
- "symbol": "SKY",
- "address": "0x56072C95FAA701256059aa122697B133aDEd9279",
- "icon": "https://assets.coingecko.com/coins/images/39925/standard/sky.jpg",
- "description": "SKY demonstrates strong ownership characteristics with binding onchain governance and active value accrual through buybacks. The token is non-upgradeable with no censorship capabilities. Trademarks remain with an independent foundation.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 13,
- "neutral": 3,
- "atRisk": 2,
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://sky.money/",
- "twitter": "https://twitter.com/SkyEcosystem",
- "scan": "https://etherscan.io/token/0x56072C95FAA701256059aa122697B133aDEd9279"
- },
- "infoDescription": "Sky Protocol (formerly MakerDAO) issues two stablecoins: DAI (non-upgradeable) and USDS (upgradeable)."
- },
- {
- "id": "ethfi",
- "coingeckoId": "ether-fi",
- "name": "ETHFI",
- "symbol": "ETHFI",
- "address": "0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB",
- "icon": "https://assets.coingecko.com/coins/images/35958/standard/etherfi.jpeg",
- "description": "EtherFi runs restaking infrastructure, liquid vaults, and savings products — expanding from LST into neobank territory. Governance is offchain with multisig execution. An active buyback program distributes purchased ETHFI to sETHFI holders; any funding from broader protocol revenue is currently discretionary.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 3,
- "neutral": 13,
- "atRisk": 2,
- "lastUpdated": 1774549304,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ether.fi/",
- "twitter": "https://twitter.com/ether_fi",
- "scan": "https://etherscan.io/token/0xFe0c30065B384F05761f15d0CC899D4F9F9Cc0eB"
- },
- "infoDescription": "ether.fi is a liquid restaking protocol that enables users to stake ETH while maintaining liquidity through eETH tokens and participating in EigenLayer restaking."
- },
- {
- "id": "ondo",
- "name": "ONDO",
- "symbol": "ONDO",
- "address": "0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3",
- "icon": "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png",
- "description": "Ondo Finance tokenizes real-world assets: OUSG (US Treasuries), USDY (yield-bearing stablecoin), and Global Markets (tokenized equities). ONDO token has no control over these core products; team multisigs govern all ~$3.5B TVL.",
- "network": "ethereum",
- "evidenceEntries": 18,
- "positive": 3,
- "neutral": 2,
- "atRisk": 13,
- "lastUpdated": 1778674909,
- "updatedBy": {
- "avatar": "/logo192.png",
- "name": "Aragon Developers"
- },
- "links": {
- "website": "https://ondo.finance/",
- "twitter": "https://twitter.com/OndoFinance",
- "scan": "https://etherscan.io/token/0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3"
- },
- "infoDescription": "Ondo Finance is a tokenized real-world asset (RWA) protocol with ~$3.56B TVL across OUSG, USDY, and Global Markets. ONDO token governs Flux Finance (~$43M TVL), a Compound V2 fork for permissioned lending.",
- "coingeckoId": "ondo-finance"
- }
-]
diff --git a/tests/round-trip.test.ts b/tests/round-trip.test.ts
deleted file mode 100644
index 4246d2d..0000000
--- a/tests/round-trip.test.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * Round-trip gate: the COMPOSER's join/scoring logic must reproduce the
- * golden fixtures captured from the pre-refactor runtime (tests/golden/,
- * frozen 2026-06-05) when run over the frozen content snapshot
- * (tests/fixtures/content-6b17fa7/, the atoms as migrated at commit 6b17fa7).
- *
- * Both inputs and expectations are frozen: this permanently regression-tests
- * the composition logic without breaking when live content/ legitimately
- * evolves (editorial edits, CI timestamp updates). Live content is covered
- * by atoms-valid.test.ts (schemas) and freshness.test.ts (generated parity).
- *
- * ONE intentional diff is allowed and asserted explicitly: the token status
- * counts (positive/neutral/atRisk/evidenceEntries) are DERIVED from
- * evaluations at compose time — the legacy hand-maintained counts were stale
- * for all 11 tokens and are corrected, not preserved.
- */
-import { join } from "node:path"
-import { describe, expect, it } from "vitest"
-// biome-ignore lint/style/noNamespaceImport: JSON module namespaces
-import goldenFaq from "./golden/faq.json"
-import goldenFramework from "./golden/framework.json"
-import goldenMetrics from "./golden/metrics.json"
-import goldenScores from "./golden/scores.json"
-import goldenTestimonials from "./golden/testimonials.json"
-import goldenTokens from "./golden/tokens.json"
-// @ts-expect-error untyped .mjs module
-import { composeAll } from "../scripts/compose-data.mjs"
-
-const COUNT_FIELDS = ["positive", "neutral", "atRisk", "evidenceEntries"]
-
-const withoutCounts = (obj: Record) =>
- Object.fromEntries(
- Object.entries(obj).filter(
- ([k]) => !COUNT_FIELDS.includes(k) && k !== "score"
- )
- )
-
-const composed = composeAll(join(__dirname, "fixtures", "content-6b17fa7"))
-
-describe("round-trip vs golden fixtures", () => {
- it("covers every golden token, none extra", () => {
- expect(composed.tokenDocs.map((d: { id: string }) => d.id).sort()).toEqual(
- goldenTokens.map((t) => t.id).sort()
- )
- })
-
- for (const golden of goldenTokens) {
- describe(golden.id, () => {
- const doc = composed.tokenDocs.find(
- (d: { id: string }) => d.id === golden.id
- )
-
- it("composed metrics equal golden merged metrics", () => {
- expect(doc.metrics).toEqual(
- goldenMetrics[golden.id as keyof typeof goldenMetrics]
- )
- })
-
- it("composed score equals golden score", () => {
- expect(doc.score).toEqual(
- goldenScores[golden.id as keyof typeof goldenScores]
- )
- })
-
- it("registry fields equal golden token (counts excluded)", () => {
- expect(withoutCounts(doc)).toMatchObject(withoutCounts(golden))
- })
-
- it("derived counts equal counts computed from golden metrics (intentional correction of stale legacy values)", () => {
- const criteria = goldenMetrics[
- golden.id as keyof typeof goldenMetrics
- ].flatMap((m) => m.criteria)
- expect(doc.positive).toBe(
- criteria.filter((c) => c.status === "positive").length
- )
- expect(doc.neutral).toBe(
- criteria.filter((c) => c.status === "warning").length
- )
- expect(doc.atRisk).toBe(
- criteria.filter((c) => c.status === "at_risk").length
- )
- expect(doc.evidenceEntries).toBe(
- criteria.flatMap((c) => ("evidence" in c ? c.evidence : [])).length
- )
- })
- })
- }
-
- it("framework doc projects onto golden framework", () => {
- expect(
- composed.frameworkDoc.metrics.map(
- ({
- id,
- name,
- about,
- criteria,
- }: {
- id: string
- name: string
- about: string
- criteria: unknown
- }) => ({ id, name, about, criteria })
- )
- ).toEqual(goldenFramework)
- })
-
- it("faq topics equal golden", () => {
- expect(composed.faq.topics).toEqual(goldenFaq)
- })
-
- it("testimonials equal golden", () => {
- expect(composed.testimonials).toEqual(goldenTestimonials)
- })
-
- it("index rows mirror token docs", () => {
- for (const row of composed.index.tokens) {
- const { metrics: _metrics, ...doc } = composed.tokenDocs.find(
- (d: { id: string }) => d.id === row.id
- )
- // Index rows ARE the doc minus metrics (full score + criterion-status
- // map included) — the dashboard read model needs no per-token docs.
- expect(row).toEqual(doc)
- }
- })
-})
From 167347daa02e9464733aaf70054514dec272ea3b Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Sat, 6 Jun 2026 20:04:50 +0200
Subject: [PATCH 12/38] fix: upgrade vitest past CVE-2026-47429
---
package.json | 2 +-
pnpm-lock.yaml | 272 +++++++++++++++++--------------------------------
2 files changed, 96 insertions(+), 178 deletions(-)
diff --git a/package.json b/package.json
index 0db91d4..8970d58 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"sharp": "^0.34.5",
"typescript": "^5.9.3",
"vite": "^7.3.1",
- "vitest": "^3.2.4",
+ "vitest": "4.1.7",
"web-vitals": "^5.1.0"
},
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0e3f395..69cd2e0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -160,8 +160,8 @@ importers:
specifier: ^7.3.1
version: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
vitest:
- specifier: ^3.2.4
- version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.11)(jiti@2.6.1)(jsdom@27.4.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(tsx@4.21.0)
+ specifier: 4.1.7
+ version: 4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
web-vitals:
specifier: ^5.1.0
version: 5.1.0
@@ -1559,6 +1559,9 @@ packages:
peerDependencies:
solid-js: ^1.6.12
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
'@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
@@ -2011,34 +2014,34 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
- '@vitest/expect@3.2.4':
- resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
+ '@vitest/expect@4.1.7':
+ resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==}
- '@vitest/mocker@3.2.4':
- resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
+ '@vitest/mocker@4.1.7':
+ resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==}
peerDependencies:
msw: ^2.4.9
- vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
- '@vitest/pretty-format@3.2.4':
- resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
+ '@vitest/pretty-format@4.1.7':
+ resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==}
- '@vitest/runner@3.2.4':
- resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
+ '@vitest/runner@4.1.7':
+ resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==}
- '@vitest/snapshot@3.2.4':
- resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
+ '@vitest/snapshot@4.1.7':
+ resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==}
- '@vitest/spy@3.2.4':
- resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
+ '@vitest/spy@4.1.7':
+ resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==}
- '@vitest/utils@3.2.4':
- resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
+ '@vitest/utils@4.1.7':
+ resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==}
accepts@2.0.0:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
@@ -2156,10 +2159,6 @@ packages:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
- cac@6.7.14:
- resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
- engines: {node: '>=8'}
-
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
@@ -2178,8 +2177,8 @@ packages:
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
- chai@5.3.3:
- resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ chai@6.2.2:
+ resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
chalk@5.6.2:
@@ -2198,10 +2197,6 @@ packages:
character-reference-invalid@2.0.1:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
- check-error@2.1.3:
- resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
- engines: {node: '>= 16'}
-
cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
@@ -2436,10 +2431,6 @@ packages:
babel-plugin-macros:
optional: true
- deep-eql@5.0.2:
- resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
- engines: {node: '>=6'}
-
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
@@ -2559,8 +2550,8 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
- es-module-lexer@1.7.0:
- resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+ es-module-lexer@2.1.0:
+ resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
@@ -2985,9 +2976,6 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-tokens@9.0.1:
- resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
-
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
@@ -3125,9 +3113,6 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
- loupe@3.2.1:
- resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
-
lru-cache@11.2.6:
resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
engines: {node: 20 || >=22}
@@ -3376,6 +3361,10 @@ packages:
resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==}
engines: {node: '>= 10'}
+ obug@2.1.2:
+ resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==}
+ engines: {node: '>=12.20.0'}
+
ofetch@2.0.0-alpha.3:
resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==}
@@ -3470,10 +3459,6 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
- pathval@2.0.1:
- resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
- engines: {node: '>= 14.16'}
-
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -3846,8 +3831,8 @@ packages:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
- std-env@3.10.0:
- resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+ std-env@4.1.0:
+ resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==}
stdin-discarder@0.2.2:
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
@@ -3891,9 +3876,6 @@ packages:
resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
engines: {node: '>=18'}
- strip-literal@3.1.0:
- resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
-
style-to-js@1.1.21:
resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==}
@@ -3929,9 +3911,6 @@ packages:
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
- tinyexec@0.3.2:
- resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
-
tinyexec@1.0.2:
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
engines: {node: '>=18'}
@@ -3940,16 +3919,8 @@ packages:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
- tinypool@1.1.1:
- resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
- engines: {node: ^18.0.0 || >=20.0.0}
-
- tinyrainbow@2.0.0:
- resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
- engines: {node: '>=14.0.0'}
-
- tinyspy@4.0.4:
- resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
+ tinyrainbow@3.1.0:
+ resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
engines: {node: '>=14.0.0'}
tldts-core@7.0.23:
@@ -4209,11 +4180,6 @@ packages:
victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
- vite-node@3.2.4:
- resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
- hasBin: true
-
vite-tsconfig-paths@5.1.4:
resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==}
peerDependencies:
@@ -4270,26 +4236,39 @@ packages:
vite:
optional: true
- vitest@3.2.4:
- resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ vitest@4.1.7:
+ resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==}
+ engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
- '@types/debug': ^4.1.12
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- '@vitest/browser': 3.2.4
- '@vitest/ui': 3.2.4
+ '@opentelemetry/api': ^1.9.0
+ '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
+ '@vitest/browser-playwright': 4.1.7
+ '@vitest/browser-preview': 4.1.7
+ '@vitest/browser-webdriverio': 4.1.7
+ '@vitest/coverage-istanbul': 4.1.7
+ '@vitest/coverage-v8': 4.1.7
+ '@vitest/ui': 4.1.7
happy-dom: '*'
jsdom: '*'
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
- '@types/debug':
+ '@opentelemetry/api':
optional: true
'@types/node':
optional: true
- '@vitest/browser':
+ '@vitest/browser-playwright':
+ optional: true
+ '@vitest/browser-preview':
+ optional: true
+ '@vitest/browser-webdriverio':
+ optional: true
+ '@vitest/coverage-istanbul':
+ optional: true
+ '@vitest/coverage-v8':
optional: true
'@vitest/ui':
optional: true
@@ -5522,6 +5501,8 @@ snapshots:
dependencies:
solid-js: 1.9.10
+ '@standard-schema/spec@1.1.0': {}
+
'@standard-schema/utils@0.3.0': {}
'@tabler/icons-react@3.37.1(react@19.2.4)':
@@ -6062,48 +6043,47 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitest/expect@3.2.4':
+ '@vitest/expect@4.1.7':
dependencies:
+ '@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
- '@vitest/spy': 3.2.4
- '@vitest/utils': 3.2.4
- chai: 5.3.3
- tinyrainbow: 2.0.0
+ '@vitest/spy': 4.1.7
+ '@vitest/utils': 4.1.7
+ chai: 6.2.2
+ tinyrainbow: 3.1.0
- '@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@vitest/mocker@4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
dependencies:
- '@vitest/spy': 3.2.4
+ '@vitest/spy': 4.1.7
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@22.19.11)(typescript@5.9.3)
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
- '@vitest/pretty-format@3.2.4':
+ '@vitest/pretty-format@4.1.7':
dependencies:
- tinyrainbow: 2.0.0
+ tinyrainbow: 3.1.0
- '@vitest/runner@3.2.4':
+ '@vitest/runner@4.1.7':
dependencies:
- '@vitest/utils': 3.2.4
+ '@vitest/utils': 4.1.7
pathe: 2.0.3
- strip-literal: 3.1.0
- '@vitest/snapshot@3.2.4':
+ '@vitest/snapshot@4.1.7':
dependencies:
- '@vitest/pretty-format': 3.2.4
+ '@vitest/pretty-format': 4.1.7
+ '@vitest/utils': 4.1.7
magic-string: 0.30.21
pathe: 2.0.3
- '@vitest/spy@3.2.4':
- dependencies:
- tinyspy: 4.0.4
+ '@vitest/spy@4.1.7': {}
- '@vitest/utils@3.2.4':
+ '@vitest/utils@4.1.7':
dependencies:
- '@vitest/pretty-format': 3.2.4
- loupe: 3.2.1
- tinyrainbow: 2.0.0
+ '@vitest/pretty-format': 4.1.7
+ convert-source-map: 2.0.0
+ tinyrainbow: 3.1.0
accepts@2.0.0:
dependencies:
@@ -6217,8 +6197,6 @@ snapshots:
bytes@3.1.2: {}
- cac@6.7.14: {}
-
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
@@ -6235,13 +6213,7 @@ snapshots:
ccount@2.0.1: {}
- chai@5.3.3:
- dependencies:
- assertion-error: 2.0.1
- check-error: 2.1.3
- deep-eql: 5.0.2
- loupe: 3.2.1
- pathval: 2.0.1
+ chai@6.2.2: {}
chalk@5.6.2: {}
@@ -6253,8 +6225,6 @@ snapshots:
character-reference-invalid@2.0.1: {}
- check-error@2.1.3: {}
-
cheerio-select@2.1.0:
dependencies:
boolbase: 1.0.0
@@ -6451,8 +6421,6 @@ snapshots:
dedent@1.7.1: {}
- deep-eql@5.0.2: {}
-
deepmerge@4.3.1: {}
default-browser-id@5.0.1: {}
@@ -6554,7 +6522,7 @@ snapshots:
es-errors@1.3.0: {}
- es-module-lexer@1.7.0: {}
+ es-module-lexer@2.1.0: {}
es-object-atoms@1.1.1:
dependencies:
@@ -6991,8 +6959,6 @@ snapshots:
js-tokens@4.0.0: {}
- js-tokens@9.0.1: {}
-
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
@@ -7114,8 +7080,6 @@ snapshots:
dependencies:
js-tokens: 4.0.0
- loupe@3.2.1: {}
-
lru-cache@11.2.6: {}
lru-cache@5.1.1:
@@ -7513,6 +7477,8 @@ snapshots:
object-treeify@1.1.33: {}
+ obug@2.1.2: {}
+
ofetch@2.0.0-alpha.3: {}
ohash@2.0.11: {}
@@ -7658,8 +7624,6 @@ snapshots:
pathe@2.0.3: {}
- pathval@2.0.1: {}
-
picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -8134,7 +8098,7 @@ snapshots:
statuses@2.0.2: {}
- std-env@3.10.0: {}
+ std-env@4.1.0: {}
stdin-discarder@0.2.2: {}
@@ -8177,10 +8141,6 @@ snapshots:
strip-final-newline@4.0.0: {}
- strip-literal@3.1.0:
- dependencies:
- js-tokens: 9.0.1
-
style-to-js@1.1.21:
dependencies:
style-to-object: 1.0.14
@@ -8207,8 +8167,6 @@ snapshots:
tinybench@2.9.0: {}
- tinyexec@0.3.2: {}
-
tinyexec@1.0.2: {}
tinyglobby@0.2.15:
@@ -8216,11 +8174,7 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
- tinypool@1.1.1: {}
-
- tinyrainbow@2.0.0: {}
-
- tinyspy@4.0.4: {}
+ tinyrainbow@3.1.0: {}
tldts-core@7.0.23: {}
@@ -8419,27 +8373,6 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-node@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0):
- dependencies:
- cac: 6.7.14
- debug: 4.4.3
- es-module-lexer: 1.7.0
- pathe: 2.0.3
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
- transitivePeerDependencies:
- - '@types/node'
- - jiti
- - less
- - lightningcss
- - sass
- - sass-embedded
- - stylus
- - sugarss
- - supports-color
- - terser
- - tsx
- - yaml
-
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
dependencies:
debug: 4.4.3
@@ -8470,48 +8403,33 @@ snapshots:
optionalDependencies:
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
- vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.11)(jiti@2.6.1)(jsdom@27.4.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(tsx@4.21.0):
+ vitest@4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
dependencies:
- '@types/chai': 5.2.3
- '@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
- '@vitest/pretty-format': 3.2.4
- '@vitest/runner': 3.2.4
- '@vitest/snapshot': 3.2.4
- '@vitest/spy': 3.2.4
- '@vitest/utils': 3.2.4
- chai: 5.3.3
- debug: 4.4.3
+ '@vitest/expect': 4.1.7
+ '@vitest/mocker': 4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ '@vitest/pretty-format': 4.1.7
+ '@vitest/runner': 4.1.7
+ '@vitest/snapshot': 4.1.7
+ '@vitest/spy': 4.1.7
+ '@vitest/utils': 4.1.7
+ es-module-lexer: 2.1.0
expect-type: 1.3.0
magic-string: 0.30.21
+ obug: 2.1.2
pathe: 2.0.3
picomatch: 4.0.3
- std-env: 3.10.0
+ std-env: 4.1.0
tinybench: 2.9.0
- tinyexec: 0.3.2
+ tinyexec: 1.0.2
tinyglobby: 0.2.15
- tinypool: 1.1.1
- tinyrainbow: 2.0.0
+ tinyrainbow: 3.1.0
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
- vite-node: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
why-is-node-running: 2.3.0
optionalDependencies:
- '@types/debug': 4.1.12
'@types/node': 22.19.11
jsdom: 27.4.0(@noble/hashes@1.8.0)
transitivePeerDependencies:
- - jiti
- - less
- - lightningcss
- msw
- - sass
- - sass-embedded
- - stylus
- - sugarss
- - supports-color
- - terser
- - tsx
- - yaml
w3c-xmlserializer@5.0.0:
dependencies:
From a9db93898c0a1399ff135d5d1f13609936a40547 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Sat, 6 Jun 2026 22:33:30 +0200
Subject: [PATCH 13/38] feat: add CI with vendored schema integrity gate
---
.github/workflows/ci.yml | 39 +++++++++++++++++++++
scripts/check-schema-drift.mjs | 46 ++++++++++++++++++++++++
scripts/vendor-schemas.mjs | 58 +++++++++++++++++++++++++++++++
src/lib/schemas/.vendor-lock.json | 10 ++++++
src/lib/schemas/index.ts | 13 +++----
5 files changed, 158 insertions(+), 8 deletions(-)
create mode 100644 .github/workflows/ci.yml
create mode 100644 scripts/check-schema-drift.mjs
create mode 100644 scripts/vendor-schemas.mjs
create mode 100644 src/lib/schemas/.vendor-lock.json
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..9bff6f3
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,39 @@
+name: CI
+
+on:
+ pull_request:
+ push:
+ branches: [development, main]
+
+permissions:
+ contents: read
+
+jobs:
+ checks:
+ runs-on: ubuntu-latest
+ steps:
+ # Third-party actions pinned to full commit SHAs (supply-chain policy)
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+
+ - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
+
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+ with:
+ node-version: "22"
+
+ - run: pnpm install --frozen-lockfile
+
+ - name: Vendored schema integrity
+ run: node scripts/check-schema-drift.mjs
+
+ - name: Lint and format
+ run: pnpm exec biome check src tests
+
+ - name: Type check
+ run: pnpm type-check
+
+ - name: Tests
+ run: pnpm test
+
+ - name: Build
+ run: pnpm build
diff --git a/scripts/check-schema-drift.mjs b/scripts/check-schema-drift.mjs
new file mode 100644
index 0000000..db11853
--- /dev/null
+++ b/scripts/check-schema-drift.mjs
@@ -0,0 +1,46 @@
+#!/usr/bin/env node
+/**
+ * Vendored-schema integrity gate (CI): every file in src/lib/schemas/ must
+ * match the vendor lock written by scripts/vendor-schemas.mjs. Direct edits
+ * to the vendored copy fail here — change schemas in otf-cms and re-vendor.
+ */
+import { createHash } from "node:crypto"
+import { readdirSync, readFileSync } from "node:fs"
+import { dirname, join } from "node:path"
+import { fileURLToPath } from "node:url"
+
+const dir = join(
+ dirname(fileURLToPath(import.meta.url)),
+ "..",
+ "src",
+ "lib",
+ "schemas"
+)
+
+const lock = JSON.parse(readFileSync(join(dir, ".vendor-lock.json"), "utf8"))
+const files = readdirSync(dir).filter((f) => f.endsWith(".ts"))
+
+const drifted = []
+for (const file of files.sort()) {
+ const hash = createHash("sha256")
+ .update(readFileSync(join(dir, file), "utf8"))
+ .digest("hex")
+ if (lock.files[file] !== hash) drifted.push(file)
+}
+for (const file of Object.keys(lock.files)) {
+ if (!files.includes(file)) drifted.push(`${file} (missing)`)
+}
+
+if (drifted.length > 0) {
+ console.error(
+ `Vendored schema drift detected: ${drifted.join(", ")}\n` +
+ "src/lib/schemas/ is a vendored copy of otf-cms/schemas " +
+ `(locked at ${lock.source_commit.slice(0, 7)}). ` +
+ "Edit the schemas in aragon/otf-cms, then run: node scripts/vendor-schemas.mjs"
+ )
+ process.exit(1)
+}
+
+console.log(
+ `vendored schemas intact (${files.length} files, source ${lock.source}@${lock.source_commit.slice(0, 7)})`
+)
diff --git a/scripts/vendor-schemas.mjs b/scripts/vendor-schemas.mjs
new file mode 100644
index 0000000..db89e49
--- /dev/null
+++ b/scripts/vendor-schemas.mjs
@@ -0,0 +1,58 @@
+#!/usr/bin/env node
+/**
+ * Re-vendor the schema contract from otf-cms (the source of truth).
+ *
+ * Usage: node scripts/vendor-schemas.mjs [path-to-otf-cms-checkout]
+ * (default: ../otf-cms sibling checkout)
+ *
+ * Copies otf-cms/schemas/*.ts into src/lib/schemas/, injects the VENDORED
+ * banner into index.ts, and records a vendor lock (source commit + per-file
+ * hashes). CI verifies the lock — direct edits to the vendored copy fail CI;
+ * this script is the only sanctioned way to change these files.
+ */
+import { execSync } from "node:child_process"
+import { createHash } from "node:crypto"
+import { readdirSync, readFileSync, writeFileSync } from "node:fs"
+import { dirname, join, resolve } from "node:path"
+import { fileURLToPath } from "node:url"
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const sourceRepo = resolve(root, process.argv[2] ?? "../otf-cms")
+const sourceDir = join(sourceRepo, "schemas")
+const targetDir = join(root, "src", "lib", "schemas")
+
+const BANNER = (commit) => `/**
+ * OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
+ *
+ * Source of truth: https://github.com/aragon/otf-cms (schemas/), vendored
+ * at commit ${commit}. Change upstream, then re-vendor:
+ * node scripts/vendor-schemas.mjs
+ * CI fails on direct edits (scripts/check-schema-drift.mjs).
+ */`
+
+const sourceCommit = execSync("git rev-parse HEAD", {
+ cwd: sourceRepo,
+ encoding: "utf8",
+}).trim()
+
+const files = readdirSync(sourceDir).filter((f) => f.endsWith(".ts"))
+const lock = { source: "aragon/otf-cms", source_commit: sourceCommit, files: {} }
+
+for (const file of files.sort()) {
+ let content = readFileSync(join(sourceDir, file), "utf8")
+ if (file === "index.ts") {
+ // Replace the upstream header comment with the vendored banner
+ content = content.replace(/^\/\*\*[\s\S]*?\*\//, BANNER(sourceCommit))
+ }
+ writeFileSync(join(targetDir, file), content)
+ lock.files[file] = createHash("sha256").update(content).digest("hex")
+}
+
+writeFileSync(
+ join(targetDir, ".vendor-lock.json"),
+ `${JSON.stringify(lock, null, 2)}\n`
+)
+
+console.log(
+ `vendored ${files.length} schema files from otf-cms@${sourceCommit.slice(0, 7)}`
+)
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
new file mode 100644
index 0000000..a213022
--- /dev/null
+++ b/src/lib/schemas/.vendor-lock.json
@@ -0,0 +1,10 @@
+{
+ "source": "aragon/otf-cms",
+ "source_commit": "2d37cee43562769d1bba4835a3e9c14142ac982d",
+ "files": {
+ "atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
+ "common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
+ "index.ts": "bc4ffe76c1b3029c2f4ec77d494273ae0ff49192377ea0972afc4dbe8a7f5110",
+ "read-models.ts": "ce8518850d56e6146593694f8185b90ecc6beaaded9e1b4d5e69bd93d250fbf2"
+ }
+}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index 265175e..7f69889 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -1,13 +1,10 @@
/**
- * OTF data contract — VENDORED COPY.
+ * OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
- * Source of truth: https://github.com/aragon/otf-cms (schemas/). Do not edit
- * here; change in otf-cms and re-vendor. A CI drift check pins the two
- * (plan task T-SCHEMA-DRIFT).
- *
- * Write-model schemas describe otf-cms content/ atoms; read-model schemas
- * describe the composed docs this app serves (src/data/generated/, later
- * Blob/Edge Config). This module must not import app code.
+ * Source of truth: https://github.com/aragon/otf-cms (schemas/), vendored
+ * at commit 2d37cee43562769d1bba4835a3e9c14142ac982d. Change upstream, then re-vendor:
+ * node scripts/vendor-schemas.mjs
+ * CI fails on direct edits (scripts/check-schema-drift.mjs).
*/
export * from "./atoms"
export * from "./common"
From 4f95cd956df7e1947600a32653c307ae3c37de9d Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 9 Jun 2026 16:10:17 +0200
Subject: [PATCH 14/38] feat: version published API under /api/v1 and add
llms.txt agent guide
---
public/agent-guide.md | 58 ++++++++
public/llms.txt | 26 ++++
src/lib/published-queries.ts | 8 +-
src/lib/server/published-data.ts | 6 +
src/lib/server/token-api.ts | 15 +-
src/routeTree.gen.ts | 129 ++++++++++--------
src/routes/api.v1.faq.ts | 10 ++
.../{api.framework.ts => api.v1.framework.ts} | 2 +-
....$tokenId.ts => api.v1.tokens.$tokenId.ts} | 2 +-
.../{api.tokens.ts => api.v1.tokens.ts} | 2 +-
tests/api-endpoints.test.ts | 13 ++
11 files changed, 207 insertions(+), 64 deletions(-)
create mode 100644 public/agent-guide.md
create mode 100644 public/llms.txt
create mode 100644 src/routes/api.v1.faq.ts
rename src/routes/{api.framework.ts => api.v1.framework.ts} (76%)
rename src/routes/{api.tokens.$tokenId.ts => api.v1.tokens.$tokenId.ts} (76%)
rename src/routes/{api.tokens.ts => api.v1.tokens.ts} (77%)
diff --git a/public/agent-guide.md b/public/agent-guide.md
new file mode 100644
index 0000000..333bcca
--- /dev/null
+++ b/public/agent-guide.md
@@ -0,0 +1,58 @@
+# OTF agent guide
+
+Orientation for agents and analysts consuming the Ownership Token Framework
+data. The framework evaluates how genuinely tokenholder-owned a crypto
+protocol is, on evidence, against a fixed rubric.
+
+## The data model in one minute
+
+A **token's analysis** is a join of two things:
+
+- the **framework** — a fixed rubric of ~5 metrics, each with several
+ criteria (the *questions*, identical for every token). See
+ `/api/v1/framework`.
+- that token's **evaluations** — one verdict per criterion: a status, notes,
+ and evidence (the *answers*). Delivered composed inside `/api/v1/tokens/{id}`.
+
+Criterion ids encode their place in the rubric: `onchain-ctrl__governance-workflow`
+= the `governance-workflow` criterion of the `onchain-ctrl` metric.
+
+## Endpoints
+
+| Endpoint | Use |
+|---|---|
+| `/api/v1/tokens` | discovery + cross-token comparison: slim rows with score, status counts, and a `criteriaStatuses` map keyed by criterion id |
+| `/api/v1/tokens/{id}` | a full token report: `metrics[].criteria[]` with `status`, `notes`, `evidence[]`; plus `score` and counts |
+| `/api/v1/framework` | the rubric: metric/criterion `name` + `about` definitions |
+| `/api/v1/faq` | methodology and framework Q&A |
+
+`{id}` is the lowercase token id (e.g. `ldo`, `aave`).
+
+## Status vocabulary (exactly these)
+
+- `positive` — criterion met
+- `warning` — partially met / caveats
+- `at_risk` — not met (the terminal negative)
+- `unevaluated` — not yet assessed
+- `reference` — informational, not a judgment
+
+A token's `score` counts only evaluated, non-reference criteria.
+
+## Provenance and reproducibility
+
+Every response is `{ data, provenance }`. `provenance.snapshot_id` is a
+deterministic content hash of the entire published data set — cite it to pin
+exactly what you read. `provenance.commit_ref` ties it to a deployment.
+`published_at` may be null in the current serving mode; use `snapshot_id` /
+`commit_ref` as the version of record.
+
+## How to use it well
+
+- To analyze a protocol, fetch its token doc and follow the **evidence URLs**
+ (onchain explorers, docs, governance forums) — the framework is the map;
+ the evidence is the territory.
+- To compare protocols, use the index's `criteriaStatuses` map — no need to
+ fetch every token doc.
+- Statuses are the canonical machine signal; `notes` are human prose context.
+- The data updates roughly quarterly; the same `snapshot_id` means the data
+ has not changed.
diff --git a/public/llms.txt b/public/llms.txt
new file mode 100644
index 0000000..ec75c65
--- /dev/null
+++ b/public/llms.txt
@@ -0,0 +1,26 @@
+# Ownership Token Framework
+
+Structured, evidence-backed analysis of crypto token ownership and governance,
+by Aragon. Machine-readable, schema-validated, versioned.
+
+## API (JSON, no auth)
+
+- /api/v1/tokens — index of all analyzed tokens (scores, status counts, per-criterion status map)
+- /api/v1/tokens/{id} — full analysis for one token (metrics, criteria, notes, evidence); {id} is lowercase, e.g. ldo
+- /api/v1/framework — the evaluation framework: metric and criterion definitions
+- /api/v1/faq — framework and methodology Q&A
+
+## How to read it
+
+- Each response is `{ data, provenance }`. provenance carries snapshot_id
+ (a content hash of the whole data set) and commit_ref — cite these for
+ reproducibility; do not infer freshness from cache headers.
+- Criterion status is exactly one of: positive | warning | at_risk |
+ unevaluated | reference. There is no other vocabulary.
+- A token's analysis is the framework (shared rubric) filled in with that
+ token's evaluations; criterion ids are composite, e.g.
+ onchain-ctrl__governance-workflow.
+
+## Guide
+
+A fuller orientation for agents and analysts: /agent-guide.md
diff --git a/src/lib/published-queries.ts b/src/lib/published-queries.ts
index 62e60f5..4ff8be9 100644
--- a/src/lib/published-queries.ts
+++ b/src/lib/published-queries.ts
@@ -7,7 +7,7 @@
* dropped from the client build entirely.
*
* Client side, queryFns fetch the canonical JSON endpoints — the app is the
- * first consumer of its own published API (/api/tokens*).
+ * first consumer of its own published API (/api/v1/tokens*).
*
* Published data is immutable per snapshot (~90-day editorial cadence), so
* staleTime/gcTime are Infinity: a new snapshot arrives as a new deployment
@@ -32,7 +32,7 @@ export const publishedIndexQuery = queryOptions({
const { getPublishedIndex } = await import("@/lib/server/published-data")
return getPublishedIndex()
}
- return fetchEnvelopeData("/api/tokens")
+ return fetchEnvelopeData("/api/v1/tokens")
},
staleTime: Number.POSITIVE_INFINITY,
gcTime: Number.POSITIVE_INFINITY,
@@ -47,7 +47,7 @@ export const publishedFrameworkQuery = queryOptions({
)
return getPublishedFramework()
}
- return fetchEnvelopeData("/api/framework")
+ return fetchEnvelopeData("/api/v1/framework")
},
staleTime: Number.POSITIVE_INFINITY,
gcTime: Number.POSITIVE_INFINITY,
@@ -64,7 +64,7 @@ export const publishedTokenDocQuery = (tokenId: string) => {
)
return getPublishedTokenDoc(normalizedId)
}
- const res = await fetch(`/api/tokens/${normalizedId}`)
+ const res = await fetch(`/api/v1/tokens/${normalizedId}`)
if (res.status === 404) return null
if (!res.ok) {
throw new Error(`Published data fetch failed: ${res.status}`)
diff --git a/src/lib/server/published-data.ts b/src/lib/server/published-data.ts
index b0f93dc..6cb400a 100644
--- a/src/lib/server/published-data.ts
+++ b/src/lib/server/published-data.ts
@@ -6,10 +6,12 @@
* implementation replaces the internals without any response-shape change —
* consumers depend only on this module's interface.
*/
+import faqData from "@/data/generated/faq.json"
import frameworkData from "@/data/generated/framework.json"
import indexData from "@/data/generated/index.json"
import manifestData from "@/data/generated/manifest.json"
import type {
+ FaqTopic,
FrameworkDoc,
IndexRow,
Manifest,
@@ -63,6 +65,10 @@ export function getPublishedFramework(): FrameworkDoc {
return frameworkData as FrameworkDoc
}
+export function getPublishedFaq(): { topics: FaqTopic[] } {
+ return faqData as { topics: FaqTopic[] }
+}
+
export function listPublishedTokenIds(): string[] {
return manifest.tokens
}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index e42a255..566e027 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -13,6 +13,7 @@
*/
import {
getProvenance,
+ getPublishedFaq,
getPublishedFramework,
getPublishedIndex,
getPublishedTokenDoc,
@@ -29,7 +30,7 @@ function jsonResponse(body: unknown, status = 200): Response {
})
}
-/** GET /api/tokens — the published index (discovery + cross-token queries). */
+/** GET /api/v1/tokens — the published index (discovery + cross-token queries). */
export function handleGetTokens(): Response {
return jsonResponse({
data: getPublishedIndex(),
@@ -37,7 +38,7 @@ export function handleGetTokens(): Response {
})
}
-/** GET /api/framework — canonical metric/criteria definitions + anchors. */
+/** GET /api/v1/framework — canonical metric/criteria definitions + anchors. */
export function handleGetFramework(): Response {
return jsonResponse({
data: getPublishedFramework(),
@@ -45,7 +46,15 @@ export function handleGetFramework(): Response {
})
}
-/** GET /api/tokens/{id} — one composed token doc (the per-token reusable unit). */
+/** GET /api/v1/faq — published framework/methodology Q&A. */
+export function handleGetFaq(): Response {
+ return jsonResponse({
+ data: getPublishedFaq(),
+ provenance: getProvenance(),
+ })
+}
+
+/** GET /api/v1/tokens/{id} — one composed token doc (the per-token reusable unit). */
export function handleGetToken(tokenId: string): Response {
const doc = getPublishedTokenDoc(tokenId)
if (!doc) {
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index f2100d3..4b42de8 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -12,9 +12,10 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as FaqRouteImport } from './routes/faq'
import { Route as IndexRouteImport } from './routes/index'
import { Route as TokensTokenIdRouteImport } from './routes/tokens/$tokenId'
-import { Route as ApiTokensRouteImport } from './routes/api.tokens'
-import { Route as ApiFrameworkRouteImport } from './routes/api.framework'
-import { Route as ApiTokensTokenIdRouteImport } from './routes/api.tokens.$tokenId'
+import { Route as ApiV1TokensRouteImport } from './routes/api.v1.tokens'
+import { Route as ApiV1FrameworkRouteImport } from './routes/api.v1.framework'
+import { Route as ApiV1FaqRouteImport } from './routes/api.v1.faq'
+import { Route as ApiV1TokensTokenIdRouteImport } from './routes/api.v1.tokens.$tokenId'
const FaqRoute = FaqRouteImport.update({
id: '/faq',
@@ -31,80 +32,92 @@ const TokensTokenIdRoute = TokensTokenIdRouteImport.update({
path: '/tokens/$tokenId',
getParentRoute: () => rootRouteImport,
} as any)
-const ApiTokensRoute = ApiTokensRouteImport.update({
- id: '/api/tokens',
- path: '/api/tokens',
+const ApiV1TokensRoute = ApiV1TokensRouteImport.update({
+ id: '/api/v1/tokens',
+ path: '/api/v1/tokens',
getParentRoute: () => rootRouteImport,
} as any)
-const ApiFrameworkRoute = ApiFrameworkRouteImport.update({
- id: '/api/framework',
- path: '/api/framework',
+const ApiV1FrameworkRoute = ApiV1FrameworkRouteImport.update({
+ id: '/api/v1/framework',
+ path: '/api/v1/framework',
getParentRoute: () => rootRouteImport,
} as any)
-const ApiTokensTokenIdRoute = ApiTokensTokenIdRouteImport.update({
+const ApiV1FaqRoute = ApiV1FaqRouteImport.update({
+ id: '/api/v1/faq',
+ path: '/api/v1/faq',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const ApiV1TokensTokenIdRoute = ApiV1TokensTokenIdRouteImport.update({
id: '/$tokenId',
path: '/$tokenId',
- getParentRoute: () => ApiTokensRoute,
+ getParentRoute: () => ApiV1TokensRoute,
} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
- '/api/framework': typeof ApiFrameworkRoute
- '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
- '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
+ '/api/v1/faq': typeof ApiV1FaqRoute
+ '/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
+ '/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/faq': typeof FaqRoute
- '/api/framework': typeof ApiFrameworkRoute
- '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
- '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
+ '/api/v1/faq': typeof ApiV1FaqRoute
+ '/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
+ '/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/faq': typeof FaqRoute
- '/api/framework': typeof ApiFrameworkRoute
- '/api/tokens': typeof ApiTokensRouteWithChildren
'/tokens/$tokenId': typeof TokensTokenIdRoute
- '/api/tokens/$tokenId': typeof ApiTokensTokenIdRoute
+ '/api/v1/faq': typeof ApiV1FaqRoute
+ '/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
+ '/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
| '/faq'
- | '/api/framework'
- | '/api/tokens'
| '/tokens/$tokenId'
- | '/api/tokens/$tokenId'
+ | '/api/v1/faq'
+ | '/api/v1/framework'
+ | '/api/v1/tokens'
+ | '/api/v1/tokens/$tokenId'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/faq'
- | '/api/framework'
- | '/api/tokens'
| '/tokens/$tokenId'
- | '/api/tokens/$tokenId'
+ | '/api/v1/faq'
+ | '/api/v1/framework'
+ | '/api/v1/tokens'
+ | '/api/v1/tokens/$tokenId'
id:
| '__root__'
| '/'
| '/faq'
- | '/api/framework'
- | '/api/tokens'
| '/tokens/$tokenId'
- | '/api/tokens/$tokenId'
+ | '/api/v1/faq'
+ | '/api/v1/framework'
+ | '/api/v1/tokens'
+ | '/api/v1/tokens/$tokenId'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
FaqRoute: typeof FaqRoute
- ApiFrameworkRoute: typeof ApiFrameworkRoute
- ApiTokensRoute: typeof ApiTokensRouteWithChildren
TokensTokenIdRoute: typeof TokensTokenIdRoute
+ ApiV1FaqRoute: typeof ApiV1FaqRoute
+ ApiV1FrameworkRoute: typeof ApiV1FrameworkRoute
+ ApiV1TokensRoute: typeof ApiV1TokensRouteWithChildren
}
declare module '@tanstack/react-router' {
@@ -130,48 +143,56 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof TokensTokenIdRouteImport
parentRoute: typeof rootRouteImport
}
- '/api/tokens': {
- id: '/api/tokens'
- path: '/api/tokens'
- fullPath: '/api/tokens'
- preLoaderRoute: typeof ApiTokensRouteImport
+ '/api/v1/tokens': {
+ id: '/api/v1/tokens'
+ path: '/api/v1/tokens'
+ fullPath: '/api/v1/tokens'
+ preLoaderRoute: typeof ApiV1TokensRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/api/v1/framework': {
+ id: '/api/v1/framework'
+ path: '/api/v1/framework'
+ fullPath: '/api/v1/framework'
+ preLoaderRoute: typeof ApiV1FrameworkRouteImport
parentRoute: typeof rootRouteImport
}
- '/api/framework': {
- id: '/api/framework'
- path: '/api/framework'
- fullPath: '/api/framework'
- preLoaderRoute: typeof ApiFrameworkRouteImport
+ '/api/v1/faq': {
+ id: '/api/v1/faq'
+ path: '/api/v1/faq'
+ fullPath: '/api/v1/faq'
+ preLoaderRoute: typeof ApiV1FaqRouteImport
parentRoute: typeof rootRouteImport
}
- '/api/tokens/$tokenId': {
- id: '/api/tokens/$tokenId'
+ '/api/v1/tokens/$tokenId': {
+ id: '/api/v1/tokens/$tokenId'
path: '/$tokenId'
- fullPath: '/api/tokens/$tokenId'
- preLoaderRoute: typeof ApiTokensTokenIdRouteImport
- parentRoute: typeof ApiTokensRoute
+ fullPath: '/api/v1/tokens/$tokenId'
+ preLoaderRoute: typeof ApiV1TokensTokenIdRouteImport
+ parentRoute: typeof ApiV1TokensRoute
}
}
}
-interface ApiTokensRouteChildren {
- ApiTokensTokenIdRoute: typeof ApiTokensTokenIdRoute
+interface ApiV1TokensRouteChildren {
+ ApiV1TokensTokenIdRoute: typeof ApiV1TokensTokenIdRoute
}
-const ApiTokensRouteChildren: ApiTokensRouteChildren = {
- ApiTokensTokenIdRoute: ApiTokensTokenIdRoute,
+const ApiV1TokensRouteChildren: ApiV1TokensRouteChildren = {
+ ApiV1TokensTokenIdRoute: ApiV1TokensTokenIdRoute,
}
-const ApiTokensRouteWithChildren = ApiTokensRoute._addFileChildren(
- ApiTokensRouteChildren,
+const ApiV1TokensRouteWithChildren = ApiV1TokensRoute._addFileChildren(
+ ApiV1TokensRouteChildren,
)
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
FaqRoute: FaqRoute,
- ApiFrameworkRoute: ApiFrameworkRoute,
- ApiTokensRoute: ApiTokensRouteWithChildren,
TokensTokenIdRoute: TokensTokenIdRoute,
+ ApiV1FaqRoute: ApiV1FaqRoute,
+ ApiV1FrameworkRoute: ApiV1FrameworkRoute,
+ ApiV1TokensRoute: ApiV1TokensRouteWithChildren,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
diff --git a/src/routes/api.v1.faq.ts b/src/routes/api.v1.faq.ts
new file mode 100644
index 0000000..67f7193
--- /dev/null
+++ b/src/routes/api.v1.faq.ts
@@ -0,0 +1,10 @@
+import { createFileRoute } from "@tanstack/react-router"
+import { handleGetFaq } from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/v1/faq")({
+ server: {
+ handlers: {
+ GET: () => handleGetFaq(),
+ },
+ },
+})
diff --git a/src/routes/api.framework.ts b/src/routes/api.v1.framework.ts
similarity index 76%
rename from src/routes/api.framework.ts
rename to src/routes/api.v1.framework.ts
index 08f8084..51ff72e 100644
--- a/src/routes/api.framework.ts
+++ b/src/routes/api.v1.framework.ts
@@ -1,7 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import { handleGetFramework } from "@/lib/server/token-api"
-export const Route = createFileRoute("/api/framework")({
+export const Route = createFileRoute("/api/v1/framework")({
server: {
handlers: {
GET: () => handleGetFramework(),
diff --git a/src/routes/api.tokens.$tokenId.ts b/src/routes/api.v1.tokens.$tokenId.ts
similarity index 76%
rename from src/routes/api.tokens.$tokenId.ts
rename to src/routes/api.v1.tokens.$tokenId.ts
index ca367ca..1d62a3c 100644
--- a/src/routes/api.tokens.$tokenId.ts
+++ b/src/routes/api.v1.tokens.$tokenId.ts
@@ -1,7 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import { handleGetToken } from "@/lib/server/token-api"
-export const Route = createFileRoute("/api/tokens/$tokenId")({
+export const Route = createFileRoute("/api/v1/tokens/$tokenId")({
server: {
handlers: {
GET: ({ params }) => handleGetToken(params.tokenId),
diff --git a/src/routes/api.tokens.ts b/src/routes/api.v1.tokens.ts
similarity index 77%
rename from src/routes/api.tokens.ts
rename to src/routes/api.v1.tokens.ts
index 5cf9189..70d7c67 100644
--- a/src/routes/api.tokens.ts
+++ b/src/routes/api.v1.tokens.ts
@@ -1,7 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import { handleGetTokens } from "@/lib/server/token-api"
-export const Route = createFileRoute("/api/tokens")({
+export const Route = createFileRoute("/api/v1/tokens")({
server: {
handlers: {
GET: () => handleGetTokens(),
diff --git a/tests/api-endpoints.test.ts b/tests/api-endpoints.test.ts
index c817889..64ff872 100644
--- a/tests/api-endpoints.test.ts
+++ b/tests/api-endpoints.test.ts
@@ -7,12 +7,14 @@ import { join } from "node:path"
import { describe, expect, it } from "vitest"
import {
apiErrorSchema,
+ faqSchema,
frameworkDocSchema,
indexSchema,
provenanceSchema,
tokenDocSchema,
} from "@/lib/schemas"
import {
+ handleGetFaq,
handleGetFramework,
handleGetToken,
handleGetTokens,
@@ -65,6 +67,17 @@ describe("GET /api/framework", () => {
})
})
+describe("GET /api/v1/faq", () => {
+ it("returns the faq doc with provenance, identical to generated", async () => {
+ const res = handleGetFaq()
+ expect(res.status).toBe(200)
+ const payload = await body(res)
+ expect(() => faqSchema.parse(payload.data)).not.toThrow()
+ expect(() => provenanceSchema.parse(payload.provenance)).not.toThrow()
+ expect(payload.data).toEqual(readJson(join(generated, "faq.json")))
+ })
+})
+
describe("GET /api/tokens/{id}", () => {
it("returns every published token doc identical to its generated file", async () => {
for (const id of TOKEN_IDS) {
From 12ab5303c31479e572124e01e88f2c2d4df8c41f Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 9 Jun 2026 18:54:23 +0200
Subject: [PATCH 15/38] feat: compose published data from otf-cms at build time
by ref
---
package.json | 3 +-
scripts/build-data.mjs | 101 +++++++++++++++
scripts/check-schema-drift.mjs | 49 ++++----
scripts/lib/compose-data.mjs | 198 ++++++++++++++++++++++++++++++
scripts/vendor-schemas.mjs | 56 +++++----
src/lib/schemas/.vendor-lock.json | 11 +-
src/lib/schemas/index.ts | 4 +-
7 files changed, 367 insertions(+), 55 deletions(-)
create mode 100644 scripts/build-data.mjs
create mode 100644 scripts/lib/compose-data.mjs
diff --git a/package.json b/package.json
index 8970d58..341dbd2 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
"type": "module",
"scripts": {
"dev": "vite dev --port 3000",
- "build": "vite build",
+ "build": "node scripts/build-data.mjs && vite build",
+ "build:data": "node scripts/build-data.mjs",
"preview": "vite preview",
"test": "vitest run",
"format": "biome format",
diff --git a/scripts/build-data.mjs b/scripts/build-data.mjs
new file mode 100644
index 0000000..53931a5
--- /dev/null
+++ b/scripts/build-data.mjs
@@ -0,0 +1,101 @@
+#!/usr/bin/env node
+/**
+ * Build-time data layer. Produces src/data/generated/ (the read models the
+ * app serves) from otf-cms content. Three modes, by env:
+ *
+ * (default) no env set → leave the committed src/data/generated/
+ * as-is. Hermetic builds, local dev, and the test
+ * suite all use the committed snapshot.
+ *
+ * OTF_CONTENT_LOCAL= compose from a local otf-cms checkout at
.
+ * Local development against sibling content.
+ *
+ * OTF_CONTENT_REF=[ fetch otf-cms content at ][ (a branch/sha) and
+ * (+ OTF_CONTENT_TOKEN) compose it. This is the production + preview path:
+ * prod builds from `main`, PR previews from the
+ * content branch — one mechanism, no committed data
+ * churn, no write access to this repo.
+ *
+ * Composition uses the VENDORED composer (scripts/lib/compose-data.mjs), so
+ * the app produces byte-identical output to otf-cms.
+ */
+import { execSync } from "node:child_process"
+import {
+ existsSync,
+ mkdirSync,
+ mkdtempSync,
+ readdirSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs"
+import { tmpdir } from "node:os"
+import { dirname, join } from "node:path"
+import { fileURLToPath } from "node:url"
+import { composeAll } from "./lib/compose-data.mjs"
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const generatedDir = join(root, "src", "data", "generated")
+
+const ref = process.env.OTF_CONTENT_REF
+const local = process.env.OTF_CONTENT_LOCAL
+
+if (!ref && !local) {
+ console.log(
+ "build-data: no OTF_CONTENT_REF / OTF_CONTENT_LOCAL — using committed src/data/generated/"
+ )
+ process.exit(0)
+}
+
+/** Resolve the otf-cms `content/` directory for this build. */
+function resolveContentDir() {
+ if (local) {
+ const dir = join(local, "content")
+ if (!existsSync(dir)) throw new Error(`No content/ at ${local}`)
+ console.log(`build-data: composing from local checkout ${local}`)
+ return { contentDir: dir, cleanup: () => {} }
+ }
+
+ const token = process.env.OTF_CONTENT_TOKEN
+ if (!token) throw new Error("OTF_CONTENT_REF set but OTF_CONTENT_TOKEN missing")
+ const tmp = mkdtempSync(join(tmpdir(), "otf-content-"))
+ const tarball = join(tmp, "otf-cms.tar.gz")
+ console.log(`build-data: fetching otf-cms@${ref}`)
+ // GitHub tarball API; -L follows the redirect to the asset.
+ execSync(
+ `curl -sSL -H "Authorization: Bearer ${token}" -H "User-Agent: otf-app-build" ` +
+ `-o "${tarball}" "https://api.github.com/repos/aragon/otf-cms/tarball/${ref}"`,
+ { stdio: "inherit" }
+ )
+ execSync(`tar xzf "${tarball}" -C "${tmp}"`, { stdio: "inherit" })
+ const extracted = readdirSync(tmp).find((n) => n.startsWith("aragon-otf-cms-"))
+ if (!extracted) throw new Error("tarball did not contain the expected root")
+ return {
+ contentDir: join(tmp, extracted, "content"),
+ cleanup: () => rmSync(tmp, { recursive: true, force: true }),
+ }
+}
+
+const { contentDir, cleanup } = resolveContentDir()
+try {
+ const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
+ composeAll(contentDir)
+
+ rmSync(generatedDir, { recursive: true, force: true })
+ const write = (rel, data) => {
+ const p = join(generatedDir, rel)
+ mkdirSync(dirname(p), { recursive: true })
+ writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
+ }
+ write("index.json", index)
+ write("framework.json", frameworkDoc)
+ write("faq.json", faq)
+ write("testimonials.json", testimonials)
+ write("manifest.json", manifest)
+ for (const doc of tokenDocs) write(join("tokens", `${doc.id}.json`), doc)
+
+ console.log(
+ `build-data: composed ${tokenDocs.length} token docs (snapshot ${manifest.snapshot_id})`
+ )
+} finally {
+ cleanup()
+}
diff --git a/scripts/check-schema-drift.mjs b/scripts/check-schema-drift.mjs
index db11853..f3c0398 100644
--- a/scripts/check-schema-drift.mjs
+++ b/scripts/check-schema-drift.mjs
@@ -1,46 +1,43 @@
#!/usr/bin/env node
/**
- * Vendored-schema integrity gate (CI): every file in src/lib/schemas/ must
- * match the vendor lock written by scripts/vendor-schemas.mjs. Direct edits
- * to the vendored copy fail here — change schemas in otf-cms and re-vendor.
+ * Vendored-contract integrity gate (CI): every vendored file (schemas +
+ * composer) must match the vendor lock written by scripts/vendor-schemas.mjs.
+ * Direct edits to a vendored copy fail here — change it in otf-cms and
+ * re-vendor.
*/
import { createHash } from "node:crypto"
-import { readdirSync, readFileSync } from "node:fs"
+import { readFileSync } from "node:fs"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"
-const dir = join(
- dirname(fileURLToPath(import.meta.url)),
- "..",
- "src",
- "lib",
- "schemas"
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const lock = JSON.parse(
+ readFileSync(join(root, "src/lib/schemas/.vendor-lock.json"), "utf8")
)
-const lock = JSON.parse(readFileSync(join(dir, ".vendor-lock.json"), "utf8"))
-const files = readdirSync(dir).filter((f) => f.endsWith(".ts"))
-
const drifted = []
-for (const file of files.sort()) {
- const hash = createHash("sha256")
- .update(readFileSync(join(dir, file), "utf8"))
- .digest("hex")
- if (lock.files[file] !== hash) drifted.push(file)
-}
-for (const file of Object.keys(lock.files)) {
- if (!files.includes(file)) drifted.push(`${file} (missing)`)
+for (const [rel, expected] of Object.entries(lock.files)) {
+ let hash
+ try {
+ hash = createHash("sha256")
+ .update(readFileSync(join(root, rel), "utf8"))
+ .digest("hex")
+ } catch {
+ drifted.push(`${rel} (missing)`)
+ continue
+ }
+ if (hash !== expected) drifted.push(rel)
}
if (drifted.length > 0) {
console.error(
- `Vendored schema drift detected: ${drifted.join(", ")}\n` +
- "src/lib/schemas/ is a vendored copy of otf-cms/schemas " +
- `(locked at ${lock.source_commit.slice(0, 7)}). ` +
- "Edit the schemas in aragon/otf-cms, then run: node scripts/vendor-schemas.mjs"
+ `Vendored contract drift: ${drifted.join(", ")}\n` +
+ `These are vendored from aragon/otf-cms (locked at ${lock.source_commit.slice(0, 7)}). ` +
+ "Edit them in otf-cms, then run: node scripts/vendor-schemas.mjs"
)
process.exit(1)
}
console.log(
- `vendored schemas intact (${files.length} files, source ${lock.source}@${lock.source_commit.slice(0, 7)})`
+ `vendored contract intact (${Object.keys(lock.files).length} files, ${lock.source}@${lock.source_commit.slice(0, 7)})`
)
diff --git a/scripts/lib/compose-data.mjs b/scripts/lib/compose-data.mjs
new file mode 100644
index 0000000..21ba32c
--- /dev/null
+++ b/scripts/lib/compose-data.mjs
@@ -0,0 +1,198 @@
+#!/usr/bin/env node
+/**
+ * Composer: content/ atoms → src/data/generated/ read models.
+ *
+ * Joins research-shaped atoms (registry, framework, evaluations) into
+ * consumer-shaped docs by id:
+ * - criterion name/about come from framework (atom `name` overrides)
+ * - metric display name + about come from framework
+ * - scores and status counts are computed here (compose time), not at render
+ *
+ * Replaces the runtime framework-merge formerly in src/lib/metrics-data.ts.
+ * The scoring logic mirrors the pure functions in src/lib/scoring.ts and is
+ * pinned to them by the golden round-trip tests.
+ *
+ * Exports composeAll() for tests; run directly to write src/data/generated/.
+ */
+import { createHash } from "node:crypto"
+import {
+ mkdirSync,
+ readdirSync,
+ readFileSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs"
+import { dirname, join } from "node:path"
+import { fileURLToPath } from "node:url"
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..")
+const contentDir = join(root, "content")
+const generatedDir = join(root, "generated")
+
+const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
+
+const SCORED_STATUSES = new Set(["positive", "warning", "at_risk"])
+
+function getMetricScore(metric) {
+ const reference = metric.tags?.includes("Reference") ?? false
+ const evaluatedCriteria = metric.criteria.filter((c) =>
+ SCORED_STATUSES.has(c.status)
+ )
+ const total = evaluatedCriteria.length
+ const passing = evaluatedCriteria.filter(
+ (c) => c.status === "positive"
+ ).length
+ const evaluated = reference ? false : total > 0
+ const percentage = total > 0 ? (passing / total) * 100 : 0
+
+ return {
+ metricId: metric.id,
+ metricName: metric.name,
+ passing,
+ total,
+ percentage,
+ evaluated,
+ reference,
+ }
+}
+
+function getTokenScore(tokenId, metrics) {
+ const metricScores = metrics.map(getMetricScore)
+ const scoredMetrics = metricScores.filter((m) => m.evaluated && !m.reference)
+ const passing = scoredMetrics.reduce((sum, m) => sum + m.passing, 0)
+ const total = scoredMetrics.reduce((sum, m) => sum + m.total, 0)
+ const percentage = total > 0 ? (passing / total) * 100 : 0
+
+ return { tokenId, passing, total, percentage, metrics: metricScores }
+}
+
+export function composeAll(dir = contentDir) {
+ const meta = readJson(join(dir, "framework-meta.json"))
+ const framework = meta.order.map((id) =>
+ readJson(join(dir, "framework", `${id}.json`))
+ )
+ const criterionDefs = new Map(
+ framework.flatMap((m) => m.criteria.map((c) => [c.id, c]))
+ )
+
+ const tokenIds = readdirSync(join(dir, "tokens"))
+ .filter((f) => f.endsWith(".json"))
+ .map((f) => f.replace(/\.json$/, ""))
+ .sort()
+
+ const tokenAtoms = new Map(
+ tokenIds.map((id) => [id, readJson(join(dir, "tokens", `${id}.json`))])
+ )
+
+ const tokenDocs = []
+ for (const tokenId of tokenIds) {
+ const metrics = []
+ for (const fm of framework) {
+ const metricDir = join(dir, "evaluations", tokenId, fm.id)
+ const editorial = readJson(
+ join(dir, "summaries", tokenId, `${fm.id}.json`)
+ )
+ const criteria = fm.criteria.map((fc) => {
+ const atom = readJson(join(metricDir, `${fc.id}.json`))
+ const composed = {
+ id: fc.id,
+ name: atom.name ?? fc.name,
+ about: fc.about,
+ status: atom.status,
+ notes: atom.notes,
+ }
+ if ("tags" in atom) composed.tags = atom.tags
+ if ("evidence" in atom) composed.evidence = atom.evidence
+ return composed
+ })
+ metrics.push({
+ id: fm.id,
+ name: fm.displayName,
+ about: fm.about,
+ summary: editorial.summary,
+ tags: editorial.tags,
+ criteria,
+ })
+ }
+
+ const allCriteria = metrics.flatMap((m) => m.criteria)
+ const countBy = (status) =>
+ allCriteria.filter((c) => c.status === status).length
+ const score = getTokenScore(tokenId, metrics)
+
+ tokenDocs.push({
+ ...tokenAtoms.get(tokenId),
+ positive: countBy("positive"),
+ neutral: countBy("warning"),
+ atRisk: countBy("at_risk"),
+ evidenceEntries: allCriteria.flatMap((c) => c.evidence ?? []).length,
+ score,
+ criteriaStatuses: Object.fromEntries(
+ allCriteria.map((c) => [c.id, c.status])
+ ),
+ metrics,
+ })
+ }
+
+ // Index rows are the dashboard read model: full score (the score hover
+ // shows the per-metric breakdown) and a flat criterion-status map (the
+ // table renders single-criterion columns across all tokens) — so the
+ // dashboard needs exactly one fetch and never loads per-token docs.
+ const index = {
+ tokens: tokenDocs.map(({ metrics: _metrics, ...row }) => row),
+ }
+
+ const frameworkDoc = { baseUrl: meta.baseUrl, metrics: framework }
+ const faq = readJson(join(dir, "faq.json"))
+ const testimonials = readJson(join(dir, "testimonials.json"))
+
+ // Deterministic snapshot identity: a content hash over the composed output.
+ // Stable across recompositions of identical content (keeps the freshness
+ // gate meaningful); changes exactly when published data changes. The future
+ // publish pipeline reuses this as the R2 snapshot key component.
+ const snapshotId = createHash("sha256")
+ .update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
+ .digest("hex")
+ .slice(0, 16)
+ const manifest = {
+ snapshot_id: snapshotId,
+ tokens: tokenDocs.map((d) => d.id),
+ }
+
+ return {
+ index,
+ tokenDocs,
+ frameworkDoc,
+ faq,
+ testimonials,
+ manifest,
+ }
+}
+
+function main() {
+ const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
+ composeAll()
+
+ rmSync(generatedDir, { recursive: true, force: true })
+ const writeJson = (p, data) => {
+ mkdirSync(dirname(p), { recursive: true })
+ writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
+ }
+
+ writeJson(join(generatedDir, "index.json"), index)
+ for (const doc of tokenDocs) {
+ writeJson(join(generatedDir, "tokens", `${doc.id}.json`), doc)
+ }
+ writeJson(join(generatedDir, "framework.json"), frameworkDoc)
+ writeJson(join(generatedDir, "faq.json"), faq)
+ writeJson(join(generatedDir, "testimonials.json"), testimonials)
+ writeJson(join(generatedDir, "manifest.json"), manifest)
+
+ console.log(
+ `composed: index (${index.tokens.length} rows), ${tokenDocs.length} token docs, framework, faq, testimonials (snapshot ${manifest.snapshot_id})`
+ )
+}
+
+if (process.argv[1] === fileURLToPath(import.meta.url)) {
+ main()
+}
diff --git a/scripts/vendor-schemas.mjs b/scripts/vendor-schemas.mjs
index db89e49..9472220 100644
--- a/scripts/vendor-schemas.mjs
+++ b/scripts/vendor-schemas.mjs
@@ -1,31 +1,34 @@
#!/usr/bin/env node
/**
- * Re-vendor the schema contract from otf-cms (the source of truth).
+ * Re-vendor the data contract + composer from otf-cms (the source of truth).
*
* Usage: node scripts/vendor-schemas.mjs [path-to-otf-cms-checkout]
* (default: ../otf-cms sibling checkout)
*
- * Copies otf-cms/schemas/*.ts into src/lib/schemas/, injects the VENDORED
- * banner into index.ts, and records a vendor lock (source commit + per-file
- * hashes). CI verifies the lock — direct edits to the vendored copy fail CI;
- * this script is the only sanctioned way to change these files.
+ * Vendors:
+ * otf-cms/schemas/*.ts → src/lib/schemas/ (the Zod contract)
+ * otf-cms/scripts/compose-data.mjs → scripts/lib/compose-data.mjs
+ * (the composer — the app composes otf-cms content at build time, so it
+ * must run the exact same composition logic)
+ *
+ * Records a vendor lock (source commit + per-file hashes). CI verifies it —
+ * direct edits to the vendored copies fail; this script is the only
+ * sanctioned way to change them.
*/
import { execSync } from "node:child_process"
import { createHash } from "node:crypto"
-import { readdirSync, readFileSync, writeFileSync } from "node:fs"
+import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"
import { dirname, join, resolve } from "node:path"
import { fileURLToPath } from "node:url"
const root = join(dirname(fileURLToPath(import.meta.url)), "..")
const sourceRepo = resolve(root, process.argv[2] ?? "../otf-cms")
-const sourceDir = join(sourceRepo, "schemas")
-const targetDir = join(root, "src", "lib", "schemas")
const BANNER = (commit) => `/**
* OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
- * Source of truth: https://github.com/aragon/otf-cms (schemas/), vendored
- * at commit ${commit}. Change upstream, then re-vendor:
+ * Source of truth: https://github.com/aragon/otf-cms, vendored at commit
+ * ${commit}. Change upstream, then re-vendor:
* node scripts/vendor-schemas.mjs
* CI fails on direct edits (scripts/check-schema-drift.mjs).
*/`
@@ -35,24 +38,35 @@ const sourceCommit = execSync("git rev-parse HEAD", {
encoding: "utf8",
}).trim()
-const files = readdirSync(sourceDir).filter((f) => f.endsWith(".ts"))
const lock = { source: "aragon/otf-cms", source_commit: sourceCommit, files: {} }
-for (const file of files.sort()) {
- let content = readFileSync(join(sourceDir, file), "utf8")
- if (file === "index.ts") {
- // Replace the upstream header comment with the vendored banner
- content = content.replace(/^\/\*\*[\s\S]*?\*\//, BANNER(sourceCommit))
- }
- writeFileSync(join(targetDir, file), content)
- lock.files[file] = createHash("sha256").update(content).digest("hex")
+/** Copy a source file to a repo-root-relative target; record its hash. */
+function vendor(srcAbs, targetRel, { banner = false } = {}) {
+ let content = readFileSync(srcAbs, "utf8")
+ if (banner) content = content.replace(/^\/\*\*[\s\S]*?\*\//, BANNER(sourceCommit))
+ const targetAbs = join(root, targetRel)
+ mkdirSync(dirname(targetAbs), { recursive: true })
+ writeFileSync(targetAbs, content)
+ lock.files[targetRel] = createHash("sha256").update(content).digest("hex")
+}
+
+// Schemas
+const schemaDir = join(sourceRepo, "schemas")
+for (const f of readdirSync(schemaDir).filter((f) => f.endsWith(".ts")).sort()) {
+ vendor(join(schemaDir, f), join("src/lib/schemas", f), { banner: f === "index.ts" })
}
+// Composer
+vendor(
+ join(sourceRepo, "scripts", "compose-data.mjs"),
+ "scripts/lib/compose-data.mjs"
+)
+
writeFileSync(
- join(targetDir, ".vendor-lock.json"),
+ join(root, "src/lib/schemas/.vendor-lock.json"),
`${JSON.stringify(lock, null, 2)}\n`
)
console.log(
- `vendored ${files.length} schema files from otf-cms@${sourceCommit.slice(0, 7)}`
+ `vendored ${Object.keys(lock.files).length} files from otf-cms@${sourceCommit.slice(0, 7)}`
)
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index a213022..7d75fce 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -1,10 +1,11 @@
{
"source": "aragon/otf-cms",
- "source_commit": "2d37cee43562769d1bba4835a3e9c14142ac982d",
+ "source_commit": "12f289be4b42f485634f1047ccbc6b4752bf1d55",
"files": {
- "atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
- "common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "index.ts": "bc4ffe76c1b3029c2f4ec77d494273ae0ff49192377ea0972afc4dbe8a7f5110",
- "read-models.ts": "ce8518850d56e6146593694f8185b90ecc6beaaded9e1b4d5e69bd93d250fbf2"
+ "src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
+ "src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
+ "src/lib/schemas/index.ts": "41d23b4cf7319386a62138a36f899a87fd2632995dcf811138c25258c5aeefee",
+ "src/lib/schemas/read-models.ts": "ce8518850d56e6146593694f8185b90ecc6beaaded9e1b4d5e69bd93d250fbf2",
+ "scripts/lib/compose-data.mjs": "ada9e8803a6dd3ae4b8dd49357d991770643c300787e6016e430b3eb386bec25"
}
}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index 7f69889..c0ea314 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -1,8 +1,8 @@
/**
* OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
- * Source of truth: https://github.com/aragon/otf-cms (schemas/), vendored
- * at commit 2d37cee43562769d1bba4835a3e9c14142ac982d. Change upstream, then re-vendor:
+ * Source of truth: https://github.com/aragon/otf-cms, vendored at commit
+ * 12f289be4b42f485634f1047ccbc6b4752bf1d55. Change upstream, then re-vendor:
* node scripts/vendor-schemas.mjs
* CI fails on direct edits (scripts/check-schema-drift.mjs).
*/
From 38048bb0be973f887f6fc6a44e9f62b072d0a358 Mon Sep 17 00:00:00 2001
From: Kevin Davis ]
Date: Tue, 9 Jun 2026 19:18:14 +0200
Subject: [PATCH 16/38] fix: remove shell from build-data fetch to close
command-injection finding
---
scripts/build-data.mjs | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/scripts/build-data.mjs b/scripts/build-data.mjs
index 53931a5..6fb33d3 100644
--- a/scripts/build-data.mjs
+++ b/scripts/build-data.mjs
@@ -19,7 +19,7 @@
* Composition uses the VENDORED composer (scripts/lib/compose-data.mjs), so
* the app produces byte-identical output to otf-cms.
*/
-import { execSync } from "node:child_process"
+import { execFileSync } from "node:child_process"
import {
existsSync,
mkdirSync,
@@ -28,6 +28,7 @@ import {
rmSync,
writeFileSync,
} from "node:fs"
+import { Buffer } from "node:buffer"
import { tmpdir } from "node:os"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"
@@ -47,7 +48,7 @@ if (!ref && !local) {
}
/** Resolve the otf-cms `content/` directory for this build. */
-function resolveContentDir() {
+async function resolveContentDir() {
if (local) {
const dir = join(local, "content")
if (!existsSync(dir)) throw new Error(`No content/ at ${local}`)
@@ -60,13 +61,27 @@ function resolveContentDir() {
const tmp = mkdtempSync(join(tmpdir(), "otf-content-"))
const tarball = join(tmp, "otf-cms.tar.gz")
console.log(`build-data: fetching otf-cms@${ref}`)
- // GitHub tarball API; -L follows the redirect to the asset.
- execSync(
- `curl -sSL -H "Authorization: Bearer ${token}" -H "User-Agent: otf-app-build" ` +
- `-o "${tarball}" "https://api.github.com/repos/aragon/otf-cms/tarball/${ref}"`,
- { stdio: "inherit" }
+
+ // Native fetch — no shell. The token rides an Authorization header (never a
+ // command line), and the ref is URL-encoded into the path. GitHub's tarball
+ // API 302-redirects to a pre-signed codeload URL; fetch follows it.
+ const res = await fetch(
+ `https://api.github.com/repos/aragon/otf-cms/tarball/${encodeURIComponent(ref)}`,
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "User-Agent": "otf-app-build",
+ Accept: "application/vnd.github+json",
+ },
+ }
)
- execSync(`tar xzf "${tarball}" -C "${tmp}"`, { stdio: "inherit" })
+ if (!res.ok) {
+ throw new Error(`fetch otf-cms@${ref} failed: ${res.status} ${res.statusText}`)
+ }
+ writeFileSync(tarball, Buffer.from(await res.arrayBuffer()))
+
+ // execFileSync with an args array — no shell, so no metacharacter injection.
+ execFileSync("tar", ["xzf", tarball, "-C", tmp], { stdio: "inherit" })
const extracted = readdirSync(tmp).find((n) => n.startsWith("aragon-otf-cms-"))
if (!extracted) throw new Error("tarball did not contain the expected root")
return {
@@ -75,7 +90,7 @@ function resolveContentDir() {
}
}
-const { contentDir, cleanup } = resolveContentDir()
+const { contentDir, cleanup } = await resolveContentDir()
try {
const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
composeAll(contentDir)
From 92c757ae547074f30503be3112fd8eef2d166d4e Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Wed, 10 Jun 2026 14:30:58 +0200
Subject: [PATCH 17/38] docs: clarify count/status mapping and add response
example to agent surface
---
public/agent-guide.md | 42 ++++++++++++++++++++++++++++++++++++++++--
public/llms.txt | 17 ++++++++++-------
2 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/public/agent-guide.md b/public/agent-guide.md
index 333bcca..4c3cd72 100644
--- a/public/agent-guide.md
+++ b/public/agent-guide.md
@@ -38,13 +38,51 @@ Criterion ids encode their place in the rubric: `onchain-ctrl__governance-workfl
A token's `score` counts only evaluated, non-reference criteria.
+The per-token count fields predate this vocabulary and don't match it
+one-to-one: `positive` = positive, **`neutral` = warning**, **`atRisk` =
+at_risk**. `evidenceEntries` is the total number of evidence items across all
+criteria. Trust `criteriaStatuses` / `criteria[].status` for the canonical
+labels; treat the counts as pre-rolled tallies.
+
## Provenance and reproducibility
Every response is `{ data, provenance }`. `provenance.snapshot_id` is a
deterministic content hash of the entire published data set — cite it to pin
exactly what you read. `provenance.commit_ref` ties it to a deployment.
-`published_at` may be null in the current serving mode; use `snapshot_id` /
-`commit_ref` as the version of record.
+`published_at` may be null in the current serving mode (`provenance.source`
+tells you that mode, e.g. `generated`); use `snapshot_id` / `commit_ref` as the
+version of record.
+
+## Shape of a response
+
+Every endpoint returns `{ data, provenance }`. The index nests its rows under
+`data.tokens`; a token doc is `data` directly. Trimmed:
+
+```jsonc
+// GET /api/v1/tokens/ldo
+{
+ "data": {
+ "id": "ldo", "name": "Lido DAO", "symbol": "LDO",
+ "score": { "passing": 12, "total": 12, "percentage": 100 },
+ "positive": 15, "neutral": 0, "atRisk": 0, "evidenceEntries": 26,
+ "criteriaStatuses": { "onchain-ctrl__governance-workflow": "positive" },
+ "metrics": [{
+ "id": "onchain-ctrl", "name": "Onchain Control",
+ "criteria": [{
+ "id": "onchain-ctrl__governance-workflow",
+ "name": "Governance workflow", "status": "positive",
+ "notes": "…",
+ "evidence": [{ "name": "…", "summary": "…",
+ "urls": [{ "name": "Forum", "url": "https://…", "type": "vote" }] }]
+ }]
+ }]
+ },
+ "provenance": {
+ "snapshot_id": "…", "commit_ref": "…",
+ "published_at": null, "source": "generated"
+ }
+}
+```
## How to use it well
diff --git a/public/llms.txt b/public/llms.txt
index ec75c65..bb29093 100644
--- a/public/llms.txt
+++ b/public/llms.txt
@@ -1,14 +1,16 @@
# Ownership Token Framework
-Structured, evidence-backed analysis of crypto token ownership and governance,
-by Aragon. Machine-readable, schema-validated, versioned.
+> Structured, evidence-backed analysis of how genuinely tokenholder-owned crypto
+> protocols are, by Aragon. Machine-readable, schema-validated, versioned. Every
+> token is scored against one fixed rubric; every verdict is backed by linked
+> evidence.
## API (JSON, no auth)
-- /api/v1/tokens — index of all analyzed tokens (scores, status counts, per-criterion status map)
-- /api/v1/tokens/{id} — full analysis for one token (metrics, criteria, notes, evidence); {id} is lowercase, e.g. ldo
-- /api/v1/framework — the evaluation framework: metric and criterion definitions
-- /api/v1/faq — framework and methodology Q&A
+- `/api/v1/tokens` — index of all analyzed tokens (scores, status counts, per-criterion status map)
+- `/api/v1/tokens/{id}` — full analysis for one token (metrics, criteria, notes, evidence); {id} is lowercase, e.g. ldo
+- `/api/v1/framework` — the evaluation framework: metric and criterion definitions
+- `/api/v1/faq` — framework and methodology Q&A
## How to read it
@@ -16,7 +18,8 @@ by Aragon. Machine-readable, schema-validated, versioned.
(a content hash of the whole data set) and commit_ref — cite these for
reproducibility; do not infer freshness from cache headers.
- Criterion status is exactly one of: positive | warning | at_risk |
- unevaluated | reference. There is no other vocabulary.
+ unevaluated | reference. There is no other vocabulary. (Index count fields
+ use older names: `neutral` = warning, `atRisk` = at_risk.)
- A token's analysis is the framework (shared rubric) filled in with that
token's evaluations; criterion ids are composite, e.g.
onchain-ctrl__governance-workflow.
From 672bb0709135a1b600b0db1300f3ccb2f0897e71 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Wed, 10 Jun 2026 14:31:06 +0200
Subject: [PATCH 18/38] feat: cache and harden /api/v1 endpoints against
request floods
---
src/lib/server/token-api.ts | 64 ++++++++++++++++++++++++++--
src/routes/api.v1.faq.ts | 11 ++++-
src/routes/api.v1.framework.ts | 11 ++++-
src/routes/api.v1.tokens.$tokenId.ts | 11 ++++-
src/routes/api.v1.tokens.ts | 11 ++++-
vercel.json | 22 ++++++++++
6 files changed, 122 insertions(+), 8 deletions(-)
create mode 100644 vercel.json
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index 566e027..ca8efb2 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -19,17 +19,72 @@ import {
getPublishedTokenDoc,
} from "@/lib/server/published-data"
-function jsonResponse(body: unknown, status = 200): Response {
+// The published data is immutable for the life of a deploy (composed at build
+// time and content-hashed). Hosts purge their edge cache on each new deploy, so
+// we cache hard: after the first hit per edge node the CDN serves every
+// subsequent request and the function is never invoked. A request flood is
+// absorbed by the CDN, not paid for at the origin — this is the primary DoS
+// posture for a read-only API (see .tempor/docs/operations/api-hardening.md).
+const CACHE_OK =
+ "public, max-age=300, s-maxage=86400, stale-while-revalidate=604800"
+// Misses (unknown ids) are cached briefly so a repeated bogus id can't hammer
+// the function; short because an id can become valid on the next deploy.
+const CACHE_MISS = "public, max-age=30, s-maxage=60"
+
+function jsonResponse(
+ body: unknown,
+ status = 200,
+ cacheControl = CACHE_OK
+): Response {
return new Response(JSON.stringify(body), {
status,
headers: {
"Content-Type": "application/json",
- // Canonical published data: cacheable, must revalidate on new deploys.
- "Cache-Control": "public, max-age=60, stale-while-revalidate=300",
+ "Cache-Control": cacheControl,
+ // Public, read-only data with no credentials — a wildcard origin is safe
+ // and keeps CORS from being a footgun for consumers.
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
+ // Never let a client sniff the response into another content type.
+ "X-Content-Type-Options": "nosniff",
+ },
+ })
+}
+
+/** Cheap CORS preflight / method probe — no body, cacheable. */
+export function handleOptions(): Response {
+ return new Response(null, {
+ status: 204,
+ headers: {
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
+ "Access-Control-Max-Age": "86400",
+ "Cache-Control": CACHE_OK,
},
})
}
+/**
+ * Reject non-GET methods with a cheap 405 instead of letting them fall through
+ * to the SSR shell — an uncacheable HTML render is a far more expensive (and
+ * cache-bypassing) thing to serve a flood than a one-line 405.
+ */
+export function handleMethodNotAllowed(): Response {
+ return new Response(
+ JSON.stringify({
+ error: { code: "METHOD_NOT_ALLOWED", message: "Only GET is supported." },
+ }),
+ {
+ status: 405,
+ headers: {
+ "Content-Type": "application/json",
+ Allow: "GET, OPTIONS",
+ "Cache-Control": CACHE_MISS,
+ },
+ }
+ )
+}
+
/** GET /api/v1/tokens — the published index (discovery + cross-token queries). */
export function handleGetTokens(): Response {
return jsonResponse({
@@ -65,7 +120,8 @@ export function handleGetToken(tokenId: string): Response {
message: `No published token with id "${tokenId.trim().toLowerCase()}"`,
},
},
- 404
+ 404,
+ CACHE_MISS
)
}
return jsonResponse({ data: doc, provenance: getProvenance() })
diff --git a/src/routes/api.v1.faq.ts b/src/routes/api.v1.faq.ts
index 67f7193..6664e86 100644
--- a/src/routes/api.v1.faq.ts
+++ b/src/routes/api.v1.faq.ts
@@ -1,10 +1,19 @@
import { createFileRoute } from "@tanstack/react-router"
-import { handleGetFaq } from "@/lib/server/token-api"
+import {
+ handleGetFaq,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
export const Route = createFileRoute("/api/v1/faq")({
server: {
handlers: {
GET: () => handleGetFaq(),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
},
},
})
diff --git a/src/routes/api.v1.framework.ts b/src/routes/api.v1.framework.ts
index 51ff72e..01ac833 100644
--- a/src/routes/api.v1.framework.ts
+++ b/src/routes/api.v1.framework.ts
@@ -1,10 +1,19 @@
import { createFileRoute } from "@tanstack/react-router"
-import { handleGetFramework } from "@/lib/server/token-api"
+import {
+ handleGetFramework,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
export const Route = createFileRoute("/api/v1/framework")({
server: {
handlers: {
GET: () => handleGetFramework(),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
},
},
})
diff --git a/src/routes/api.v1.tokens.$tokenId.ts b/src/routes/api.v1.tokens.$tokenId.ts
index 1d62a3c..24e6202 100644
--- a/src/routes/api.v1.tokens.$tokenId.ts
+++ b/src/routes/api.v1.tokens.$tokenId.ts
@@ -1,10 +1,19 @@
import { createFileRoute } from "@tanstack/react-router"
-import { handleGetToken } from "@/lib/server/token-api"
+import {
+ handleGetToken,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
export const Route = createFileRoute("/api/v1/tokens/$tokenId")({
server: {
handlers: {
GET: ({ params }) => handleGetToken(params.tokenId),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
},
},
})
diff --git a/src/routes/api.v1.tokens.ts b/src/routes/api.v1.tokens.ts
index 70d7c67..7746b11 100644
--- a/src/routes/api.v1.tokens.ts
+++ b/src/routes/api.v1.tokens.ts
@@ -1,10 +1,19 @@
import { createFileRoute } from "@tanstack/react-router"
-import { handleGetTokens } from "@/lib/server/token-api"
+import {
+ handleGetTokens,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
export const Route = createFileRoute("/api/v1/tokens")({
server: {
handlers: {
GET: () => handleGetTokens(),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
},
},
})
diff --git a/vercel.json b/vercel.json
new file mode 100644
index 0000000..49ab7a6
--- /dev/null
+++ b/vercel.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://openapi.vercel.sh/vercel.json",
+ "headers": [
+ {
+ "source": "/(.*)",
+ "headers": [
+ { "key": "X-Content-Type-Options", "value": "nosniff" },
+ { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
+ { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
+ ]
+ },
+ {
+ "source": "/(llms.txt|agent-guide.md)",
+ "headers": [
+ {
+ "key": "Cache-Control",
+ "value": "public, max-age=300, s-maxage=86400, stale-while-revalidate=604800"
+ }
+ ]
+ }
+ ]
+}
From 81e7332a5b7d25954ccc800d5a1c365704bb2c2a Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Wed, 10 Jun 2026 14:38:51 +0200
Subject: [PATCH 19/38] chore: add lefthook pre-commit/pre-push rails mirroring
CI
---
lefthook.yml | 28 +++++++++++++
package.json | 4 +-
pnpm-lock.yaml | 100 ++++++++++++++++++++++++++++++++++++++++++++
pnpm-workspace.yaml | 1 +
4 files changed, 132 insertions(+), 1 deletion(-)
create mode 100644 lefthook.yml
diff --git a/lefthook.yml b/lefthook.yml
new file mode 100644
index 0000000..4262f0a
--- /dev/null
+++ b/lefthook.yml
@@ -0,0 +1,28 @@
+# Local rails — same gates as CI (.github/workflows/ci.yml), run on your
+# machine so a red build is caught before it leaves it.
+#
+# pre-commit fast: format/lint only the staged files, auto-fix and re-stage
+# pre-push full: the exact checks CI runs (build stays CI-only — too heavy
+# for every push)
+#
+# Skip in a pinch with `git commit --no-verify` / `git push --no-verify`.
+
+pre-commit:
+ parallel: true
+ commands:
+ biome:
+ glob: "*.{ts,tsx,js,jsx,json,jsonc,css}"
+ run: pnpm exec biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files}
+ stage_fixed: true
+
+pre-push:
+ parallel: true
+ commands:
+ schema-drift:
+ run: node scripts/check-schema-drift.mjs
+ biome:
+ run: pnpm exec biome check src tests
+ type-check:
+ run: pnpm type-check
+ test:
+ run: pnpm test
diff --git a/package.json b/package.json
index 341dbd2..e82a83a 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,8 @@
"lint": "biome lint",
"check": "biome check --write",
"type-check": "tsc --noEmit",
- "og:generate": "node scripts/generate-og-screenshots.mjs"
+ "og:generate": "node scripts/generate-og-screenshots.mjs",
+ "prepare": "lefthook install"
},
"dependencies": {
"@base-ui/react": "^1.2.0",
@@ -62,6 +63,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.4",
"jsdom": "^27.4.0",
+ "lefthook": "2.1.9",
"playwright": "^1.58.2",
"shadcn": "^3.8.5",
"sharp": "^0.34.5",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 69cd2e0..a25fa4a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -144,6 +144,9 @@ importers:
jsdom:
specifier: ^27.4.0
version: 27.4.0(@noble/hashes@1.8.0)
+ lefthook:
+ specifier: 2.1.9
+ version: 2.1.9
playwright:
specifier: ^1.58.2
version: 1.58.2
@@ -3022,6 +3025,60 @@ packages:
launch-editor@2.13.0:
resolution: {integrity: sha512-u+9asUHMJ99lA15VRMXw5XKfySFR9dGXwgsgS14YTbUq3GITP58mIM32At90P5fZ+MUId5Yw+IwI/yKub7jnCQ==}
+ lefthook-darwin-arm64@2.1.9:
+ resolution: {integrity: sha512-119HryNcvr4nqn0wUIrNPgpMEPn9yMQzEcW/lezRsnb56PCJriJB92+MCySPVcWDxJnZef7o0T3jdnPNiSH7Qg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ lefthook-darwin-x64@2.1.9:
+ resolution: {integrity: sha512-dwo5Tke2XcQCM56DGHgFKBfRbJIL6xs2wZ0zG1TUVZgl4t4mQUt6LiZ4V/ZQfYHTZF9qywvXoIlR5N35qOaiVQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ lefthook-freebsd-arm64@2.1.9:
+ resolution: {integrity: sha512-+09PVap6nl6xsaHch5JLtq7WvIR++U1Q2MzA2ai0M4uB/VP3AqrvKqHw6+9hjyKnIH+HHL83uqi77EAY+LaxLA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ lefthook-freebsd-x64@2.1.9:
+ resolution: {integrity: sha512-8XresjKIYpkE9ARgCtBEZgJZxAU3T4MIqzj4zNy15XRT59I1Us+QdqXTNm+pkZ41Yd2X/nxs2Pkvbq3NWWlIGw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ lefthook-linux-arm64@2.1.9:
+ resolution: {integrity: sha512-1oNIQfwrPe6rgU2KcDM3aF6+hpZDCKx1TmawQKpXUY5gVsbZ7MqX0Sk/1lnnWxqPm+kQQ5f6J2dpFWd+4xH8jg==}
+ cpu: [arm64]
+ os: [linux]
+
+ lefthook-linux-x64@2.1.9:
+ resolution: {integrity: sha512-fT+7Q+BJyGp+CslFQkNXmdFRgyVXsPHPi9NAsDX0a6QOyNnoORByAsvx6zeAKuF5rL3BBgNfho1/v2RuGxGy9w==}
+ cpu: [x64]
+ os: [linux]
+
+ lefthook-openbsd-arm64@2.1.9:
+ resolution: {integrity: sha512-4bVuafBk3dddVNo0+3hMbjcJs4mqYAstxpPMmX2ufkudSTYFNIhWoqwuGVQV/SS/xdcOKJAldW4qayAzed2ysw==}
+ cpu: [arm64]
+ os: [openbsd]
+
+ lefthook-openbsd-x64@2.1.9:
+ resolution: {integrity: sha512-PmPoMmLP/wQQWcQ9u2YH86bTZ3UCfBsxuEmVTEyPU2U8R1qSTp5r/Gs3G8cN5Mxo91XB9oBERtF1n+xD3W6aVA==}
+ cpu: [x64]
+ os: [openbsd]
+
+ lefthook-windows-arm64@2.1.9:
+ resolution: {integrity: sha512-KphfkBKmwBnmolyrdhIl3lrBaOyTcCgXBT2AB/9OHnEXhOLvv5uTCUkrD4YRAxXPtFKq6UvnapIeoL3GZq0bdA==}
+ cpu: [arm64]
+ os: [win32]
+
+ lefthook-windows-x64@2.1.9:
+ resolution: {integrity: sha512-2qlUtkJHZ3MyUxgV5XTEmcrIoNZA07iwaquoswAcqv/1MeBFXlD+O+koFRfrzWng2O5WYEbpJnd8tvaYnV8fTA==}
+ cpu: [x64]
+ os: [win32]
+
+ lefthook@2.1.9:
+ resolution: {integrity: sha512-bwDaIOViTktE8kJLf9jP0p+H2/RDTlFFlc43Am2YgUsX22hI6Sq4RbzsrecwzY5y+MHTipOH7WsmWSEniePHWQ==}
+ hasBin: true
+
lightningcss-android-arm64@1.31.1:
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
engines: {node: '>= 12.0.0'}
@@ -7016,6 +7073,49 @@ snapshots:
picocolors: 1.1.1
shell-quote: 1.8.3
+ lefthook-darwin-arm64@2.1.9:
+ optional: true
+
+ lefthook-darwin-x64@2.1.9:
+ optional: true
+
+ lefthook-freebsd-arm64@2.1.9:
+ optional: true
+
+ lefthook-freebsd-x64@2.1.9:
+ optional: true
+
+ lefthook-linux-arm64@2.1.9:
+ optional: true
+
+ lefthook-linux-x64@2.1.9:
+ optional: true
+
+ lefthook-openbsd-arm64@2.1.9:
+ optional: true
+
+ lefthook-openbsd-x64@2.1.9:
+ optional: true
+
+ lefthook-windows-arm64@2.1.9:
+ optional: true
+
+ lefthook-windows-x64@2.1.9:
+ optional: true
+
+ lefthook@2.1.9:
+ optionalDependencies:
+ lefthook-darwin-arm64: 2.1.9
+ lefthook-darwin-x64: 2.1.9
+ lefthook-freebsd-arm64: 2.1.9
+ lefthook-freebsd-x64: 2.1.9
+ lefthook-linux-arm64: 2.1.9
+ lefthook-linux-x64: 2.1.9
+ lefthook-openbsd-arm64: 2.1.9
+ lefthook-openbsd-x64: 2.1.9
+ lefthook-windows-arm64: 2.1.9
+ lefthook-windows-x64: 2.1.9
+
lightningcss-android-arm64@1.31.1:
optional: true
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index caa16aa..df0d9cc 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,3 +1,4 @@
onlyBuiltDependencies:
- esbuild
+ - lefthook
- msw
From e734f0de3aeb9da67c5b6ae0c506f53b61c20b3b Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 19:44:36 +0200
Subject: [PATCH 20/38] feat: carry last_updated freshness through the API
provenance envelope
---
public/agent-guide.md | 8 +++++---
public/llms.txt | 3 ++-
scripts/lib/compose-data.mjs | 10 ++++++++++
src/data/generated/manifest.json | 1 +
src/lib/schemas/.vendor-lock.json | 8 ++++----
src/lib/schemas/index.ts | 2 +-
src/lib/schemas/read-models.ts | 7 ++++++-
src/lib/server/published-data.ts | 5 ++++-
8 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/public/agent-guide.md b/public/agent-guide.md
index 4c3cd72..bc133bd 100644
--- a/public/agent-guide.md
+++ b/public/agent-guide.md
@@ -49,9 +49,10 @@ labels; treat the counts as pre-rolled tallies.
Every response is `{ data, provenance }`. `provenance.snapshot_id` is a
deterministic content hash of the entire published data set — cite it to pin
exactly what you read. `provenance.commit_ref` ties it to a deployment.
-`published_at` may be null in the current serving mode (`provenance.source`
-tells you that mode, e.g. `generated`); use `snapshot_id` / `commit_ref` as the
-version of record.
+`provenance.last_updated` is when the content was last edited (ISO), distinct
+from `published_at` — when this snapshot was published, which may be null in the
+current serving mode (`provenance.source` tells you that mode, e.g.
+`generated`). Use `snapshot_id` / `commit_ref` as the version of record.
## Shape of a response
@@ -79,6 +80,7 @@ Every endpoint returns `{ data, provenance }`. The index nests its rows under
},
"provenance": {
"snapshot_id": "…", "commit_ref": "…",
+ "last_updated": "2026-05-13T12:21:49.000Z",
"published_at": null, "source": "generated"
}
}
diff --git a/public/llms.txt b/public/llms.txt
index bb29093..d936598 100644
--- a/public/llms.txt
+++ b/public/llms.txt
@@ -15,7 +15,8 @@
## How to read it
- Each response is `{ data, provenance }`. provenance carries snapshot_id
- (a content hash of the whole data set) and commit_ref — cite these for
+ (a content hash of the whole data set), commit_ref, and last_updated (when
+ the content was last edited, distinct from published_at) — cite these for
reproducibility; do not infer freshness from cache headers.
- Criterion status is exactly one of: positive | warning | at_risk |
unevaluated | reference. There is no other vocabulary. (Index count fields
diff --git a/scripts/lib/compose-data.mjs b/scripts/lib/compose-data.mjs
index 21ba32c..af7c4a7 100644
--- a/scripts/lib/compose-data.mjs
+++ b/scripts/lib/compose-data.mjs
@@ -154,8 +154,18 @@ export function composeAll(dir = contentDir) {
.update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
.digest("hex")
.slice(0, 16)
+ // Most-recent editorial timestamp across the set (unix seconds → ISO).
+ // Freshness signal surfaced in the API provenance envelope. Derived purely
+ // from content already inside snapshot_id's hash, so it never perturbs it.
+ const editedAt = tokenDocs
+ .map((d) => d.lastUpdated)
+ .filter((t) => typeof t === "number" && t > 0)
const manifest = {
snapshot_id: snapshotId,
+ last_updated:
+ editedAt.length > 0
+ ? new Date(Math.max(...editedAt) * 1000).toISOString()
+ : null,
tokens: tokenDocs.map((d) => d.id),
}
diff --git a/src/data/generated/manifest.json b/src/data/generated/manifest.json
index 5f2706b..b797b06 100644
--- a/src/data/generated/manifest.json
+++ b/src/data/generated/manifest.json
@@ -1,5 +1,6 @@
{
"snapshot_id": "364589340247aa7f",
+ "last_updated": "2026-05-13T12:21:49.000Z",
"tokens": [
"aave",
"aero",
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index 7d75fce..1f95205 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -1,11 +1,11 @@
{
"source": "aragon/otf-cms",
- "source_commit": "12f289be4b42f485634f1047ccbc6b4752bf1d55",
+ "source_commit": "c564a48d32dadaecca8ce8e7df8ff1026455886d",
"files": {
"src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
"src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "src/lib/schemas/index.ts": "41d23b4cf7319386a62138a36f899a87fd2632995dcf811138c25258c5aeefee",
- "src/lib/schemas/read-models.ts": "ce8518850d56e6146593694f8185b90ecc6beaaded9e1b4d5e69bd93d250fbf2",
- "scripts/lib/compose-data.mjs": "ada9e8803a6dd3ae4b8dd49357d991770643c300787e6016e430b3eb386bec25"
+ "src/lib/schemas/index.ts": "5fab896462bcff4afbb03e7df62127868939acd3a7126936394f16cbb10db8db",
+ "src/lib/schemas/read-models.ts": "3398ae5d209b89f81283db9cd82ba188072c433f91bc907c953a73f313e9718f",
+ "scripts/lib/compose-data.mjs": "38de2a42dd4826c7eb2ae628cd0f78e42c55144c807c3df6856331fade750847"
}
}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index c0ea314..13267b0 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -2,7 +2,7 @@
* OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
* Source of truth: https://github.com/aragon/otf-cms, vendored at commit
- * 12f289be4b42f485634f1047ccbc6b4752bf1d55. Change upstream, then re-vendor:
+ * c564a48d32dadaecca8ce8e7df8ff1026455886d. Change upstream, then re-vendor:
* node scripts/vendor-schemas.mjs
* CI fails on direct edits (scripts/check-schema-drift.mjs).
*/
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
index ecbfda1..55bd0b1 100644
--- a/src/lib/schemas/read-models.ts
+++ b/src/lib/schemas/read-models.ts
@@ -111,16 +111,21 @@ export const frameworkDocSchema = z.strictObject({
export const manifestSchema = z.strictObject({
/** Content hash over the composed output; future R2 snapshot key component. */
snapshot_id: z.string(),
+ /** Most-recent editorial edit across the set (ISO); null if none carry one. */
+ last_updated: z.string().nullable(),
tokens: z.array(z.string()),
})
/**
* Provenance envelope wrapped around every API response.
- * published_at stays null until the publish pipeline stamps real publishes.
+ * - last_updated: when the content was last edited (from the CMS).
+ * - published_at: when this snapshot was published; stays null until the
+ * publish pipeline stamps real publishes. Kept distinct from last_updated.
*/
export const provenanceSchema = z.strictObject({
snapshot_id: z.string(),
commit_ref: z.string(),
+ last_updated: z.string().nullable(),
published_at: z.string().nullable(),
source: z.enum(["generated", "kv"]),
})
diff --git a/src/lib/server/published-data.ts b/src/lib/server/published-data.ts
index 6cb400a..8c7e1f5 100644
--- a/src/lib/server/published-data.ts
+++ b/src/lib/server/published-data.ts
@@ -47,7 +47,10 @@ export function getProvenance(): Provenance {
return {
snapshot_id: manifest.snapshot_id,
commit_ref: resolveCommitRef(),
- // Stamped by the publish pipeline once snapshots are actually published.
+ // When the content was last edited (carried in the composed manifest).
+ last_updated: manifest.last_updated,
+ // Stamped by the publish pipeline once snapshots are actually published;
+ // kept distinct from last_updated.
published_at: null,
source: "generated",
}
From 344ac3bf2e2f9fe4ffc15b38e98280516931aa16 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 19:54:38 +0200
Subject: [PATCH 21/38] feat: validate composed data against the schema
contract before writing
---
package.json | 5 +-
pnpm-lock.yaml | 368 ++++++++++++++++++----
scripts/{build-data.mjs => build-data.ts} | 38 ++-
scripts/lib/compose-data.d.mts | 14 +
4 files changed, 361 insertions(+), 64 deletions(-)
rename scripts/{build-data.mjs => build-data.ts} (77%)
create mode 100644 scripts/lib/compose-data.d.mts
diff --git a/package.json b/package.json
index e82a83a..98a0560 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,8 @@
"type": "module",
"scripts": {
"dev": "vite dev --port 3000",
- "build": "node scripts/build-data.mjs && vite build",
- "build:data": "node scripts/build-data.mjs",
+ "build": "tsx scripts/build-data.ts && vite build",
+ "build:data": "tsx scripts/build-data.ts",
"preview": "vite preview",
"test": "vitest run",
"format": "biome format",
@@ -67,6 +67,7 @@
"playwright": "^1.58.2",
"shadcn": "^3.8.5",
"sharp": "^0.34.5",
+ "tsx": "^4.22.4",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vitest": "4.1.7",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a25fa4a..43e203a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -37,7 +37,7 @@ importers:
version: 0.5.19(tailwindcss@4.2.0)
'@tailwindcss/vite':
specifier: ^4.2.0
- version: 4.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 4.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@tanstack/react-devtools':
specifier: ^0.7.11
version: 0.7.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)
@@ -55,13 +55,13 @@ importers:
version: 1.161.3(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.21(react@19.2.4))(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.161.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/react-start':
specifier: ^1.161.3
- version: 1.161.3(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 1.161.3(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@tanstack/react-table':
specifier: ^8.21.3
version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/router-plugin':
specifier: ^1.161.3
- version: 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@unpic/react':
specifier: ^1.0.2
version: 1.0.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -76,7 +76,7 @@ importers:
version: 0.561.0(react@19.2.4)
nitro:
specifier: latest
- version: 3.0.1-alpha.2(lru-cache@11.2.6)(rollup@4.57.1)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 3.0.1-alpha.2(lru-cache@11.2.6)(rollup@4.57.1)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
react:
specifier: ^19.2.4
version: 19.2.4
@@ -112,7 +112,7 @@ importers:
version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
vite-tsconfig-paths:
specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
zod:
specifier: ^4.3.6
version: 4.3.6
@@ -122,7 +122,7 @@ importers:
version: 2.4.3
'@tanstack/devtools-vite':
specifier: ^0.3.12
- version: 0.3.12(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 0.3.12(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@testing-library/dom':
specifier: ^10.4.1
version: 10.4.1
@@ -140,7 +140,7 @@ importers:
version: 19.2.3(@types/react@19.2.14)
'@vitejs/plugin-react':
specifier: ^5.1.4
- version: 5.1.4(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 5.1.4(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
jsdom:
specifier: ^27.4.0
version: 27.4.0(@noble/hashes@1.8.0)
@@ -156,15 +156,18 @@ importers:
sharp:
specifier: ^0.34.5
version: 0.34.5
+ tsx:
+ specifier: ^4.22.4
+ version: 4.22.4
typescript:
specifier: ^5.9.3
version: 5.9.3
vite:
specifier: ^7.3.1
- version: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ version: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
vitest:
specifier: 4.1.7
- version: 4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ version: 4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
web-vitals:
specifier: ^5.1.0
version: 5.1.0
@@ -498,156 +501,312 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.28.1':
+ resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/android-arm64@0.27.3':
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.28.1':
+ resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm@0.27.3':
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.28.1':
+ resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-x64@0.27.3':
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.28.1':
+ resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/darwin-arm64@0.27.3':
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.28.1':
+ resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.27.3':
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.28.1':
+ resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/freebsd-arm64@0.27.3':
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.28.1':
+ resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.27.3':
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.28.1':
+ resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/linux-arm64@0.27.3':
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.28.1':
+ resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm@0.27.3':
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.28.1':
+ resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-ia32@0.27.3':
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.28.1':
+ resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-loong64@0.27.3':
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.28.1':
+ resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.27.3':
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.28.1':
+ resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.27.3':
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.28.1':
+ resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.27.3':
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.28.1':
+ resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-s390x@0.27.3':
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.28.1':
+ resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-x64@0.27.3':
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.28.1':
+ resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/netbsd-arm64@0.27.3':
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
+ '@esbuild/netbsd-arm64@0.28.1':
+ resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
'@esbuild/netbsd-x64@0.27.3':
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.28.1':
+ resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/openbsd-arm64@0.27.3':
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
+ '@esbuild/openbsd-arm64@0.28.1':
+ resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.27.3':
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.28.1':
+ resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/openharmony-arm64@0.27.3':
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
+ '@esbuild/openharmony-arm64@0.28.1':
+ resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
'@esbuild/sunos-x64@0.27.3':
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.28.1':
+ resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/win32-arm64@0.27.3':
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.28.1':
+ resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-ia32@0.27.3':
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.28.1':
+ resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-x64@0.27.3':
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.28.1':
+ resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@exodus/bytes@1.14.1':
resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
@@ -2565,6 +2724,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ esbuild@0.28.1:
+ resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -2743,9 +2907,6 @@ packages:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'}
- get-tsconfig@4.13.6:
- resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==}
-
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -3721,9 +3882,6 @@ packages:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
- resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
-
restore-cursor@5.1.0:
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
engines: {node: '>=18'}
@@ -4032,8 +4190,8 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
- tsx@4.21.0:
- resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
+ tsx@4.22.4:
+ resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -4840,81 +4998,159 @@ snapshots:
'@esbuild/aix-ppc64@0.27.3':
optional: true
+ '@esbuild/aix-ppc64@0.28.1':
+ optional: true
+
'@esbuild/android-arm64@0.27.3':
optional: true
+ '@esbuild/android-arm64@0.28.1':
+ optional: true
+
'@esbuild/android-arm@0.27.3':
optional: true
+ '@esbuild/android-arm@0.28.1':
+ optional: true
+
'@esbuild/android-x64@0.27.3':
optional: true
+ '@esbuild/android-x64@0.28.1':
+ optional: true
+
'@esbuild/darwin-arm64@0.27.3':
optional: true
+ '@esbuild/darwin-arm64@0.28.1':
+ optional: true
+
'@esbuild/darwin-x64@0.27.3':
optional: true
+ '@esbuild/darwin-x64@0.28.1':
+ optional: true
+
'@esbuild/freebsd-arm64@0.27.3':
optional: true
+ '@esbuild/freebsd-arm64@0.28.1':
+ optional: true
+
'@esbuild/freebsd-x64@0.27.3':
optional: true
+ '@esbuild/freebsd-x64@0.28.1':
+ optional: true
+
'@esbuild/linux-arm64@0.27.3':
optional: true
+ '@esbuild/linux-arm64@0.28.1':
+ optional: true
+
'@esbuild/linux-arm@0.27.3':
optional: true
+ '@esbuild/linux-arm@0.28.1':
+ optional: true
+
'@esbuild/linux-ia32@0.27.3':
optional: true
+ '@esbuild/linux-ia32@0.28.1':
+ optional: true
+
'@esbuild/linux-loong64@0.27.3':
optional: true
+ '@esbuild/linux-loong64@0.28.1':
+ optional: true
+
'@esbuild/linux-mips64el@0.27.3':
optional: true
+ '@esbuild/linux-mips64el@0.28.1':
+ optional: true
+
'@esbuild/linux-ppc64@0.27.3':
optional: true
+ '@esbuild/linux-ppc64@0.28.1':
+ optional: true
+
'@esbuild/linux-riscv64@0.27.3':
optional: true
+ '@esbuild/linux-riscv64@0.28.1':
+ optional: true
+
'@esbuild/linux-s390x@0.27.3':
optional: true
+ '@esbuild/linux-s390x@0.28.1':
+ optional: true
+
'@esbuild/linux-x64@0.27.3':
optional: true
+ '@esbuild/linux-x64@0.28.1':
+ optional: true
+
'@esbuild/netbsd-arm64@0.27.3':
optional: true
+ '@esbuild/netbsd-arm64@0.28.1':
+ optional: true
+
'@esbuild/netbsd-x64@0.27.3':
optional: true
+ '@esbuild/netbsd-x64@0.28.1':
+ optional: true
+
'@esbuild/openbsd-arm64@0.27.3':
optional: true
+ '@esbuild/openbsd-arm64@0.28.1':
+ optional: true
+
'@esbuild/openbsd-x64@0.27.3':
optional: true
+ '@esbuild/openbsd-x64@0.28.1':
+ optional: true
+
'@esbuild/openharmony-arm64@0.27.3':
optional: true
+ '@esbuild/openharmony-arm64@0.28.1':
+ optional: true
+
'@esbuild/sunos-x64@0.27.3':
optional: true
+ '@esbuild/sunos-x64@0.28.1':
+ optional: true
+
'@esbuild/win32-arm64@0.27.3':
optional: true
+ '@esbuild/win32-arm64@0.28.1':
+ optional: true
+
'@esbuild/win32-ia32@0.27.3':
optional: true
+ '@esbuild/win32-ia32@0.28.1':
+ optional: true
+
'@esbuild/win32-x64@0.27.3':
optional: true
+ '@esbuild/win32-x64@0.28.1':
+ optional: true
+
'@exodus/bytes@1.14.1(@noble/hashes@1.8.0)':
optionalDependencies:
'@noble/hashes': 1.8.0
@@ -5635,12 +5871,12 @@ snapshots:
postcss-selector-parser: 6.0.10
tailwindcss: 4.2.0
- '@tailwindcss/vite@4.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@tailwindcss/vite@4.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@tailwindcss/node': 4.2.0
'@tailwindcss/oxide': 4.2.0
tailwindcss: 4.2.0
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
'@tanstack/devtools-client@0.0.3':
dependencies:
@@ -5669,7 +5905,7 @@ snapshots:
transitivePeerDependencies:
- csstype
- '@tanstack/devtools-vite@0.3.12(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@tanstack/devtools-vite@0.3.12(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@babel/core': 7.29.0
'@babel/generator': 7.29.1
@@ -5681,7 +5917,7 @@ snapshots:
chalk: 5.6.2
launch-editor: 2.13.0
picomatch: 4.0.3
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -5780,19 +6016,19 @@ snapshots:
transitivePeerDependencies:
- crossws
- '@tanstack/react-start@1.161.3(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@tanstack/react-start@1.161.3(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@tanstack/react-router': 1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/react-start-client': 1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/react-start-server': 1.161.3(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/router-utils': 1.158.0
'@tanstack/start-client-core': 1.161.3
- '@tanstack/start-plugin-core': 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ '@tanstack/start-plugin-core': 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@tanstack/start-server-core': 1.161.3(crossws@0.4.4(srvx@0.10.1))
pathe: 2.0.3
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- '@rsbuild/core'
- crossws
@@ -5840,12 +6076,12 @@ snapshots:
prettier: 3.8.1
recast: 0.23.11
source-map: 0.7.6
- tsx: 4.21.0
+ tsx: 4.22.4
zod: 3.25.76
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@tanstack/router-plugin@1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
@@ -5862,7 +6098,7 @@ snapshots:
zod: 3.25.76
optionalDependencies:
'@tanstack/react-router': 1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- supports-color
@@ -5896,7 +6132,7 @@ snapshots:
'@tanstack/start-fn-stubs@1.154.7': {}
- '@tanstack/start-plugin-core@1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@tanstack/start-plugin-core@1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/core': 7.29.0
@@ -5904,7 +6140,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.40
'@tanstack/router-core': 1.161.3
'@tanstack/router-generator': 1.161.3
- '@tanstack/router-plugin': 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ '@tanstack/router-plugin': 1.161.3(@tanstack/react-router@1.161.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@tanstack/router-utils': 1.158.0
'@tanstack/start-client-core': 1.161.3
'@tanstack/start-server-core': 1.161.3(crossws@0.4.4(srvx@0.10.1))
@@ -5916,8 +6152,8 @@ snapshots:
srvx: 0.11.7
tinyglobby: 0.2.15
ufo: 1.6.3
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
- vitefu: 1.1.1(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
+ vitefu: 1.1.1(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
xmlbuilder2: 4.0.3
zod: 3.25.76
transitivePeerDependencies:
@@ -6088,7 +6324,7 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -6096,7 +6332,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.3
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- supports-color
@@ -6109,14 +6345,14 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
- '@vitest/mocker@4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))':
+ '@vitest/mocker@4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))':
dependencies:
'@vitest/spy': 4.1.7
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@22.19.11)(typescript@5.9.3)
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
'@vitest/pretty-format@4.1.7':
dependencies:
@@ -6614,6 +6850,35 @@ snapshots:
'@esbuild/win32-ia32': 0.27.3
'@esbuild/win32-x64': 0.27.3
+ esbuild@0.28.1:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.28.1
+ '@esbuild/android-arm': 0.28.1
+ '@esbuild/android-arm64': 0.28.1
+ '@esbuild/android-x64': 0.28.1
+ '@esbuild/darwin-arm64': 0.28.1
+ '@esbuild/darwin-x64': 0.28.1
+ '@esbuild/freebsd-arm64': 0.28.1
+ '@esbuild/freebsd-x64': 0.28.1
+ '@esbuild/linux-arm': 0.28.1
+ '@esbuild/linux-arm64': 0.28.1
+ '@esbuild/linux-ia32': 0.28.1
+ '@esbuild/linux-loong64': 0.28.1
+ '@esbuild/linux-mips64el': 0.28.1
+ '@esbuild/linux-ppc64': 0.28.1
+ '@esbuild/linux-riscv64': 0.28.1
+ '@esbuild/linux-s390x': 0.28.1
+ '@esbuild/linux-x64': 0.28.1
+ '@esbuild/netbsd-arm64': 0.28.1
+ '@esbuild/netbsd-x64': 0.28.1
+ '@esbuild/openbsd-arm64': 0.28.1
+ '@esbuild/openbsd-x64': 0.28.1
+ '@esbuild/openharmony-arm64': 0.28.1
+ '@esbuild/sunos-x64': 0.28.1
+ '@esbuild/win32-arm64': 0.28.1
+ '@esbuild/win32-ia32': 0.28.1
+ '@esbuild/win32-x64': 0.28.1
+
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -6816,10 +7081,6 @@ snapshots:
'@sec-ant/readable-stream': 0.4.1
is-stream: 4.0.1
- get-tsconfig@4.13.6:
- dependencies:
- resolve-pkg-maps: 1.0.0
-
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -7498,7 +7759,7 @@ snapshots:
nf3@0.3.10: {}
- nitro@3.0.1-alpha.2(lru-cache@11.2.6)(rollup@4.57.1)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
+ nitro@3.0.1-alpha.2(lru-cache@11.2.6)(rollup@4.57.1)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)):
dependencies:
consola: 3.4.2
crossws: 0.4.4(srvx@0.10.1)
@@ -7516,7 +7777,7 @@ snapshots:
unstorage: 2.0.0-alpha.5(db0@0.3.4)(lru-cache@11.2.6)(ofetch@2.0.0-alpha.3)
optionalDependencies:
rollup: 4.57.1
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- '@azure/app-configuration'
- '@azure/cosmos'
@@ -7946,8 +8207,6 @@ snapshots:
resolve-from@4.0.0: {}
- resolve-pkg-maps@1.0.0: {}
-
restore-cursor@5.1.0:
dependencies:
onetime: 7.0.0
@@ -8319,10 +8578,9 @@ snapshots:
tslib@2.8.1: {}
- tsx@4.21.0:
+ tsx@4.22.4:
dependencies:
- esbuild: 0.27.3
- get-tsconfig: 4.13.6
+ esbuild: 0.28.1
optionalDependencies:
fsevents: 2.3.3
@@ -8473,18 +8731,18 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
+ vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.3)
optionalDependencies:
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
transitivePeerDependencies:
- supports-color
- typescript
- vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0):
+ vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
@@ -8497,16 +8755,16 @@ snapshots:
fsevents: 2.3.3
jiti: 2.6.1
lightningcss: 1.31.1
- tsx: 4.21.0
+ tsx: 4.22.4
- vitefu@1.1.1(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
+ vitefu@1.1.1(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)):
optionalDependencies:
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
- vitest@4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)):
+ vitest@4.1.7(@types/node@22.19.11)(jsdom@27.4.0(@noble/hashes@1.8.0))(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)):
dependencies:
'@vitest/expect': 4.1.7
- '@vitest/mocker': 4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
+ '@vitest/mocker': 4.1.7(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4))
'@vitest/pretty-format': 4.1.7
'@vitest/runner': 4.1.7
'@vitest/snapshot': 4.1.7
@@ -8523,7 +8781,7 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.1.0
- vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)
+ vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.22.4)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.19.11
diff --git a/scripts/build-data.mjs b/scripts/build-data.ts
similarity index 77%
rename from scripts/build-data.mjs
rename to scripts/build-data.ts
index 6fb33d3..f037e08 100644
--- a/scripts/build-data.mjs
+++ b/scripts/build-data.ts
@@ -1,4 +1,4 @@
-#!/usr/bin/env node
+#!/usr/bin/env tsx
/**
* Build-time data layer. Produces src/data/generated/ (the read models the
* app serves) from otf-cms content. Three modes, by env:
@@ -17,8 +17,12 @@
* churn, no write access to this repo.
*
* Composition uses the VENDORED composer (scripts/lib/compose-data.mjs), so
- * the app produces byte-identical output to otf-cms.
+ * the app produces byte-identical output to otf-cms. The composed output is
+ * Zod-validated against the shared contract BEFORE it is written, so an
+ * invalid ref (or composer/schema drift) fails the build instead of shipping
+ * unvalidated data into the deployment artifact.
*/
+import { Buffer } from "node:buffer"
import { execFileSync } from "node:child_process"
import {
existsSync,
@@ -28,11 +32,19 @@ import {
rmSync,
writeFileSync,
} from "node:fs"
-import { Buffer } from "node:buffer"
import { tmpdir } from "node:os"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"
+// Vendored composer (plain JS, no types) — same composition logic as otf-cms.
import { composeAll } from "./lib/compose-data.mjs"
+import {
+ faqSchema,
+ frameworkDocSchema,
+ indexSchema,
+ manifestSchema,
+ testimonialsSchema,
+ tokenDocSchema,
+} from "../src/lib/schemas/index"
const root = join(dirname(fileURLToPath(import.meta.url)), "..")
const generatedDir = join(root, "src", "data", "generated")
@@ -48,7 +60,10 @@ if (!ref && !local) {
}
/** Resolve the otf-cms `content/` directory for this build. */
-async function resolveContentDir() {
+async function resolveContentDir(): Promise<{
+ contentDir: string
+ cleanup: () => void
+}> {
if (local) {
const dir = join(local, "content")
if (!existsSync(dir)) throw new Error(`No content/ at ${local}`)
@@ -66,7 +81,7 @@ async function resolveContentDir() {
// command line), and the ref is URL-encoded into the path. GitHub's tarball
// API 302-redirects to a pre-signed codeload URL; fetch follows it.
const res = await fetch(
- `https://api.github.com/repos/aragon/otf-cms/tarball/${encodeURIComponent(ref)}`,
+ `https://api.github.com/repos/aragon/otf-cms/tarball/${encodeURIComponent(ref as string)}`,
{
headers: {
Authorization: `Bearer ${token}`,
@@ -95,8 +110,17 @@ try {
const { index, tokenDocs, frameworkDoc, faq, testimonials, manifest } =
composeAll(contentDir)
+ // Validate against the shared contract before writing. Throwing here fails
+ // the build — invalid content never reaches the deployment artifact.
+ indexSchema.parse(index)
+ frameworkDocSchema.parse(frameworkDoc)
+ faqSchema.parse(faq)
+ testimonialsSchema.parse(testimonials)
+ manifestSchema.parse(manifest)
+ for (const doc of tokenDocs) tokenDocSchema.parse(doc)
+
rmSync(generatedDir, { recursive: true, force: true })
- const write = (rel, data) => {
+ const write = (rel: string, data: unknown) => {
const p = join(generatedDir, rel)
mkdirSync(dirname(p), { recursive: true })
writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
@@ -109,7 +133,7 @@ try {
for (const doc of tokenDocs) write(join("tokens", `${doc.id}.json`), doc)
console.log(
- `build-data: composed ${tokenDocs.length} token docs (snapshot ${manifest.snapshot_id})`
+ `build-data: validated + composed ${tokenDocs.length} token docs (snapshot ${manifest.snapshot_id})`
)
} finally {
cleanup()
diff --git a/scripts/lib/compose-data.d.mts b/scripts/lib/compose-data.d.mts
new file mode 100644
index 0000000..3df5035
--- /dev/null
+++ b/scripts/lib/compose-data.d.mts
@@ -0,0 +1,14 @@
+/**
+ * Typed contract for the VENDORED composer (compose-data.mjs is byte-identical
+ * to otf-cms and stays plain JS so it vendors cleanly). The composed values are
+ * `unknown` on purpose — build-data.ts Zod-parses each against the shared
+ * schemas before writing, so the real shapes are enforced at runtime there.
+ */
+export function composeAll(dir?: string): {
+ index: unknown
+ tokenDocs: { id: string }[]
+ frameworkDoc: unknown
+ faq: unknown
+ testimonials: unknown
+ manifest: { snapshot_id: string }
+}
From 082e98613b9a9f7ef6dfa59b29ebc1025533362d Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:07:38 +0200
Subject: [PATCH 22/38] refactor: vendor the TypeScript composer and drop the
JS type shim
---
scripts/build-data.ts | 4 +-
scripts/lib/compose-data.d.mts | 14 ------
.../lib/{compose-data.mjs => compose-data.ts} | 45 ++++++++++---------
scripts/vendor-schemas.mjs | 6 +--
src/lib/schemas/.vendor-lock.json | 6 +--
src/lib/schemas/index.ts | 2 +-
6 files changed, 33 insertions(+), 44 deletions(-)
delete mode 100644 scripts/lib/compose-data.d.mts
rename scripts/lib/{compose-data.mjs => compose-data.ts} (84%)
diff --git a/scripts/build-data.ts b/scripts/build-data.ts
index f037e08..8d9934f 100644
--- a/scripts/build-data.ts
+++ b/scripts/build-data.ts
@@ -35,8 +35,8 @@ import {
import { tmpdir } from "node:os"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"
-// Vendored composer (plain JS, no types) — same composition logic as otf-cms.
-import { composeAll } from "./lib/compose-data.mjs"
+// Vendored composer (TypeScript, same composition logic as otf-cms).
+import { composeAll } from "./lib/compose-data"
import {
faqSchema,
frameworkDocSchema,
diff --git a/scripts/lib/compose-data.d.mts b/scripts/lib/compose-data.d.mts
deleted file mode 100644
index 3df5035..0000000
--- a/scripts/lib/compose-data.d.mts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Typed contract for the VENDORED composer (compose-data.mjs is byte-identical
- * to otf-cms and stays plain JS so it vendors cleanly). The composed values are
- * `unknown` on purpose — build-data.ts Zod-parses each against the shared
- * schemas before writing, so the real shapes are enforced at runtime there.
- */
-export function composeAll(dir?: string): {
- index: unknown
- tokenDocs: { id: string }[]
- frameworkDoc: unknown
- faq: unknown
- testimonials: unknown
- manifest: { snapshot_id: string }
-}
diff --git a/scripts/lib/compose-data.mjs b/scripts/lib/compose-data.ts
similarity index 84%
rename from scripts/lib/compose-data.mjs
rename to scripts/lib/compose-data.ts
index af7c4a7..161e235 100644
--- a/scripts/lib/compose-data.mjs
+++ b/scripts/lib/compose-data.ts
@@ -1,4 +1,4 @@
-#!/usr/bin/env node
+#!/usr/bin/env tsx
/**
* Composer: content/ atoms → src/data/generated/ read models.
*
@@ -12,6 +12,11 @@
* The scoring logic mirrors the pure functions in src/lib/scoring.ts and is
* pinned to them by the golden round-trip tests.
*
+ * Inputs are read from JSON (untyped by nature) and the composed output is
+ * Zod-validated downstream (otf-cms tests; the app's build-data step) — so the
+ * transform is typed loosely on purpose and the schema contract is the source
+ * of truth for the real shapes.
+ *
* Exports composeAll() for tests; run directly to write src/data/generated/.
*/
import { createHash } from "node:crypto"
@@ -29,18 +34,18 @@ const root = join(dirname(fileURLToPath(import.meta.url)), "..")
const contentDir = join(root, "content")
const generatedDir = join(root, "generated")
-const readJson = (p) => JSON.parse(readFileSync(p, "utf8"))
+const readJson = (p: string): any => JSON.parse(readFileSync(p, "utf8"))
const SCORED_STATUSES = new Set(["positive", "warning", "at_risk"])
-function getMetricScore(metric) {
+function getMetricScore(metric: any) {
const reference = metric.tags?.includes("Reference") ?? false
- const evaluatedCriteria = metric.criteria.filter((c) =>
+ const evaluatedCriteria = metric.criteria.filter((c: any) =>
SCORED_STATUSES.has(c.status)
)
const total = evaluatedCriteria.length
const passing = evaluatedCriteria.filter(
- (c) => c.status === "positive"
+ (c: any) => c.status === "positive"
).length
const evaluated = reference ? false : total > 0
const percentage = total > 0 ? (passing / total) * 100 : 0
@@ -56,7 +61,7 @@ function getMetricScore(metric) {
}
}
-function getTokenScore(tokenId, metrics) {
+function getTokenScore(tokenId: string, metrics: any[]) {
const metricScores = metrics.map(getMetricScore)
const scoredMetrics = metricScores.filter((m) => m.evaluated && !m.reference)
const passing = scoredMetrics.reduce((sum, m) => sum + m.passing, 0)
@@ -66,35 +71,32 @@ function getTokenScore(tokenId, metrics) {
return { tokenId, passing, total, percentage, metrics: metricScores }
}
-export function composeAll(dir = contentDir) {
+export function composeAll(dir: string = contentDir) {
const meta = readJson(join(dir, "framework-meta.json"))
- const framework = meta.order.map((id) =>
+ const framework = meta.order.map((id: string) =>
readJson(join(dir, "framework", `${id}.json`))
)
- const criterionDefs = new Map(
- framework.flatMap((m) => m.criteria.map((c) => [c.id, c]))
- )
- const tokenIds = readdirSync(join(dir, "tokens"))
+ const tokenIds: string[] = readdirSync(join(dir, "tokens"))
.filter((f) => f.endsWith(".json"))
.map((f) => f.replace(/\.json$/, ""))
.sort()
- const tokenAtoms = new Map(
+ const tokenAtoms = new Map(
tokenIds.map((id) => [id, readJson(join(dir, "tokens", `${id}.json`))])
)
- const tokenDocs = []
+ const tokenDocs: any[] = []
for (const tokenId of tokenIds) {
- const metrics = []
+ const metrics: any[] = []
for (const fm of framework) {
const metricDir = join(dir, "evaluations", tokenId, fm.id)
const editorial = readJson(
join(dir, "summaries", tokenId, `${fm.id}.json`)
)
- const criteria = fm.criteria.map((fc) => {
+ const criteria = fm.criteria.map((fc: any) => {
const atom = readJson(join(metricDir, `${fc.id}.json`))
- const composed = {
+ const composed: any = {
id: fc.id,
name: atom.name ?? fc.name,
about: fc.about,
@@ -116,7 +118,7 @@ export function composeAll(dir = contentDir) {
}
const allCriteria = metrics.flatMap((m) => m.criteria)
- const countBy = (status) =>
+ const countBy = (status: string) =>
allCriteria.filter((c) => c.status === status).length
const score = getTokenScore(tokenId, metrics)
@@ -154,10 +156,11 @@ export function composeAll(dir = contentDir) {
.update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
.digest("hex")
.slice(0, 16)
+
// Most-recent editorial timestamp across the set (unix seconds → ISO).
// Freshness signal surfaced in the API provenance envelope. Derived purely
// from content already inside snapshot_id's hash, so it never perturbs it.
- const editedAt = tokenDocs
+ const editedAt: number[] = tokenDocs
.map((d) => d.lastUpdated)
.filter((t) => typeof t === "number" && t > 0)
const manifest = {
@@ -166,7 +169,7 @@ export function composeAll(dir = contentDir) {
editedAt.length > 0
? new Date(Math.max(...editedAt) * 1000).toISOString()
: null,
- tokens: tokenDocs.map((d) => d.id),
+ tokens: tokenDocs.map((d) => d.id as string),
}
return {
@@ -184,7 +187,7 @@ function main() {
composeAll()
rmSync(generatedDir, { recursive: true, force: true })
- const writeJson = (p, data) => {
+ const writeJson = (p: string, data: unknown) => {
mkdirSync(dirname(p), { recursive: true })
writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`)
}
diff --git a/scripts/vendor-schemas.mjs b/scripts/vendor-schemas.mjs
index 9472220..38e00b4 100644
--- a/scripts/vendor-schemas.mjs
+++ b/scripts/vendor-schemas.mjs
@@ -7,7 +7,7 @@
*
* Vendors:
* otf-cms/schemas/*.ts → src/lib/schemas/ (the Zod contract)
- * otf-cms/scripts/compose-data.mjs → scripts/lib/compose-data.mjs
+ * otf-cms/scripts/compose-data.ts → scripts/lib/compose-data.ts
* (the composer — the app composes otf-cms content at build time, so it
* must run the exact same composition logic)
*
@@ -58,8 +58,8 @@ for (const f of readdirSync(schemaDir).filter((f) => f.endsWith(".ts")).sort())
// Composer
vendor(
- join(sourceRepo, "scripts", "compose-data.mjs"),
- "scripts/lib/compose-data.mjs"
+ join(sourceRepo, "scripts", "compose-data.ts"),
+ "scripts/lib/compose-data.ts"
)
writeFileSync(
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index 1f95205..8bce74e 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -1,11 +1,11 @@
{
"source": "aragon/otf-cms",
- "source_commit": "c564a48d32dadaecca8ce8e7df8ff1026455886d",
+ "source_commit": "319028143dded10d61978a13b3201970794688a9",
"files": {
"src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
"src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "src/lib/schemas/index.ts": "5fab896462bcff4afbb03e7df62127868939acd3a7126936394f16cbb10db8db",
+ "src/lib/schemas/index.ts": "71deef751208c1dfb3699cd9fbf100f5b2f33bf65ba8fc5f68942a7de6f9a6c8",
"src/lib/schemas/read-models.ts": "3398ae5d209b89f81283db9cd82ba188072c433f91bc907c953a73f313e9718f",
- "scripts/lib/compose-data.mjs": "38de2a42dd4826c7eb2ae628cd0f78e42c55144c807c3df6856331fade750847"
+ "scripts/lib/compose-data.ts": "f271c040c4605bad94fc550dfeac94ff025878036ebb1176b948795fe7624346"
}
}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index 13267b0..aa3f1a5 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -2,7 +2,7 @@
* OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
* Source of truth: https://github.com/aragon/otf-cms, vendored at commit
- * c564a48d32dadaecca8ce8e7df8ff1026455886d. Change upstream, then re-vendor:
+ * 319028143dded10d61978a13b3201970794688a9. Change upstream, then re-vendor:
* node scripts/vendor-schemas.mjs
* CI fails on direct edits (scripts/check-schema-drift.mjs).
*/
From ecb96d1f76768e62b5980cc7fb6e3ae7ec27d458 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:17:44 +0200
Subject: [PATCH 23/38] feat: serve published content from the release at
runtime behind a dark fallback
---
src/lib/server/published-source.ts | 221 +++++++++++++++++++++++++++++
src/lib/server/token-api.ts | 45 +++---
tests/api-endpoints.test.ts | 16 +--
3 files changed, 250 insertions(+), 32 deletions(-)
create mode 100644 src/lib/server/published-source.ts
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
new file mode 100644
index 0000000..60b6149
--- /dev/null
+++ b/src/lib/server/published-source.ts
@@ -0,0 +1,221 @@
+/**
+ * Runtime published-content source with a committed-data fallback.
+ *
+ * This sits in front of published-data.ts (the committed read models). When the
+ * publish pipeline is enabled via env, it fetches the latest snapshot from the
+ * private aragon/otf-cms GitHub Release, validates it against the vendored
+ * schemas, caches it in-process with a short TTL, and serves it. With NO env
+ * configured (the default, shipped dark) it transparently serves the committed
+ * data — byte-identical to the pre-pipeline behavior, provenance.source
+ * "generated".
+ *
+ * Hard rule: this module NEVER throws to the caller. Any fetch/parse/validate
+ * failure falls back to committed data and logs a warning.
+ */
+import {
+ type FaqTopic,
+ type FrameworkDoc,
+ faqSchema,
+ frameworkDocSchema,
+ type IndexRow,
+ indexSchema,
+ type Manifest,
+ manifestSchema,
+ type Provenance,
+ type TokenDoc,
+ testimonialsSchema,
+ tokenDocSchema,
+} from "@/lib/schemas"
+import {
+ getPublishedFaq as getCommittedFaq,
+ getPublishedFramework as getCommittedFramework,
+ getPublishedIndex as getCommittedIndex,
+ getProvenance as getCommittedProvenance,
+ getPublishedTokenDoc as getCommittedTokenDoc,
+} from "@/lib/server/published-data"
+
+const RELEASE_API_URL =
+ "https://api.github.com/repos/aragon/otf-cms/releases/latest"
+const SNAPSHOT_ASSET_NAME = "snapshot.json"
+const USER_AGENT = "otf-dashboard"
+/** How long a validated release bundle is served before we revalidate. */
+const CACHE_TTL_MS = 60_000
+
+/** A fully validated snapshot bundle composed from the release asset. */
+type Bundle = {
+ manifest: Manifest
+ index: { tokens: IndexRow[] }
+ tokens: Map
+ framework: FrameworkDoc
+ faq: { topics: FaqTopic[] }
+}
+
+/** Module-level cache of the last successfully validated release bundle. */
+let cachedBundle: Bundle | null = null
+let cachedAtMs = 0
+/** De-dupes concurrent revalidations so a request burst issues one fetch. */
+let inFlight: Promise | null = null
+
+/**
+ * The publish pipeline is opt-in. With OTF_PUBLISHED_RELEASE unset (or anything
+ * other than "true") we serve committed data exactly as before.
+ */
+function isReleaseEnabled(): boolean {
+ return process.env.OTF_PUBLISHED_RELEASE === "true"
+}
+
+/** Mirrors published-data.ts so committed and release provenance agree. */
+function resolveCommitRef(): string {
+ return (
+ process.env.VERCEL_GIT_COMMIT_SHA ??
+ process.env.CF_PAGES_COMMIT_SHA ??
+ process.env.GITHUB_SHA ??
+ "dev"
+ )
+}
+
+/**
+ * Fetch + validate the latest release snapshot into a Bundle. Returns null on
+ * ANY failure (network, non-2xx, missing asset, malformed JSON, schema
+ * violation) after logging a warning — the caller then falls back to committed
+ * data.
+ */
+async function fetchReleaseBundle(): Promise {
+ const token = process.env.OTF_CONTENT_TOKEN
+ try {
+ const releaseRes = await fetch(RELEASE_API_URL, {
+ headers: {
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
+ Accept: "application/vnd.github+json",
+ "User-Agent": USER_AGENT,
+ },
+ })
+ if (!releaseRes.ok) {
+ console.warn(
+ `[published-source] release lookup failed: ${releaseRes.status} ${releaseRes.statusText}`
+ )
+ return null
+ }
+ const release = (await releaseRes.json()) as {
+ assets?: Array<{ name?: string; url?: string }>
+ }
+ const asset = release.assets?.find((a) => a.name === SNAPSHOT_ASSET_NAME)
+ if (!asset?.url) {
+ console.warn(
+ `[published-source] release has no "${SNAPSHOT_ASSET_NAME}" asset`
+ )
+ return null
+ }
+
+ const assetRes = await fetch(asset.url, {
+ headers: {
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
+ // The GitHub asset API returns the raw bytes only with this Accept.
+ Accept: "application/octet-stream",
+ "User-Agent": USER_AGENT,
+ },
+ })
+ if (!assetRes.ok) {
+ console.warn(
+ `[published-source] asset download failed: ${assetRes.status} ${assetRes.statusText}`
+ )
+ return null
+ }
+
+ const raw = (await assetRes.json()) as Record
+
+ // Validate each part against the vendored schemas. A throw here is caught
+ // below and surfaces as a fallback, so a bad publish can never serve
+ // malformed shapes.
+ const manifest = manifestSchema.parse(raw.manifest)
+ const index = indexSchema.parse(raw.index)
+ const framework = frameworkDocSchema.parse(raw.framework)
+ const faq = faqSchema.parse(raw.faq)
+ // Validated for integrity but not served via this seam's endpoints.
+ testimonialsSchema.parse(raw.testimonials)
+
+ const rawTokens = (raw.tokens ?? {}) as Record
+ const tokens = new Map()
+ for (const doc of Object.values(rawTokens)) {
+ const parsed = tokenDocSchema.parse(doc)
+ tokens.set(parsed.id, parsed)
+ }
+
+ return { manifest, index, tokens, framework, faq }
+ } catch (err) {
+ console.warn(
+ `[published-source] falling back to committed data: ${
+ err instanceof Error ? err.message : String(err)
+ }`
+ )
+ return null
+ }
+}
+
+/**
+ * Returns the active release bundle, fetching/revalidating as needed. Serves a
+ * fresh cached bundle immediately; on expiry revalidates and, if that fails,
+ * keeps serving the stale bundle rather than dropping to committed data. Returns
+ * null only when the release is disabled or no bundle has ever validated.
+ */
+async function getActiveBundle(): Promise {
+ if (!isReleaseEnabled()) {
+ return null
+ }
+ const fresh = cachedBundle && Date.now() - cachedAtMs < CACHE_TTL_MS
+ if (fresh) {
+ return cachedBundle
+ }
+ // Coalesce concurrent revalidations into one in-flight fetch.
+ if (!inFlight) {
+ inFlight = fetchReleaseBundle().finally(() => {
+ inFlight = null
+ })
+ }
+ const next = await inFlight
+ if (next) {
+ cachedBundle = next
+ cachedAtMs = Date.now()
+ return next
+ }
+ // Revalidation failed — serve the last good bundle if we have one, else the
+ // caller falls back to committed data.
+ return cachedBundle
+}
+
+export async function getProvenance(): Promise {
+ const bundle = await getActiveBundle()
+ if (!bundle) {
+ return getCommittedProvenance()
+ }
+ return {
+ snapshot_id: bundle.manifest.snapshot_id,
+ commit_ref: resolveCommitRef(),
+ last_updated: bundle.manifest.last_updated,
+ published_at: null,
+ source: "kv",
+ }
+}
+
+export async function getIndex(): Promise<{ tokens: IndexRow[] }> {
+ const bundle = await getActiveBundle()
+ return bundle ? bundle.index : getCommittedIndex()
+}
+
+export async function getTokenDoc(tokenId: string): Promise {
+ const bundle = await getActiveBundle()
+ if (!bundle) {
+ return getCommittedTokenDoc(tokenId)
+ }
+ return bundle.tokens.get(tokenId.trim().toLowerCase()) ?? null
+}
+
+export async function getFramework(): Promise {
+ const bundle = await getActiveBundle()
+ return bundle ? bundle.framework : getCommittedFramework()
+}
+
+export async function getFaq(): Promise<{ topics: FaqTopic[] }> {
+ const bundle = await getActiveBundle()
+ return bundle ? bundle.faq : getCommittedFaq()
+}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index ca8efb2..6f60e95 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -4,7 +4,7 @@
*
* Response contract (consumed by the app, future APP-796 agents, and
* external partners):
- * { data: , provenance: { snapshot_id, commit_ref, published_at, source } }
+ * { data: , provenance: { snapshot_id, commit_ref, last_updated, published_at, source } }
*
* NOTE: the route parameter is the token `id` (lowercase, e.g. "ldo") —
* matching generated/tokens/.json and the existing /tokens/$tokenId page
@@ -12,12 +12,12 @@
* to ids for all current tokens).
*/
import {
+ getFaq,
+ getFramework,
+ getIndex,
getProvenance,
- getPublishedFaq,
- getPublishedFramework,
- getPublishedIndex,
- getPublishedTokenDoc,
-} from "@/lib/server/published-data"
+ getTokenDoc,
+} from "@/lib/server/published-source"
// The published data is immutable for the life of a deploy (composed at build
// time and content-hashed). Hosts purge their edge cache on each new deploy, so
@@ -86,32 +86,29 @@ export function handleMethodNotAllowed(): Response {
}
/** GET /api/v1/tokens — the published index (discovery + cross-token queries). */
-export function handleGetTokens(): Response {
- return jsonResponse({
- data: getPublishedIndex(),
- provenance: getProvenance(),
- })
+export async function handleGetTokens(): Promise {
+ const [data, provenance] = await Promise.all([getIndex(), getProvenance()])
+ return jsonResponse({ data, provenance })
}
/** GET /api/v1/framework — canonical metric/criteria definitions + anchors. */
-export function handleGetFramework(): Response {
- return jsonResponse({
- data: getPublishedFramework(),
- provenance: getProvenance(),
- })
+export async function handleGetFramework(): Promise {
+ const [data, provenance] = await Promise.all([
+ getFramework(),
+ getProvenance(),
+ ])
+ return jsonResponse({ data, provenance })
}
/** GET /api/v1/faq — published framework/methodology Q&A. */
-export function handleGetFaq(): Response {
- return jsonResponse({
- data: getPublishedFaq(),
- provenance: getProvenance(),
- })
+export async function handleGetFaq(): Promise {
+ const [data, provenance] = await Promise.all([getFaq(), getProvenance()])
+ return jsonResponse({ data, provenance })
}
/** GET /api/v1/tokens/{id} — one composed token doc (the per-token reusable unit). */
-export function handleGetToken(tokenId: string): Response {
- const doc = getPublishedTokenDoc(tokenId)
+export async function handleGetToken(tokenId: string): Promise {
+ const doc = await getTokenDoc(tokenId)
if (!doc) {
return jsonResponse(
{
@@ -124,5 +121,5 @@ export function handleGetToken(tokenId: string): Response {
CACHE_MISS
)
}
- return jsonResponse({ data: doc, provenance: getProvenance() })
+ return jsonResponse({ data: doc, provenance: await getProvenance() })
}
diff --git a/tests/api-endpoints.test.ts b/tests/api-endpoints.test.ts
index 64ff872..7751e37 100644
--- a/tests/api-endpoints.test.ts
+++ b/tests/api-endpoints.test.ts
@@ -31,7 +31,7 @@ async function body(res: Response) {
describe("GET /api/tokens", () => {
it("returns the published index wrapped in a provenance envelope", async () => {
- const res = handleGetTokens()
+ const res = await handleGetTokens()
expect(res.status).toBe(200)
expect(res.headers.get("Content-Type")).toBe("application/json")
@@ -41,12 +41,12 @@ describe("GET /api/tokens", () => {
})
it("data payload is identical to generated/index.json", async () => {
- const payload = await body(handleGetTokens())
+ const payload = await body(await handleGetTokens())
expect(payload.data).toEqual(readJson(join(generated, "index.json")))
})
it("envelope: commit_ref non-null, published_at null pre-pipeline, snapshot_id matches manifest", async () => {
- const { provenance } = await body(handleGetTokens())
+ const { provenance } = await body(await handleGetTokens())
expect(provenance.commit_ref).toBeTruthy()
expect(provenance.published_at).toBeNull()
expect(provenance.source).toBe("generated")
@@ -58,7 +58,7 @@ describe("GET /api/tokens", () => {
describe("GET /api/framework", () => {
it("returns the framework doc with provenance, identical to generated", async () => {
- const res = handleGetFramework()
+ const res = await handleGetFramework()
expect(res.status).toBe(200)
const payload = await body(res)
expect(() => frameworkDocSchema.parse(payload.data)).not.toThrow()
@@ -69,7 +69,7 @@ describe("GET /api/framework", () => {
describe("GET /api/v1/faq", () => {
it("returns the faq doc with provenance, identical to generated", async () => {
- const res = handleGetFaq()
+ const res = await handleGetFaq()
expect(res.status).toBe(200)
const payload = await body(res)
expect(() => faqSchema.parse(payload.data)).not.toThrow()
@@ -81,7 +81,7 @@ describe("GET /api/v1/faq", () => {
describe("GET /api/tokens/{id}", () => {
it("returns every published token doc identical to its generated file", async () => {
for (const id of TOKEN_IDS) {
- const res = handleGetToken(id)
+ const res = await handleGetToken(id)
expect(res.status, id).toBe(200)
const payload = await body(res)
expect(() => tokenDocSchema.parse(payload.data), id).not.toThrow()
@@ -93,7 +93,7 @@ describe("GET /api/tokens/{id}", () => {
})
it("normalizes id casing and whitespace", async () => {
- const res = handleGetToken(" LDO ")
+ const res = await handleGetToken(" LDO ")
expect(res.status).toBe(200)
const payload = await body(res)
expect(payload.data.id).toBe("ldo")
@@ -102,7 +102,7 @@ describe("GET /api/tokens/{id}", () => {
it.each(["doge", "not-a-token"])(
"returns structured 404 for unknown id %s",
async (id) => {
- const res = handleGetToken(id)
+ const res = await handleGetToken(id)
expect(res.status).toBe(404)
const payload = await body(res)
expect(() => apiErrorSchema.parse(payload)).not.toThrow()
From 7d585d822c299eb98a3fcdb8f66ebc0f3274c511 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:24:08 +0200
Subject: [PATCH 24/38] docs: note the dark-launch flag is removable
post-migration
---
src/lib/server/published-source.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index 60b6149..813c363 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -59,6 +59,11 @@ let inFlight: Promise | null = null
/**
* The publish pipeline is opt-in. With OTF_PUBLISHED_RELEASE unset (or anything
* other than "true") we serve committed data exactly as before.
+ *
+ * TODO(post-migration): this flag is a dark-launch tool, not a permanent
+ * control — once runtime reads are provisioned and trusted, delete it and gate
+ * on OTF_CONTENT_TOKEN presence instead (no token → committed; correct for
+ * dev/test/CI). The graceful fallback below stays regardless.
*/
function isReleaseEnabled(): boolean {
return process.env.OTF_PUBLISHED_RELEASE === "true"
From 3f97f1ea79e6c0373b3c6e766a079251ae7327b4 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:26:38 +0200
Subject: [PATCH 25/38] fix: name the runtime provenance source release not kv
---
src/lib/schemas/.vendor-lock.json | 6 +++---
src/lib/schemas/index.ts | 2 +-
src/lib/schemas/read-models.ts | 8 ++++----
src/lib/server/published-source.ts | 2 +-
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index 8bce74e..fbe13de 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -1,11 +1,11 @@
{
"source": "aragon/otf-cms",
- "source_commit": "319028143dded10d61978a13b3201970794688a9",
+ "source_commit": "8170271c4873c0a3ca3f028e01dcc61dfba1589d",
"files": {
"src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
"src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "src/lib/schemas/index.ts": "71deef751208c1dfb3699cd9fbf100f5b2f33bf65ba8fc5f68942a7de6f9a6c8",
- "src/lib/schemas/read-models.ts": "3398ae5d209b89f81283db9cd82ba188072c433f91bc907c953a73f313e9718f",
+ "src/lib/schemas/index.ts": "1296722dc597074f268cca39da024befd80b33b67870e559970f579b9cca5698",
+ "src/lib/schemas/read-models.ts": "9af495412eb22c6ac7a9ced07e976b9e960582f46e4dcf2c4f2dcc6f51868041",
"scripts/lib/compose-data.ts": "f271c040c4605bad94fc550dfeac94ff025878036ebb1176b948795fe7624346"
}
}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index aa3f1a5..d53229c 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -2,7 +2,7 @@
* OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
*
* Source of truth: https://github.com/aragon/otf-cms, vendored at commit
- * 319028143dded10d61978a13b3201970794688a9. Change upstream, then re-vendor:
+ * 8170271c4873c0a3ca3f028e01dcc61dfba1589d. Change upstream, then re-vendor:
* node scripts/vendor-schemas.mjs
* CI fails on direct edits (scripts/check-schema-drift.mjs).
*/
diff --git a/src/lib/schemas/read-models.ts b/src/lib/schemas/read-models.ts
index 55bd0b1..2a1371f 100644
--- a/src/lib/schemas/read-models.ts
+++ b/src/lib/schemas/read-models.ts
@@ -1,9 +1,9 @@
/**
* Read-model schemas — the composed, consumer-shaped output under
- * `src/data/generated/` (produced by scripts/compose-data.mjs).
+ * `src/data/generated/` (produced by scripts/compose-data.ts).
*
- * These are the shapes the app renders and that the future publish
- * pipeline will serve from KV/R2 — transport changes later, shape doesn't.
+ * These are the shapes the app renders and that the publish pipeline serves
+ * from GitHub Release snapshots — transport changes later, shape doesn't.
*/
import { z } from "zod"
import { tokenAtomSchema } from "./atoms"
@@ -127,7 +127,7 @@ export const provenanceSchema = z.strictObject({
commit_ref: z.string(),
last_updated: z.string().nullable(),
published_at: z.string().nullable(),
- source: z.enum(["generated", "kv"]),
+ source: z.enum(["generated", "release"]),
})
export const apiErrorSchema = z.strictObject({
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index 813c363..c244c12 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -198,7 +198,7 @@ export async function getProvenance(): Promise {
commit_ref: resolveCommitRef(),
last_updated: bundle.manifest.last_updated,
published_at: null,
- source: "kv",
+ source: "release",
}
}
From c1a112b0eedd7b9d1c160f762a8734db887308c4 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:33:07 +0200
Subject: [PATCH 26/38] docs: define vendoring in plain terms at the script and
file touchpoints
---
scripts/check-schema-drift.mjs | 9 +++++----
scripts/vendor-schemas.mjs | 31 +++++++++++++++++--------------
src/lib/schemas/.vendor-lock.json | 2 +-
src/lib/schemas/index.ts | 10 +++++-----
4 files changed, 28 insertions(+), 24 deletions(-)
diff --git a/scripts/check-schema-drift.mjs b/scripts/check-schema-drift.mjs
index f3c0398..fd3560c 100644
--- a/scripts/check-schema-drift.mjs
+++ b/scripts/check-schema-drift.mjs
@@ -1,9 +1,10 @@
#!/usr/bin/env node
/**
- * Vendored-contract integrity gate (CI): every vendored file (schemas +
- * composer) must match the vendor lock written by scripts/vendor-schemas.mjs.
- * Direct edits to a vendored copy fail here — change it in otf-cms and
- * re-vendor.
+ * Drift gate (CI). The shared contract files here (the Zod schemas + composer)
+ * are checked-in COPIES of otf-cms's source — "vendored" by
+ * scripts/vendor-schemas.mjs. This verifies each copy still matches the hash
+ * recorded in the lock, so a hand-edit of a copy fails the build. To change
+ * one: edit it in otf-cms, then re-run vendor-schemas.mjs to refresh the copies.
*/
import { createHash } from "node:crypto"
import { readFileSync } from "node:fs"
diff --git a/scripts/vendor-schemas.mjs b/scripts/vendor-schemas.mjs
index 38e00b4..45337aa 100644
--- a/scripts/vendor-schemas.mjs
+++ b/scripts/vendor-schemas.mjs
@@ -1,19 +1,22 @@
#!/usr/bin/env node
/**
- * Re-vendor the data contract + composer from otf-cms (the source of truth).
+ * Sync the shared data contract (Zod schemas + composer) from otf-cms into this
+ * repo by COPYING the files in. This is "vendoring": the app keeps checked-in
+ * copies of otf-cms's source instead of installing it as an npm package, so
+ * there's one source of truth (otf-cms) with no registry or publish step. To
+ * "re-vendor" is just to re-run this script to refresh the copies after the
+ * otf-cms originals change.
*
* Usage: node scripts/vendor-schemas.mjs [path-to-otf-cms-checkout]
* (default: ../otf-cms sibling checkout)
*
- * Vendors:
- * otf-cms/schemas/*.ts → src/lib/schemas/ (the Zod contract)
- * otf-cms/scripts/compose-data.ts → scripts/lib/compose-data.ts
- * (the composer — the app composes otf-cms content at build time, so it
- * must run the exact same composition logic)
+ * Copies:
+ * otf-cms/schemas/*.ts → src/lib/schemas/ (the Zod contract)
+ * otf-cms/scripts/compose-data.ts → scripts/lib/compose-data.ts (the composer)
*
- * Records a vendor lock (source commit + per-file hashes). CI verifies it —
- * direct edits to the vendored copies fail; this script is the only
- * sanctioned way to change them.
+ * Writes a lock file (the otf-cms source commit + a hash of each copied file).
+ * CI (check-schema-drift.mjs) re-checks those hashes, so hand-editing a copy
+ * here fails the build — change it in otf-cms and re-run this script instead.
*/
import { execSync } from "node:child_process"
import { createHash } from "node:crypto"
@@ -25,12 +28,12 @@ const root = join(dirname(fileURLToPath(import.meta.url)), "..")
const sourceRepo = resolve(root, process.argv[2] ?? "../otf-cms")
const BANNER = (commit) => `/**
- * OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
+ * OTF data contract — a checked-in COPY of otf-cms's source (i.e. "vendored").
+ * DO NOT EDIT HERE: a change to this copy fails CI's drift check.
*
- * Source of truth: https://github.com/aragon/otf-cms, vendored at commit
- * ${commit}. Change upstream, then re-vendor:
- * node scripts/vendor-schemas.mjs
- * CI fails on direct edits (scripts/check-schema-drift.mjs).
+ * Source of truth: https://github.com/aragon/otf-cms (copied at ${commit}).
+ * To change it, edit the file in otf-cms, then refresh the copies here by
+ * re-running: node scripts/vendor-schemas.mjs
*/`
const sourceCommit = execSync("git rev-parse HEAD", {
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index fbe13de..f403405 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -4,7 +4,7 @@
"files": {
"src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
"src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "src/lib/schemas/index.ts": "1296722dc597074f268cca39da024befd80b33b67870e559970f579b9cca5698",
+ "src/lib/schemas/index.ts": "77626d4b97d528032ba32b2152a80457ab3f77da06ef90db089b885228e96f2a",
"src/lib/schemas/read-models.ts": "9af495412eb22c6ac7a9ced07e976b9e960582f46e4dcf2c4f2dcc6f51868041",
"scripts/lib/compose-data.ts": "f271c040c4605bad94fc550dfeac94ff025878036ebb1176b948795fe7624346"
}
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index d53229c..f9bc84b 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -1,10 +1,10 @@
/**
- * OTF data contract — VENDORED COPY. DO NOT EDIT HERE.
+ * OTF data contract — a checked-in COPY of otf-cms's source (i.e. "vendored").
+ * DO NOT EDIT HERE: a change to this copy fails CI's drift check.
*
- * Source of truth: https://github.com/aragon/otf-cms, vendored at commit
- * 8170271c4873c0a3ca3f028e01dcc61dfba1589d. Change upstream, then re-vendor:
- * node scripts/vendor-schemas.mjs
- * CI fails on direct edits (scripts/check-schema-drift.mjs).
+ * Source of truth: https://github.com/aragon/otf-cms (copied at 8170271c4873c0a3ca3f028e01dcc61dfba1589d).
+ * To change it, edit the file in otf-cms, then refresh the copies here by
+ * re-running: node scripts/vendor-schemas.mjs
*/
export * from "./atoms"
export * from "./common"
From ef7677ce7554f41e67f064eec3c91ce2fbfd4cb1 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:58:22 +0200
Subject: [PATCH 27/38] fix: read SSR data through the same published source as
the API
---
src/lib/published-queries.ts | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/src/lib/published-queries.ts b/src/lib/published-queries.ts
index 4ff8be9..baa4710 100644
--- a/src/lib/published-queries.ts
+++ b/src/lib/published-queries.ts
@@ -2,16 +2,18 @@
* Query definitions for the published read models.
*
* Server side (`import.meta.env.SSR` is statically true), queryFns read the
- * published data source directly — no self-HTTP, and Vite's static
- * replacement guarantees the dynamic import (and the data behind it) is
- * dropped from the client build entirely.
+ * published source directly — the SAME seam the API uses (published-source),
+ * so SSR/UI and /api/v1 never disagree: both serve committed data by default
+ * and both serve the release snapshot when release mode is on. No self-HTTP,
+ * and Vite's static replacement drops the dynamic import (and the data behind
+ * it) from the client build entirely.
*
* Client side, queryFns fetch the canonical JSON endpoints — the app is the
* first consumer of its own published API (/api/v1/tokens*).
*
- * Published data is immutable per snapshot (~90-day editorial cadence), so
- * staleTime/gcTime are Infinity: a new snapshot arrives as a new deployment
- * (later: a new Edge Config pointer), never as a background refetch.
+ * Published data is immutable per snapshot, so staleTime/gcTime are Infinity:
+ * a new snapshot arrives as a new deployment, or — in release mode — as the
+ * next SSR render reading a newer release, never as a background refetch.
*/
import { queryOptions } from "@tanstack/react-query"
import type { FrameworkDoc, IndexRow, TokenDoc } from "@/lib/schemas"
@@ -29,8 +31,8 @@ export const publishedIndexQuery = queryOptions({
queryKey: ["published", "index"],
queryFn: async (): Promise<{ tokens: IndexRow[] }> => {
if (import.meta.env.SSR) {
- const { getPublishedIndex } = await import("@/lib/server/published-data")
- return getPublishedIndex()
+ const { getIndex } = await import("@/lib/server/published-source")
+ return getIndex()
}
return fetchEnvelopeData("/api/v1/tokens")
},
@@ -42,10 +44,8 @@ export const publishedFrameworkQuery = queryOptions({
queryKey: ["published", "framework"],
queryFn: async (): Promise => {
if (import.meta.env.SSR) {
- const { getPublishedFramework } = await import(
- "@/lib/server/published-data"
- )
- return getPublishedFramework()
+ const { getFramework } = await import("@/lib/server/published-source")
+ return getFramework()
}
return fetchEnvelopeData("/api/v1/framework")
},
@@ -59,10 +59,8 @@ export const publishedTokenDocQuery = (tokenId: string) => {
queryKey: ["published", "token-doc", normalizedId],
queryFn: async (): Promise => {
if (import.meta.env.SSR) {
- const { getPublishedTokenDoc } = await import(
- "@/lib/server/published-data"
- )
- return getPublishedTokenDoc(normalizedId)
+ const { getTokenDoc } = await import("@/lib/server/published-source")
+ return getTokenDoc(normalizedId)
}
const res = await fetch(`/api/v1/tokens/${normalizedId}`)
if (res.status === 404) return null
From e75c14449f1c0b1468a7ca568da0fc8d60fbeb06 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 20:58:23 +0200
Subject: [PATCH 28/38] fix: surface release published_at and gate snapshots on
token-set completeness
---
src/lib/server/published-source.ts | 42 ++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index c244c12..9a71e96 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -48,6 +48,34 @@ type Bundle = {
tokens: Map
framework: FrameworkDoc
faq: { topics: FaqTopic[] }
+ /** The release's publication time (ISO) — distinct from content last_updated. */
+ publishedAt: string | null
+}
+
+/**
+ * Cross-file integrity: the manifest list, the index rows, and the token docs
+ * must all cover the SAME ids. Per-part schema validation can't catch a
+ * shape-valid but incomplete snapshot — e.g. an index row whose token doc is
+ * missing would link the dashboard to a /tokens/{id} that 404s. Throwing here
+ * is caught by the caller and falls back to committed data.
+ */
+function assertTokenSetsAgree(
+ manifest: Manifest,
+ index: { tokens: IndexRow[] },
+ tokens: Map
+): void {
+ const manifestIds = [...manifest.tokens].sort()
+ const indexIds = index.tokens.map((t) => t.id).sort()
+ const docIds = [...tokens.keys()].sort()
+ const agree =
+ manifestIds.length === indexIds.length &&
+ manifestIds.length === docIds.length &&
+ manifestIds.every((id, i) => id === indexIds[i] && id === docIds[i])
+ if (!agree) {
+ throw new Error(
+ `snapshot token sets disagree (manifest ${manifestIds.length}, index ${indexIds.length}, docs ${docIds.length})`
+ )
+ }
}
/** Module-level cache of the last successfully validated release bundle. */
@@ -102,6 +130,7 @@ async function fetchReleaseBundle(): Promise {
return null
}
const release = (await releaseRes.json()) as {
+ published_at?: string | null
assets?: Array<{ name?: string; url?: string }>
}
const asset = release.assets?.find((a) => a.name === SNAPSHOT_ASSET_NAME)
@@ -146,7 +175,16 @@ async function fetchReleaseBundle(): Promise {
tokens.set(parsed.id, parsed)
}
- return { manifest, index, tokens, framework, faq }
+ assertTokenSetsAgree(manifest, index, tokens)
+
+ return {
+ manifest,
+ index,
+ tokens,
+ framework,
+ faq,
+ publishedAt: release.published_at ?? null,
+ }
} catch (err) {
console.warn(
`[published-source] falling back to committed data: ${
@@ -197,7 +235,7 @@ export async function getProvenance(): Promise {
snapshot_id: bundle.manifest.snapshot_id,
commit_ref: resolveCommitRef(),
last_updated: bundle.manifest.last_updated,
- published_at: null,
+ published_at: bundle.publishedAt,
source: "release",
}
}
From 827e31b656256269cb725d20f2411c8919e534fd Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 21:57:36 +0200
Subject: [PATCH 29/38] fix: revalidate SSR published reads in release mode
instead of pinning the snapshot
---
src/lib/published-queries.ts | 37 +++++++++++++++++++++++++++++++++-
src/routes/__root.tsx | 5 +++--
src/routes/tokens/$tokenId.tsx | 4 ++--
3 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/src/lib/published-queries.ts b/src/lib/published-queries.ts
index baa4710..eb103e0 100644
--- a/src/lib/published-queries.ts
+++ b/src/lib/published-queries.ts
@@ -15,7 +15,12 @@
* a new snapshot arrives as a new deployment, or — in release mode — as the
* next SSR render reading a newer release, never as a background refetch.
*/
-import { queryOptions } from "@tanstack/react-query"
+import {
+ type FetchQueryOptions,
+ type QueryClient,
+ type QueryKey,
+ queryOptions,
+} from "@tanstack/react-query"
import type { FrameworkDoc, IndexRow, TokenDoc } from "@/lib/schemas"
async function fetchEnvelopeData(url: string): Promise {
@@ -27,6 +32,36 @@ async function fetchEnvelopeData(url: string): Promise {
return payload.data
}
+// Server-only. In release mode the published data can change within the process
+// lifetime (a new GitHub Release), so the shared QueryClient + staleTime:Infinity
+// would otherwise pin the first snapshot until restart. Statically false on the
+// client (import.meta.env.SSR), so client caching is unchanged.
+const RELEASE_MODE_SSR =
+ import.meta.env.SSR && process.env.OTF_PUBLISHED_RELEASE === "true"
+
+/**
+ * Ensure a published query is cached for this render. In release-mode SSR we
+ * force a revalidated read so the loader can't serve a process-pinned snapshot;
+ * the actual fetch is still deduped + 60s-cached by published-source, so this
+ * doesn't hammer GitHub. Committed mode and the client reuse the cached value
+ * (data is immutable per deploy there).
+ */
+export async function readPublished<
+ TQueryFnData,
+ TError,
+ TData,
+ TQueryKey extends QueryKey,
+>(
+ client: QueryClient,
+ options: FetchQueryOptions
+): Promise {
+ if (RELEASE_MODE_SSR) {
+ await client.fetchQuery({ ...options, staleTime: 0 })
+ return
+ }
+ await client.ensureQueryData(options)
+}
+
export const publishedIndexQuery = queryOptions({
queryKey: ["published", "index"],
queryFn: async (): Promise<{ tokens: IndexRow[] }> => {
diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx
index b38cd18..d73f797 100644
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -16,6 +16,7 @@ import { generateOpenGraphMetadata } from "@/lib/metadata"
import {
publishedFrameworkQuery,
publishedIndexQuery,
+ readPublished,
} from "@/lib/published-queries"
import { queryClient } from "@/lib/query-client"
import appCss from "../styles.css?url"
@@ -26,8 +27,8 @@ export const Route = createRootRoute({
// cache — ensure them before render, on server and client alike.
loader: async () => {
await Promise.all([
- queryClient.ensureQueryData(publishedIndexQuery),
- queryClient.ensureQueryData(publishedFrameworkQuery),
+ readPublished(queryClient, publishedIndexQuery),
+ readPublished(queryClient, publishedFrameworkQuery),
])
},
head: () => ({
diff --git a/src/routes/tokens/$tokenId.tsx b/src/routes/tokens/$tokenId.tsx
index e029097..5e0302e 100644
--- a/src/routes/tokens/$tokenId.tsx
+++ b/src/routes/tokens/$tokenId.tsx
@@ -1,7 +1,7 @@
import { createFileRoute } from "@tanstack/react-router"
import TokenDetail from "@/components/token-detail"
import { generateOpenGraphMetadata } from "@/lib/metadata"
-import { publishedTokenDocQuery } from "@/lib/published-queries"
+import { publishedTokenDocQuery, readPublished } from "@/lib/published-queries"
import { queryClient } from "@/lib/query-client"
import { getTokenById } from "@/lib/token-data"
@@ -9,7 +9,7 @@ export const Route = createFileRoute("/tokens/$tokenId")({
// The detail page reads the full composed token doc (metrics, criteria,
// evidence) synchronously from the query cache — ensure it before render.
loader: async ({ params }) => {
- await queryClient.ensureQueryData(publishedTokenDocQuery(params.tokenId))
+ await readPublished(queryClient, publishedTokenDocQuery(params.tokenId))
},
component: TokenDetailPage,
head: ({ params }) => {
From b54be437c8f75f0a79f545ef2b3eb79f2f8441cf Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 21:57:37 +0200
Subject: [PATCH 30/38] fix: cap API edge cache to the release revalidation
window in release mode
---
src/lib/server/published-source.ts | 2 +-
src/lib/server/token-api.ts | 22 ++++++++++++++--------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index 9a71e96..ffa2be4 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -93,7 +93,7 @@ let inFlight: Promise | null = null
* on OTF_CONTENT_TOKEN presence instead (no token → committed; correct for
* dev/test/CI). The graceful fallback below stays regardless.
*/
-function isReleaseEnabled(): boolean {
+export function isReleaseEnabled(): boolean {
return process.env.OTF_PUBLISHED_RELEASE === "true"
}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index 6f60e95..7b73176 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -17,16 +17,22 @@ import {
getIndex,
getProvenance,
getTokenDoc,
+ isReleaseEnabled,
} from "@/lib/server/published-source"
-// The published data is immutable for the life of a deploy (composed at build
-// time and content-hashed). Hosts purge their edge cache on each new deploy, so
-// we cache hard: after the first hit per edge node the CDN serves every
-// subsequent request and the function is never invoked. A request flood is
-// absorbed by the CDN, not paid for at the origin — this is the primary DoS
-// posture for a read-only API (see .tempor/docs/operations/api-hardening.md).
-const CACHE_OK =
- "public, max-age=300, s-maxage=86400, stale-while-revalidate=604800"
+// Cache posture depends on the data source.
+// - Committed / build-from-ref data is immutable for the life of the deploy, so
+// we cache hard at the edge: after the first hit per edge node the CDN serves
+// everything and the function is never invoked — a flood is absorbed by the
+// CDN, the primary DoS posture (see .tempor/docs/operations/api-hardening.md).
+// - In release mode the data can change WITHOUT a deploy (a new GitHub Release),
+// so a day-long edge cache would serve a stale snapshot. We cap it near the
+// source's revalidation window so a new snapshot propagates in ~a minute,
+// still mostly CDN-absorbed. (Eventual upgrade: a publish→app purge webhook —
+// instant propagation while keeping the long cache.)
+const CACHE_OK = isReleaseEnabled()
+ ? "public, max-age=30, s-maxage=60, stale-while-revalidate=60"
+ : "public, max-age=300, s-maxage=86400, stale-while-revalidate=604800"
// Misses (unknown ids) are cached briefly so a repeated bogus id can't hammer
// the function; short because an id can become valid on the next deploy.
const CACHE_MISS = "public, max-age=30, s-maxage=60"
From 015511ed00830798bfa510c5094cb2b3b3a52219 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Tue, 16 Jun 2026 23:27:48 +0200
Subject: [PATCH 31/38] fix: bound the release fetch with a timeout so a hung
GitHub falls back
---
src/lib/server/published-source.ts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index ffa2be4..6a036e6 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -40,6 +40,12 @@ const SNAPSHOT_ASSET_NAME = "snapshot.json"
const USER_AGENT = "otf-dashboard"
/** How long a validated release bundle is served before we revalidate. */
const CACHE_TTL_MS = 60_000
+/**
+ * Whole-operation budget for a release read (lookup + asset). A timeout aborts
+ * the in-flight fetch, which surfaces as the same fallback as any other failure
+ * — so a slow or hung GitHub can never block an SSR render.
+ */
+const REQUEST_TIMEOUT_MS = 8_000
/** A fully validated snapshot bundle composed from the release asset. */
type Bundle = {
@@ -116,7 +122,10 @@ function resolveCommitRef(): string {
async function fetchReleaseBundle(): Promise {
const token = process.env.OTF_CONTENT_TOKEN
try {
+ // One time budget shared across both fetches below.
+ const signal = AbortSignal.timeout(REQUEST_TIMEOUT_MS)
const releaseRes = await fetch(RELEASE_API_URL, {
+ signal,
headers: {
...(token ? { Authorization: `Bearer ${token}` } : {}),
Accept: "application/vnd.github+json",
@@ -142,6 +151,7 @@ async function fetchReleaseBundle(): Promise {
}
const assetRes = await fetch(asset.url, {
+ signal,
headers: {
...(token ? { Authorization: `Bearer ${token}` } : {}),
// The GitHub asset API returns the raw bytes only with this Accept.
From 852de963395a9de982d92d34ce8de0e54a281917 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Thu, 18 Jun 2026 17:52:51 +0200
Subject: [PATCH 32/38] feat: make the content repo overridable via
OTF_CONTENT_REPO for forks
---
scripts/build-data.ts | 12 ++++++++----
src/lib/server/published-source.ts | 6 ++++--
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/scripts/build-data.ts b/scripts/build-data.ts
index 8d9934f..9820cb0 100644
--- a/scripts/build-data.ts
+++ b/scripts/build-data.ts
@@ -73,15 +73,18 @@ async function resolveContentDir(): Promise<{
const token = process.env.OTF_CONTENT_TOKEN
if (!token) throw new Error("OTF_CONTENT_REF set but OTF_CONTENT_TOKEN missing")
+ // Content repo, overridable so a fork builds from its own content. The
+ // tarball extracts to "--/", so the prefix tracks the repo.
+ const repo = process.env.OTF_CONTENT_REPO ?? "aragon/otf-cms"
const tmp = mkdtempSync(join(tmpdir(), "otf-content-"))
const tarball = join(tmp, "otf-cms.tar.gz")
- console.log(`build-data: fetching otf-cms@${ref}`)
+ console.log(`build-data: fetching ${repo}@${ref}`)
// Native fetch — no shell. The token rides an Authorization header (never a
// command line), and the ref is URL-encoded into the path. GitHub's tarball
// API 302-redirects to a pre-signed codeload URL; fetch follows it.
const res = await fetch(
- `https://api.github.com/repos/aragon/otf-cms/tarball/${encodeURIComponent(ref as string)}`,
+ `https://api.github.com/repos/${repo}/tarball/${encodeURIComponent(ref as string)}`,
{
headers: {
Authorization: `Bearer ${token}`,
@@ -91,13 +94,14 @@ async function resolveContentDir(): Promise<{
}
)
if (!res.ok) {
- throw new Error(`fetch otf-cms@${ref} failed: ${res.status} ${res.statusText}`)
+ throw new Error(`fetch ${repo}@${ref} failed: ${res.status} ${res.statusText}`)
}
writeFileSync(tarball, Buffer.from(await res.arrayBuffer()))
// execFileSync with an args array — no shell, so no metacharacter injection.
execFileSync("tar", ["xzf", tarball, "-C", tmp], { stdio: "inherit" })
- const extracted = readdirSync(tmp).find((n) => n.startsWith("aragon-otf-cms-"))
+ const extractedPrefix = `${repo.replace("/", "-")}-`
+ const extracted = readdirSync(tmp).find((n) => n.startsWith(extractedPrefix))
if (!extracted) throw new Error("tarball did not contain the expected root")
return {
contentDir: join(tmp, extracted, "content"),
diff --git a/src/lib/server/published-source.ts b/src/lib/server/published-source.ts
index 6a036e6..675c3f5 100644
--- a/src/lib/server/published-source.ts
+++ b/src/lib/server/published-source.ts
@@ -34,8 +34,10 @@ import {
getPublishedTokenDoc as getCommittedTokenDoc,
} from "@/lib/server/published-data"
-const RELEASE_API_URL =
- "https://api.github.com/repos/aragon/otf-cms/releases/latest"
+// The content repo, overridable so a fork can read its own releases. Defaults
+// to the canonical Aragon repo.
+const CONTENT_REPO = process.env.OTF_CONTENT_REPO ?? "aragon/otf-cms"
+const RELEASE_API_URL = `https://api.github.com/repos/${CONTENT_REPO}/releases/latest`
const SNAPSHOT_ASSET_NAME = "snapshot.json"
const USER_AGENT = "otf-dashboard"
/** How long a validated release bundle is served before we revalidate. */
From db3326c24a3682615f901cfe730884d8b9724d07 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Thu, 18 Jun 2026 17:54:56 +0200
Subject: [PATCH 33/38] feat: add self-contained Vercel CLI deploy workflow (no
git-integration)
---
.github/workflows/deploy.yml | 103 +++++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+)
create mode 100644 .github/workflows/deploy.yml
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..4dba38f
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,103 @@
+name: Deploy
+
+# Self-contained Vercel deploy — no Vercel git-integration, so no contributor
+# needs Vercel membership. The Action deploys on behalf of one VERCEL_TOKEN,
+# building the app and uploading the prebuilt output via the Vercel CLI.
+#
+# Two ways in:
+# - workflow_dispatch: manual or cross-repo (otf-cms triggers a content
+# preview). Inputs pick the target and the otf-cms ref to build content from.
+# - push to main: production deploy of the app's own code. No content ref —
+# production content arrives at runtime from the published Release.
+#
+# Required repo secrets (your fork for testing, aragon/* for real):
+# VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID Vercel CLI auth + target
+# OTF_CONTENT_TOKEN read otf-cms for build-from-ref
+# Optional repo variable:
+# OTF_CONTENT_REPO defaults to aragon/otf-cms; set to /otf-cms on a fork
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ description: Vercel target
+ type: choice
+ options: [preview, production]
+ default: preview
+ content_ref:
+ description: otf-cms ref for a build-from-ref preview (blank = committed/runtime data)
+ type: string
+ default: ""
+ push:
+ branches: [main]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: deploy-${{ github.event.inputs.environment || 'production' }}-${{ github.event.inputs.content_ref || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ # The Vercel CLI reads these from the environment (equivalent to --token /
+ # project linking), so nothing sensitive is ever inlined into a run script.
+ env:
+ VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
+ VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
+ VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
+ TARGET: ${{ github.event.inputs.environment || 'production' }}
+ steps:
+ # Third-party actions pinned to full commit SHAs (supply-chain policy)
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+
+ - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
+
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+ with:
+ node-version: "22"
+
+ - run: pnpm install --frozen-lockfile
+
+ # Gate: never ship code that doesn't type-check or pass tests.
+ - run: pnpm type-check
+ - run: pnpm test
+
+ # Pin a specific version once confirmed on the fork; latest is fine while
+ # experimenting.
+ - name: Install Vercel CLI
+ run: pnpm add -g vercel@latest
+
+ - name: Pull Vercel project config
+ run: vercel pull --yes --environment="$TARGET"
+
+ # build-data reads OTF_CONTENT_REF: set → build-from-ref preview; blank →
+ # committed data (production, where content comes from the Release).
+ - name: Build
+ env:
+ OTF_CONTENT_REF: ${{ github.event.inputs.content_ref }}
+ OTF_CONTENT_TOKEN: ${{ secrets.OTF_CONTENT_TOKEN }}
+ OTF_CONTENT_REPO: ${{ vars.OTF_CONTENT_REPO }}
+ run: |
+ if [ "$TARGET" = production ]; then
+ vercel build --prod
+ else
+ vercel build
+ fi
+
+ - name: Deploy prebuilt output
+ id: deploy
+ run: |
+ if [ "$TARGET" = production ]; then
+ url=$(vercel deploy --prebuilt --prod)
+ else
+ url=$(vercel deploy --prebuilt)
+ fi
+ echo "url=$url" >> "$GITHUB_OUTPUT"
+
+ - name: Summary
+ env:
+ URL: ${{ steps.deploy.outputs.url }}
+ run: |
+ echo "Deployed ($TARGET): $URL" >> "$GITHUB_STEP_SUMMARY"
From d59979f11faf6b345f6aa45ed04a71b82fadbb6c Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Thu, 18 Jun 2026 18:03:33 +0200
Subject: [PATCH 34/38] feat: support posting preview URL back to the
triggering content PR
---
.github/workflows/deploy.yml | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4dba38f..f85b654 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -28,6 +28,14 @@ on:
description: otf-cms ref for a build-from-ref preview (blank = committed/runtime data)
type: string
default: ""
+ comment_repo:
+ description: "owner/repo of a PR to post the preview URL back to (optional, e.g. the otf-cms content PR)"
+ type: string
+ default: ""
+ comment_pr:
+ description: PR number in comment_repo to post the preview URL to (optional)
+ type: string
+ default: ""
push:
branches: [main]
@@ -101,3 +109,17 @@ jobs:
URL: ${{ steps.deploy.outputs.url }}
run: |
echo "Deployed ($TARGET): $URL" >> "$GITHUB_STEP_SUMMARY"
+
+ # When triggered by a content PR (otf-cms), post the preview link back so
+ # the editor sees it on their PR. Needs CMS_COMMENT_TOKEN with PR-comment
+ # access on comment_repo. Values arrive via env, never inlined into run.
+ - name: Post preview URL to the content PR
+ if: ${{ github.event.inputs.comment_pr != '' && github.event.inputs.environment == 'preview' }}
+ env:
+ GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
+ COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
+ COMMENT_PR: ${{ github.event.inputs.comment_pr }}
+ URL: ${{ steps.deploy.outputs.url }}
+ run: |
+ gh pr comment "$COMMENT_PR" --repo "$COMMENT_REPO" \
+ --body "Rendered preview of this content: $URL"
From 2d66b5c8937bd5292daccb76a857ea524590b644 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Thu, 18 Jun 2026 19:20:40 +0200
Subject: [PATCH 35/38] fix: confirm settings on first deploy of a fresh Vercel
project
---
.github/workflows/deploy.yml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index f85b654..807b1c9 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -96,11 +96,13 @@ jobs:
- name: Deploy prebuilt output
id: deploy
+ # --yes confirms default settings for a never-deployed project (sets
+ # skipAutoDetectionConfirmation) so a fresh project deploys non-interactively.
run: |
if [ "$TARGET" = production ]; then
- url=$(vercel deploy --prebuilt --prod)
+ url=$(vercel deploy --prebuilt --prod --yes)
else
- url=$(vercel deploy --prebuilt)
+ url=$(vercel deploy --prebuilt --yes)
fi
echo "url=$url" >> "$GITHUB_OUTPUT"
From 4517f14caa76fbe44fb47256a4040f3cf3be980b Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Thu, 18 Jun 2026 19:49:35 +0200
Subject: [PATCH 36/38] feat: live preview status comment + teardown-on-close
in deploy workflow
---
.github/workflows/deploy.yml | 103 +++++++++++++++++++++++++++++------
1 file changed, 86 insertions(+), 17 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 807b1c9..8eb3083 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -4,21 +4,32 @@ name: Deploy
# needs Vercel membership. The Action deploys on behalf of one VERCEL_TOKEN,
# building the app and uploading the prebuilt output via the Vercel CLI.
#
-# Two ways in:
+# Ways in:
# - workflow_dispatch: manual or cross-repo (otf-cms triggers a content
-# preview). Inputs pick the target and the otf-cms ref to build content from.
-# - push to main: production deploy of the app's own code. No content ref —
-# production content arrives at runtime from the published Release.
+# preview, or a teardown when the content PR closes).
+# - push to main: production deploy of the app's own code. Production content
+# arrives at runtime from the published Release.
+#
+# When a content preview is requested with comment_repo/comment_pr, it posts a
+# single status comment on that PR and updates it through the lifecycle
+# (generating → ready/failed), mimicking a native Vercel PR comment. On
+# action=teardown it removes that PR's preview deployment.
#
# Required repo secrets (your fork for testing, aragon/* for real):
# VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID Vercel CLI auth + target
# OTF_CONTENT_TOKEN read otf-cms for build-from-ref
+# CMS_COMMENT_TOKEN comment on the content PR
# Optional repo variable:
# OTF_CONTENT_REPO defaults to aragon/otf-cms; set to /otf-cms on a fork
on:
workflow_dispatch:
inputs:
+ action:
+ description: deploy or teardown
+ type: choice
+ options: [deploy, teardown]
+ default: deploy
environment:
description: Vercel target
type: choice
@@ -29,11 +40,11 @@ on:
type: string
default: ""
comment_repo:
- description: "owner/repo of a PR to post the preview URL back to (optional, e.g. the otf-cms content PR)"
+ description: "owner/repo of a PR to post status to (optional, e.g. the otf-cms content PR)"
type: string
default: ""
comment_pr:
- description: PR number in comment_repo to post the preview URL to (optional)
+ description: PR number in comment_repo to post status to (optional)
type: string
default: ""
push:
@@ -43,11 +54,12 @@ permissions:
contents: read
concurrency:
- group: deploy-${{ github.event.inputs.environment || 'production' }}-${{ github.event.inputs.content_ref || github.ref }}
+ group: deploy-${{ github.event.inputs.comment_pr || github.event.inputs.environment || github.ref }}
cancel-in-progress: true
jobs:
deploy:
+ if: ${{ github.event.inputs.action != 'teardown' }}
runs-on: ubuntu-latest
# The Vercel CLI reads these from the environment (equivalent to --token /
# project linking), so nothing sensitive is ever inlined into a run script.
@@ -56,6 +68,7 @@ jobs:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
TARGET: ${{ github.event.inputs.environment || 'production' }}
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
# Third-party actions pinned to full commit SHAs (supply-chain policy)
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
@@ -68,6 +81,22 @@ jobs:
- run: pnpm install --frozen-lockfile
+ # Status comment: post "generating" up front so the editor sees the build
+ # is underway (native-Vercel-bot feel). Captures the comment id to update.
+ - name: Open status comment
+ id: comment
+ if: ${{ github.event.inputs.comment_pr != '' }}
+ env:
+ GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
+ COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
+ COMMENT_PR: ${{ github.event.inputs.comment_pr }}
+ CONTENT_REF: ${{ github.event.inputs.content_ref }}
+ run: |
+ printf -v body '### 🔄 Preview — building…\nFrom content branch `%s`. ([build logs](%s))' \
+ "${CONTENT_REF:-this content}" "$RUN_URL"
+ id=$(gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" -f body="$body" --jq '.id')
+ echo "id=$id" >> "$GITHUB_OUTPUT"
+
# Gate: never ship code that doesn't type-check or pass tests.
- run: pnpm type-check
- run: pnpm test
@@ -105,23 +134,63 @@ jobs:
url=$(vercel deploy --prebuilt --yes)
fi
echo "url=$url" >> "$GITHUB_OUTPUT"
+ echo "Deployed ($TARGET): $url" >> "$GITHUB_STEP_SUMMARY"
- - name: Summary
+ # Finalize the status comment — runs even if the build/deploy failed, so a
+ # broken preview is surfaced on the PR instead of failing silently.
+ - name: Finalize status comment
+ if: ${{ always() && github.event.inputs.comment_pr != '' }}
env:
+ GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
+ COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
+ COMMENT_PR: ${{ github.event.inputs.comment_pr }}
+ COMMENT_ID: ${{ steps.comment.outputs.id }}
URL: ${{ steps.deploy.outputs.url }}
+ CONTENT_REF: ${{ github.event.inputs.content_ref }}
+ DEPLOY_OK: ${{ steps.deploy.outcome == 'success' }}
run: |
- echo "Deployed ($TARGET): $URL" >> "$GITHUB_STEP_SUMMARY"
+ if [ "$DEPLOY_OK" = "true" ] && [ -n "$URL" ]; then
+ printf -v body '### ✅ Preview ready\nContent branch `%s`.\n\n**👉 [Open the preview](%s)**' \
+ "${CONTENT_REF:-this content}" "$URL"
+ else
+ printf -v body '### ❌ Preview build failed\nContent branch `%s`. [See logs](%s)' \
+ "${CONTENT_REF:-this content}" "$RUN_URL"
+ fi
+ if [ -n "$COMMENT_ID" ]; then
+ gh api -X PATCH "repos/$COMMENT_REPO/issues/comments/$COMMENT_ID" -f body="$body"
+ else
+ gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" -f body="$body"
+ fi
- # When triggered by a content PR (otf-cms), post the preview link back so
- # the editor sees it on their PR. Needs CMS_COMMENT_TOKEN with PR-comment
- # access on comment_repo. Values arrive via env, never inlined into run.
- - name: Post preview URL to the content PR
- if: ${{ github.event.inputs.comment_pr != '' && github.event.inputs.environment == 'preview' }}
+ teardown:
+ if: ${{ github.event.inputs.action == 'teardown' }}
+ runs-on: ubuntu-latest
+ env:
+ VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
+ VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
+ VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
+ steps:
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+ with:
+ node-version: "22"
+
+ - name: Install Vercel CLI
+ run: npm i -g vercel@latest
+
+ # Find the preview URL we posted on the (now-closed) content PR and remove
+ # that deployment, then note it on the PR.
+ - name: Remove preview deployment
env:
GH_TOKEN: ${{ secrets.CMS_COMMENT_TOKEN }}
COMMENT_REPO: ${{ github.event.inputs.comment_repo }}
COMMENT_PR: ${{ github.event.inputs.comment_pr }}
- URL: ${{ steps.deploy.outputs.url }}
run: |
- gh pr comment "$COMMENT_PR" --repo "$COMMENT_REPO" \
- --body "Rendered preview of this content: $URL"
+ host=$(gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" \
+ --jq '[.[].body | capture("https://(?[a-z0-9.-]+\\.vercel\\.app)")? | .h] | map(select(. != null)) | last // empty')
+ if [ -n "$host" ]; then
+ vercel rm "$host" --yes || true
+ gh api "repos/$COMMENT_REPO/issues/$COMMENT_PR/comments" \
+ -f body="🗑️ Preview torn down (content PR closed)."
+ else
+ echo "No preview URL found on PR #$COMMENT_PR — nothing to remove."
+ fi
From df5d18dc27062c837a57619ee63627498dfaf0a3 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 19 Jun 2026 18:23:06 +0200
Subject: [PATCH 37/38] Add OpenAPI contract, discovery root, and ETag to
/api/v1
---
.gitignore | 2 +
src/lib/server/openapi.ts | 204 +++++++++++++++++++++++++++
src/lib/server/token-api.ts | 161 ++++++++++++++++++---
src/routeTree.gen.ts | 42 ++++++
src/routes/api.v1.faq.ts | 2 +-
src/routes/api.v1.framework.ts | 2 +-
src/routes/api.v1.index[.]json.ts | 19 +++
src/routes/api.v1.openapi[.]json.ts | 19 +++
src/routes/api.v1.tokens.$tokenId.ts | 2 +-
src/routes/api.v1.tokens.ts | 2 +-
tests/api-endpoints.test.ts | 160 +++++++++++++++++++++
11 files changed, 593 insertions(+), 22 deletions(-)
create mode 100644 src/lib/server/openapi.ts
create mode 100644 src/routes/api.v1.index[.]json.ts
create mode 100644 src/routes/api.v1.openapi[.]json.ts
diff --git a/.gitignore b/.gitignore
index 3dff5d5..b1cff0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ output
.agents
.tempor
.playwright-mcp
+.env.otf-app-secrets
+.pnpm-store
diff --git a/src/lib/server/openapi.ts b/src/lib/server/openapi.ts
new file mode 100644
index 0000000..40b56b0
--- /dev/null
+++ b/src/lib/server/openapi.ts
@@ -0,0 +1,204 @@
+/**
+ * Machine-readable contract for the public read API.
+ *
+ * The OpenAPI 3.1 document is built FROM the vendored Zod read-models so the
+ * schema can never drift from the shapes the handlers actually serve: the
+ * component schemas are emitted by zod's native `z.toJSONSchema` (zod v4),
+ * not hand-duplicated. The handcrafted part is only the API surface that has
+ * no Zod source — paths, the `{data, provenance}` envelope wiring, and the
+ * response/status metadata.
+ */
+import { z } from "zod"
+import {
+ apiErrorSchema,
+ faqSchema,
+ frameworkDocSchema,
+ indexSchema,
+ provenanceSchema,
+ tokenDocSchema,
+} from "@/lib/schemas"
+
+/** OpenAPI `components.schemas` ids. Kept stable — codegen consumers $ref these. */
+const SCHEMA_IDS = {
+ index: "TokenIndex",
+ tokenDoc: "TokenDoc",
+ framework: "FrameworkDoc",
+ faq: "Faq",
+ provenance: "Provenance",
+ apiError: "ApiError",
+} as const
+
+/** `#/components/schemas/` ref to a named component. */
+function ref(id: string): { $ref: string } {
+ return { $ref: `#/components/schemas/${id}` }
+}
+
+/**
+ * Emit `components.schemas` from the Zod read-models via zod-native JSON Schema
+ * conversion. Registering each top-level schema with an id makes zod cross-link
+ * reused subschemas with `#/components/schemas/` $refs; subschemas that are
+ * not registered are inlined. We strip the per-schema `$schema`/`$id` dialect
+ * keys zod stamps on, which OpenAPI 3.1 does not want on component objects.
+ */
+function buildComponentSchemas(): Record {
+ const registry = z.registry<{ id: string }>()
+ registry.add(indexSchema, { id: SCHEMA_IDS.index })
+ registry.add(tokenDocSchema, { id: SCHEMA_IDS.tokenDoc })
+ registry.add(frameworkDocSchema, { id: SCHEMA_IDS.framework })
+ registry.add(faqSchema, { id: SCHEMA_IDS.faq })
+ registry.add(provenanceSchema, { id: SCHEMA_IDS.provenance })
+ registry.add(apiErrorSchema, { id: SCHEMA_IDS.apiError })
+
+ const { schemas } = z.toJSONSchema(registry, {
+ uri: (id) => `#/components/schemas/${id}`,
+ // OpenAPI 3.1 aligns with JSON Schema 2020-12; keep refs as plain pointers.
+ target: "draft-2020-12",
+ })
+
+ const cleaned: Record = {}
+ for (const [id, schema] of Object.entries(schemas)) {
+ const { $schema, $id, ...rest } = schema as Record
+ cleaned[id] = rest
+ }
+ return cleaned
+}
+
+/** The `{ data, provenance }` success envelope wrapping a named data schema. */
+function envelope(dataRef: { $ref: string }): Record {
+ return {
+ type: "object",
+ properties: {
+ data: dataRef,
+ provenance: ref(SCHEMA_IDS.provenance),
+ },
+ required: ["data", "provenance"],
+ additionalProperties: false,
+ }
+}
+
+/** A 200 response serving the envelope around `dataRef`. */
+function okEnvelope(description: string, dataRef: { $ref: string }) {
+ return {
+ "200": {
+ description,
+ content: { "application/json": { schema: envelope(dataRef) } },
+ },
+ }
+}
+
+/** The shared `{ error: { code, message } }` response for a status code. */
+function errorResponse(description: string) {
+ return {
+ description,
+ content: {
+ "application/json": { schema: ref(SCHEMA_IDS.apiError) },
+ },
+ }
+}
+
+const NOT_MODIFIED = {
+ "304": {
+ description:
+ "Not Modified — the client's `If-None-Match` matched the current `ETag`. No body.",
+ },
+} as const
+
+/**
+ * Build the OpenAPI 3.1 document for the four public GET endpoints plus the
+ * discovery root. Pure and deterministic for a given build of the schemas.
+ */
+export function buildOpenApiDocument(): Record {
+ return {
+ openapi: "3.1.0",
+ info: {
+ title: "Ownership Token Framework API",
+ version: "v1",
+ description:
+ "Structured, evidence-backed analysis of how tokenholder-owned crypto " +
+ "protocols are. Read-only JSON, no auth. Every response is " +
+ "`{ data, provenance }`; errors are `{ error: { code, message } }`.",
+ },
+ servers: [{ url: "/api/v1" }],
+ paths: {
+ "/": {
+ get: {
+ operationId: "getDiscoveryRoot",
+ summary:
+ "API discovery root: version, endpoints, schema, and guides.",
+ responses: {
+ "200": {
+ description: "Discovery document.",
+ content: { "application/json": { schema: { type: "object" } } },
+ },
+ },
+ },
+ },
+ "/tokens": {
+ get: {
+ operationId: "getTokens",
+ summary: "Index of all analyzed tokens.",
+ responses: {
+ ...okEnvelope(
+ "Token index wrapped in a provenance envelope.",
+ ref(SCHEMA_IDS.index)
+ ),
+ ...NOT_MODIFIED,
+ },
+ },
+ },
+ "/tokens/{id}": {
+ get: {
+ operationId: "getToken",
+ summary: "Full analysis for one token.",
+ parameters: [
+ {
+ name: "id",
+ in: "path",
+ required: true,
+ description: "Lowercase token id, e.g. `ldo`.",
+ schema: { type: "string" },
+ },
+ ],
+ responses: {
+ ...okEnvelope(
+ "Composed token doc wrapped in a provenance envelope.",
+ ref(SCHEMA_IDS.tokenDoc)
+ ),
+ ...NOT_MODIFIED,
+ "404": errorResponse("No published token with that id."),
+ },
+ },
+ },
+ "/framework": {
+ get: {
+ operationId: "getFramework",
+ summary:
+ "The evaluation framework: metric and criterion definitions.",
+ responses: {
+ ...okEnvelope(
+ "Framework doc wrapped in a provenance envelope.",
+ ref(SCHEMA_IDS.framework)
+ ),
+ ...NOT_MODIFIED,
+ },
+ },
+ },
+ "/faq": {
+ get: {
+ operationId: "getFaq",
+ summary: "Framework and methodology Q&A.",
+ responses: {
+ ...okEnvelope(
+ "FAQ doc wrapped in a provenance envelope.",
+ ref(SCHEMA_IDS.faq)
+ ),
+ ...NOT_MODIFIED,
+ },
+ },
+ },
+ },
+ components: {
+ schemas: buildComponentSchemas(),
+ },
+ }
+}
diff --git a/src/lib/server/token-api.ts b/src/lib/server/token-api.ts
index 7b73176..14f0a1b 100644
--- a/src/lib/server/token-api.ts
+++ b/src/lib/server/token-api.ts
@@ -11,6 +11,8 @@
* route. APP-796's "{symbol}" wording resolves to this id (symbols lowercase
* to ids for all current tokens).
*/
+import type { Provenance } from "@/lib/schemas"
+import { buildOpenApiDocument } from "@/lib/server/openapi"
import {
getFaq,
getFramework,
@@ -37,6 +39,19 @@ const CACHE_OK = isReleaseEnabled()
// the function; short because an id can become valid on the next deploy.
const CACHE_MISS = "public, max-age=30, s-maxage=60"
+function baseHeaders(cacheControl: string): Record {
+ return {
+ "Content-Type": "application/json",
+ "Cache-Control": cacheControl,
+ // Public, read-only data with no credentials — a wildcard origin is safe
+ // and keeps CORS from being a footgun for consumers.
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
+ // Never let a client sniff the response into another content type.
+ "X-Content-Type-Options": "nosniff",
+ }
+}
+
function jsonResponse(
body: unknown,
status = 200,
@@ -44,16 +59,67 @@ function jsonResponse(
): Response {
return new Response(JSON.stringify(body), {
status,
- headers: {
- "Content-Type": "application/json",
- "Cache-Control": cacheControl,
- // Public, read-only data with no credentials — a wildcard origin is safe
- // and keeps CORS from being a footgun for consumers.
- "Access-Control-Allow-Origin": "*",
- "Access-Control-Allow-Methods": "GET, OPTIONS",
- // Never let a client sniff the response into another content type.
- "X-Content-Type-Options": "nosniff",
- },
+ headers: baseHeaders(cacheControl),
+ })
+}
+
+/**
+ * A strong validator over the snapshot identity. Every 200 body is fully
+ * determined by the snapshot it was composed from, so the snapshot_id is a
+ * sound ETag: identical snapshot ⇒ byte-identical body. Quoted per RFC 9110.
+ */
+function snapshotEtag(provenance: Provenance): string {
+ return `"${provenance.snapshot_id}"`
+}
+
+/**
+ * Does the request's `If-None-Match` already hold this `etag`? Handles the
+ * comma-separated list form and the `*` wildcard. Conservative: any parse
+ * oddity simply yields false (we serve the full body), never a wrong 304.
+ */
+function ifNoneMatchSatisfied(
+ request: Request | undefined,
+ etag: string
+): boolean {
+ const header = request?.headers.get("If-None-Match")
+ if (!header) {
+ return false
+ }
+ if (header.trim() === "*") {
+ return true
+ }
+ return (
+ header
+ .split(",")
+ .map((tag) => tag.trim())
+ // Compare ignoring a weak prefix; our validator is strong.
+ .map((tag) => (tag.startsWith("W/") ? tag.slice(2) : tag))
+ .includes(etag)
+ )
+}
+
+/**
+ * Build a 200 envelope response carrying an `ETag` derived from the snapshot,
+ * or a bodyless `304 Not Modified` when the client's `If-None-Match` already
+ * matches. Cache-Control still rides along on the 304 so the validator's
+ * freshness lifetime is refreshed.
+ */
+function envelopeResponse(
+ data: unknown,
+ provenance: Provenance,
+ request?: Request,
+ cacheControl = CACHE_OK
+): Response {
+ const etag = snapshotEtag(provenance)
+ if (ifNoneMatchSatisfied(request, etag)) {
+ return new Response(null, {
+ status: 304,
+ headers: { ...baseHeaders(cacheControl), ETag: etag },
+ })
+ }
+ return new Response(JSON.stringify({ data, provenance }), {
+ status: 200,
+ headers: { ...baseHeaders(cacheControl), ETag: etag },
})
}
@@ -92,28 +158,31 @@ export function handleMethodNotAllowed(): Response {
}
/** GET /api/v1/tokens — the published index (discovery + cross-token queries). */
-export async function handleGetTokens(): Promise {
+export async function handleGetTokens(request?: Request): Promise {
const [data, provenance] = await Promise.all([getIndex(), getProvenance()])
- return jsonResponse({ data, provenance })
+ return envelopeResponse(data, provenance, request)
}
/** GET /api/v1/framework — canonical metric/criteria definitions + anchors. */
-export async function handleGetFramework(): Promise {
+export async function handleGetFramework(request?: Request): Promise {
const [data, provenance] = await Promise.all([
getFramework(),
getProvenance(),
])
- return jsonResponse({ data, provenance })
+ return envelopeResponse(data, provenance, request)
}
/** GET /api/v1/faq — published framework/methodology Q&A. */
-export async function handleGetFaq(): Promise {
+export async function handleGetFaq(request?: Request): Promise {
const [data, provenance] = await Promise.all([getFaq(), getProvenance()])
- return jsonResponse({ data, provenance })
+ return envelopeResponse(data, provenance, request)
}
/** GET /api/v1/tokens/{id} — one composed token doc (the per-token reusable unit). */
-export async function handleGetToken(tokenId: string): Promise {
+export async function handleGetToken(
+ tokenId: string,
+ request?: Request
+): Promise {
const doc = await getTokenDoc(tokenId)
if (!doc) {
return jsonResponse(
@@ -127,5 +196,61 @@ export async function handleGetToken(tokenId: string): Promise {
CACHE_MISS
)
}
- return jsonResponse({ data: doc, provenance: await getProvenance() })
+ return envelopeResponse(doc, await getProvenance(), request)
+}
+
+/**
+ * GET /api/v1/openapi.json — the machine-readable contract for this API.
+ *
+ * Built from the vendored Zod read-models (see openapi.ts), so it tracks the
+ * served shapes automatically. The document is content-versioned by the active
+ * snapshot too, so it participates in the same ETag/conditional-GET flow.
+ */
+export async function handleGetOpenApi(request?: Request): Promise {
+ const provenance = await getProvenance()
+ const doc = buildOpenApiDocument()
+ const etag = snapshotEtag(provenance)
+ if (ifNoneMatchSatisfied(request, etag)) {
+ return new Response(null, {
+ status: 304,
+ headers: { ...baseHeaders(CACHE_OK), ETag: etag },
+ })
+ }
+ return new Response(JSON.stringify(doc), {
+ status: 200,
+ headers: { ...baseHeaders(CACHE_OK), ETag: etag },
+ })
+}
+
+/**
+ * GET /api/v1 (served as /api/v1/index.json) — discovery root. Points typed and
+ * programmatic consumers at the formal schema and the human/agent guides, and
+ * carries provenance like every other response.
+ */
+export async function handleGetDiscovery(request?: Request): Promise {
+ const provenance = await getProvenance()
+ const etag = snapshotEtag(provenance)
+ if (ifNoneMatchSatisfied(request, etag)) {
+ return new Response(null, {
+ status: 304,
+ headers: { ...baseHeaders(CACHE_OK), ETag: etag },
+ })
+ }
+ const body = {
+ name: "Ownership Token Framework API",
+ version: "v1",
+ endpoints: [
+ "/api/v1/tokens",
+ "/api/v1/tokens/{id}",
+ "/api/v1/framework",
+ "/api/v1/faq",
+ ],
+ schema: "/api/v1/openapi.json",
+ guides: ["/llms.txt", "/agent-guide.md"],
+ provenance,
+ }
+ return new Response(JSON.stringify(body), {
+ status: 200,
+ headers: { ...baseHeaders(CACHE_OK), ETag: etag },
+ })
}
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 4b42de8..082c8e9 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -13,6 +13,8 @@ import { Route as FaqRouteImport } from './routes/faq'
import { Route as IndexRouteImport } from './routes/index'
import { Route as TokensTokenIdRouteImport } from './routes/tokens/$tokenId'
import { Route as ApiV1TokensRouteImport } from './routes/api.v1.tokens'
+import { Route as ApiV1OpenapiDotjsonRouteImport } from './routes/api.v1.openapi[.]json'
+import { Route as ApiV1IndexDotjsonRouteImport } from './routes/api.v1.index[.]json'
import { Route as ApiV1FrameworkRouteImport } from './routes/api.v1.framework'
import { Route as ApiV1FaqRouteImport } from './routes/api.v1.faq'
import { Route as ApiV1TokensTokenIdRouteImport } from './routes/api.v1.tokens.$tokenId'
@@ -37,6 +39,16 @@ const ApiV1TokensRoute = ApiV1TokensRouteImport.update({
path: '/api/v1/tokens',
getParentRoute: () => rootRouteImport,
} as any)
+const ApiV1OpenapiDotjsonRoute = ApiV1OpenapiDotjsonRouteImport.update({
+ id: '/api/v1/openapi.json',
+ path: '/api/v1/openapi.json',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const ApiV1IndexDotjsonRoute = ApiV1IndexDotjsonRouteImport.update({
+ id: '/api/v1/index.json',
+ path: '/api/v1/index.json',
+ getParentRoute: () => rootRouteImport,
+} as any)
const ApiV1FrameworkRoute = ApiV1FrameworkRouteImport.update({
id: '/api/v1/framework',
path: '/api/v1/framework',
@@ -59,6 +71,8 @@ export interface FileRoutesByFullPath {
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/v1/faq': typeof ApiV1FaqRoute
'/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/index.json': typeof ApiV1IndexDotjsonRoute
+ '/api/v1/openapi.json': typeof ApiV1OpenapiDotjsonRoute
'/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
'/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
@@ -68,6 +82,8 @@ export interface FileRoutesByTo {
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/v1/faq': typeof ApiV1FaqRoute
'/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/index.json': typeof ApiV1IndexDotjsonRoute
+ '/api/v1/openapi.json': typeof ApiV1OpenapiDotjsonRoute
'/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
'/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
@@ -78,6 +94,8 @@ export interface FileRoutesById {
'/tokens/$tokenId': typeof TokensTokenIdRoute
'/api/v1/faq': typeof ApiV1FaqRoute
'/api/v1/framework': typeof ApiV1FrameworkRoute
+ '/api/v1/index.json': typeof ApiV1IndexDotjsonRoute
+ '/api/v1/openapi.json': typeof ApiV1OpenapiDotjsonRoute
'/api/v1/tokens': typeof ApiV1TokensRouteWithChildren
'/api/v1/tokens/$tokenId': typeof ApiV1TokensTokenIdRoute
}
@@ -89,6 +107,8 @@ export interface FileRouteTypes {
| '/tokens/$tokenId'
| '/api/v1/faq'
| '/api/v1/framework'
+ | '/api/v1/index.json'
+ | '/api/v1/openapi.json'
| '/api/v1/tokens'
| '/api/v1/tokens/$tokenId'
fileRoutesByTo: FileRoutesByTo
@@ -98,6 +118,8 @@ export interface FileRouteTypes {
| '/tokens/$tokenId'
| '/api/v1/faq'
| '/api/v1/framework'
+ | '/api/v1/index.json'
+ | '/api/v1/openapi.json'
| '/api/v1/tokens'
| '/api/v1/tokens/$tokenId'
id:
@@ -107,6 +129,8 @@ export interface FileRouteTypes {
| '/tokens/$tokenId'
| '/api/v1/faq'
| '/api/v1/framework'
+ | '/api/v1/index.json'
+ | '/api/v1/openapi.json'
| '/api/v1/tokens'
| '/api/v1/tokens/$tokenId'
fileRoutesById: FileRoutesById
@@ -117,6 +141,8 @@ export interface RootRouteChildren {
TokensTokenIdRoute: typeof TokensTokenIdRoute
ApiV1FaqRoute: typeof ApiV1FaqRoute
ApiV1FrameworkRoute: typeof ApiV1FrameworkRoute
+ ApiV1IndexDotjsonRoute: typeof ApiV1IndexDotjsonRoute
+ ApiV1OpenapiDotjsonRoute: typeof ApiV1OpenapiDotjsonRoute
ApiV1TokensRoute: typeof ApiV1TokensRouteWithChildren
}
@@ -150,6 +176,20 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ApiV1TokensRouteImport
parentRoute: typeof rootRouteImport
}
+ '/api/v1/openapi.json': {
+ id: '/api/v1/openapi.json'
+ path: '/api/v1/openapi.json'
+ fullPath: '/api/v1/openapi.json'
+ preLoaderRoute: typeof ApiV1OpenapiDotjsonRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/api/v1/index.json': {
+ id: '/api/v1/index.json'
+ path: '/api/v1/index.json'
+ fullPath: '/api/v1/index.json'
+ preLoaderRoute: typeof ApiV1IndexDotjsonRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/api/v1/framework': {
id: '/api/v1/framework'
path: '/api/v1/framework'
@@ -192,6 +232,8 @@ const rootRouteChildren: RootRouteChildren = {
TokensTokenIdRoute: TokensTokenIdRoute,
ApiV1FaqRoute: ApiV1FaqRoute,
ApiV1FrameworkRoute: ApiV1FrameworkRoute,
+ ApiV1IndexDotjsonRoute: ApiV1IndexDotjsonRoute,
+ ApiV1OpenapiDotjsonRoute: ApiV1OpenapiDotjsonRoute,
ApiV1TokensRoute: ApiV1TokensRouteWithChildren,
}
export const routeTree = rootRouteImport
diff --git a/src/routes/api.v1.faq.ts b/src/routes/api.v1.faq.ts
index 6664e86..c04aba6 100644
--- a/src/routes/api.v1.faq.ts
+++ b/src/routes/api.v1.faq.ts
@@ -8,7 +8,7 @@ import {
export const Route = createFileRoute("/api/v1/faq")({
server: {
handlers: {
- GET: () => handleGetFaq(),
+ GET: ({ request }) => handleGetFaq(request),
OPTIONS: () => handleOptions(),
POST: () => handleMethodNotAllowed(),
PUT: () => handleMethodNotAllowed(),
diff --git a/src/routes/api.v1.framework.ts b/src/routes/api.v1.framework.ts
index 01ac833..6cc1b39 100644
--- a/src/routes/api.v1.framework.ts
+++ b/src/routes/api.v1.framework.ts
@@ -8,7 +8,7 @@ import {
export const Route = createFileRoute("/api/v1/framework")({
server: {
handlers: {
- GET: () => handleGetFramework(),
+ GET: ({ request }) => handleGetFramework(request),
OPTIONS: () => handleOptions(),
POST: () => handleMethodNotAllowed(),
PUT: () => handleMethodNotAllowed(),
diff --git a/src/routes/api.v1.index[.]json.ts b/src/routes/api.v1.index[.]json.ts
new file mode 100644
index 0000000..052b1eb
--- /dev/null
+++ b/src/routes/api.v1.index[.]json.ts
@@ -0,0 +1,19 @@
+import { createFileRoute } from "@tanstack/react-router"
+import {
+ handleGetDiscovery,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/v1/index.json")({
+ server: {
+ handlers: {
+ GET: ({ request }) => handleGetDiscovery(request),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
+ },
+ },
+})
diff --git a/src/routes/api.v1.openapi[.]json.ts b/src/routes/api.v1.openapi[.]json.ts
new file mode 100644
index 0000000..cccf312
--- /dev/null
+++ b/src/routes/api.v1.openapi[.]json.ts
@@ -0,0 +1,19 @@
+import { createFileRoute } from "@tanstack/react-router"
+import {
+ handleGetOpenApi,
+ handleMethodNotAllowed,
+ handleOptions,
+} from "@/lib/server/token-api"
+
+export const Route = createFileRoute("/api/v1/openapi.json")({
+ server: {
+ handlers: {
+ GET: ({ request }) => handleGetOpenApi(request),
+ OPTIONS: () => handleOptions(),
+ POST: () => handleMethodNotAllowed(),
+ PUT: () => handleMethodNotAllowed(),
+ PATCH: () => handleMethodNotAllowed(),
+ DELETE: () => handleMethodNotAllowed(),
+ },
+ },
+})
diff --git a/src/routes/api.v1.tokens.$tokenId.ts b/src/routes/api.v1.tokens.$tokenId.ts
index 24e6202..ecf3cdb 100644
--- a/src/routes/api.v1.tokens.$tokenId.ts
+++ b/src/routes/api.v1.tokens.$tokenId.ts
@@ -8,7 +8,7 @@ import {
export const Route = createFileRoute("/api/v1/tokens/$tokenId")({
server: {
handlers: {
- GET: ({ params }) => handleGetToken(params.tokenId),
+ GET: ({ params, request }) => handleGetToken(params.tokenId, request),
OPTIONS: () => handleOptions(),
POST: () => handleMethodNotAllowed(),
PUT: () => handleMethodNotAllowed(),
diff --git a/src/routes/api.v1.tokens.ts b/src/routes/api.v1.tokens.ts
index 7746b11..66c8162 100644
--- a/src/routes/api.v1.tokens.ts
+++ b/src/routes/api.v1.tokens.ts
@@ -8,7 +8,7 @@ import {
export const Route = createFileRoute("/api/v1/tokens")({
server: {
handlers: {
- GET: () => handleGetTokens(),
+ GET: ({ request }) => handleGetTokens(request),
OPTIONS: () => handleOptions(),
POST: () => handleMethodNotAllowed(),
PUT: () => handleMethodNotAllowed(),
diff --git a/tests/api-endpoints.test.ts b/tests/api-endpoints.test.ts
index 7751e37..20a43de 100644
--- a/tests/api-endpoints.test.ts
+++ b/tests/api-endpoints.test.ts
@@ -14,8 +14,10 @@ import {
tokenDocSchema,
} from "@/lib/schemas"
import {
+ handleGetDiscovery,
handleGetFaq,
handleGetFramework,
+ handleGetOpenApi,
handleGetToken,
handleGetTokens,
} from "@/lib/server/token-api"
@@ -110,3 +112,161 @@ describe("GET /api/tokens/{id}", () => {
}
)
})
+
+const snapshotId = readJson(join(generated, "manifest.json"))
+ .snapshot_id as string
+const currentEtag = `"${snapshotId}"`
+
+describe("ETag / conditional GET", () => {
+ it("stamps a snapshot-derived ETag on every 200 envelope response", async () => {
+ for (const res of [
+ await handleGetTokens(),
+ await handleGetFramework(),
+ await handleGetFaq(),
+ await handleGetToken("ldo"),
+ ]) {
+ expect(res.status).toBe(200)
+ expect(res.headers.get("ETag")).toBe(currentEtag)
+ }
+ })
+
+ it("returns 304 with no body when If-None-Match matches the ETag", async () => {
+ const req = new Request("https://x/api/v1/tokens", {
+ headers: { "If-None-Match": currentEtag },
+ })
+ const res = await handleGetTokens(req)
+ expect(res.status).toBe(304)
+ expect(res.headers.get("ETag")).toBe(currentEtag)
+ expect(await res.text()).toBe("")
+ })
+
+ it("honors the comma-separated and weak forms of If-None-Match", async () => {
+ const req = new Request("https://x/api/v1/framework", {
+ headers: { "If-None-Match": `"stale-x", W/${currentEtag}` },
+ })
+ expect((await handleGetFramework(req)).status).toBe(304)
+ })
+
+ it("honors the * wildcard", async () => {
+ const req = new Request("https://x/api/v1/faq", {
+ headers: { "If-None-Match": "*" },
+ })
+ expect((await handleGetFaq(req)).status).toBe(304)
+ })
+
+ it("serves the full 200 body when If-None-Match does not match", async () => {
+ const req = new Request("https://x/api/v1/tokens", {
+ headers: { "If-None-Match": '"some-other-snapshot"' },
+ })
+ const res = await handleGetTokens(req)
+ expect(res.status).toBe(200)
+ const payload = await body(res)
+ expect(() => indexSchema.parse(payload.data)).not.toThrow()
+ })
+
+ it("conditional GET works on the per-token endpoint too", async () => {
+ const req = new Request("https://x/api/v1/tokens/ldo", {
+ headers: { "If-None-Match": currentEtag },
+ })
+ const res = await handleGetToken("ldo", req)
+ expect(res.status).toBe(304)
+ expect(await res.text()).toBe("")
+ })
+})
+
+describe("GET /api/v1/openapi.json", () => {
+ it("is a valid-shaped OpenAPI 3.1 document with the four endpoints", async () => {
+ const res = await handleGetOpenApi()
+ expect(res.status).toBe(200)
+ expect(res.headers.get("Content-Type")).toBe("application/json")
+ expect(res.headers.get("ETag")).toBe(currentEtag)
+
+ const doc = await body(res)
+ expect(doc.openapi).toBe("3.1.0")
+ expect(doc.info.version).toBe("v1")
+ for (const path of ["/tokens", "/tokens/{id}", "/framework", "/faq"]) {
+ expect(doc.paths[path]?.get, path).toBeTruthy()
+ }
+ })
+
+ it("emits component schemas generated from the Zod read-models", async () => {
+ const doc = await body(await handleGetOpenApi())
+ for (const id of [
+ "TokenIndex",
+ "TokenDoc",
+ "FrameworkDoc",
+ "Faq",
+ "Provenance",
+ "ApiError",
+ ]) {
+ expect(doc.components.schemas[id], id).toBeTruthy()
+ }
+ // Generated, not hand-duplicated: the dialect keys zod stamps are stripped.
+ expect(doc.components.schemas.Provenance.$schema).toBeUndefined()
+ // The provenance source enum is carried through from the Zod schema.
+ expect(doc.components.schemas.Provenance.properties.source.enum).toEqual([
+ "generated",
+ "release",
+ ])
+ })
+
+ it("every $ref resolves to a declared component schema", async () => {
+ const doc = await body(await handleGetOpenApi())
+ const declared = new Set(Object.keys(doc.components.schemas))
+ const refs: string[] = []
+ const walk = (node: unknown) => {
+ if (Array.isArray(node)) {
+ for (const n of node) {
+ walk(n)
+ }
+ } else if (node && typeof node === "object") {
+ for (const [k, v] of Object.entries(node)) {
+ if (k === "$ref" && typeof v === "string") {
+ refs.push(v)
+ } else {
+ walk(v)
+ }
+ }
+ }
+ }
+ walk(doc)
+ expect(refs.length).toBeGreaterThan(0)
+ for (const r of refs) {
+ const name = r.replace("#/components/schemas/", "")
+ expect(declared.has(name), r).toBe(true)
+ }
+ })
+
+ it("returns 304 when If-None-Match matches", async () => {
+ const req = new Request("https://x/api/v1/openapi.json", {
+ headers: { "If-None-Match": currentEtag },
+ })
+ const res = await handleGetOpenApi(req)
+ expect(res.status).toBe(304)
+ expect(await res.text()).toBe("")
+ })
+})
+
+describe("GET /api/v1 discovery root", () => {
+ it("points at the schema and guides and carries provenance", async () => {
+ const res = await handleGetDiscovery()
+ expect(res.status).toBe(200)
+ expect(res.headers.get("ETag")).toBe(currentEtag)
+
+ const doc = await body(res)
+ expect(doc.version).toBe("v1")
+ expect(doc.schema).toBe("/api/v1/openapi.json")
+ expect(doc.guides).toEqual(["/llms.txt", "/agent-guide.md"])
+ expect(doc.endpoints).toContain("/api/v1/tokens")
+ expect(() => provenanceSchema.parse(doc.provenance)).not.toThrow()
+ })
+
+ it("returns 304 when If-None-Match matches", async () => {
+ const req = new Request("https://x/api/v1/index.json", {
+ headers: { "If-None-Match": currentEtag },
+ })
+ const res = await handleGetDiscovery(req)
+ expect(res.status).toBe(304)
+ expect(await res.text()).toBe("")
+ })
+})
From 298596f692c43af4c663f15ada0533f165f3e065 Mon Sep 17 00:00:00 2001
From: Kevin Davis
Date: Fri, 19 Jun 2026 18:31:01 +0200
Subject: [PATCH 38/38] Vendor TK schema and render TK/empty as placeholder
---
scripts/lib/compose-data.ts | 30 ++-
src/components/evidence-card.tsx | 15 +-
src/components/info-sidebar.tsx | 8 +-
src/components/metric-card.tsx | 37 ++--
src/components/site-header.tsx | 18 +-
src/components/token-detail.tsx | 7 +-
src/components/token-ownership-analytics.tsx | 13 +-
src/components/ui/evidence-link.tsx | 11 +-
src/lib/schemas/.vendor-lock.json | 11 +-
src/lib/schemas/atoms.ts | 11 +-
src/lib/schemas/common.ts | 17 +-
src/lib/schemas/index.ts | 3 +-
src/lib/schemas/readiness.ts | 207 +++++++++++++++++++
src/lib/utils.ts | 11 +
14 files changed, 347 insertions(+), 52 deletions(-)
create mode 100644 src/lib/schemas/readiness.ts
diff --git a/scripts/lib/compose-data.ts b/scripts/lib/compose-data.ts
index 161e235..6816022 100644
--- a/scripts/lib/compose-data.ts
+++ b/scripts/lib/compose-data.ts
@@ -21,6 +21,7 @@
*/
import { createHash } from "node:crypto"
import {
+ existsSync,
mkdirSync,
readdirSync,
readFileSync,
@@ -36,6 +37,17 @@ const generatedDir = join(root, "generated")
const readJson = (p: string): any => JSON.parse(readFileSync(p, "utf8"))
+/**
+ * Tolerant read for partial tokens: a token enters the set as soon as its
+ * identity file exists, but its criterion atoms / metric summaries may not
+ * exist yet (editors stand a token up progressively). A missing file is NOT a
+ * build error — it yields `fallback` so the doc composes fully with everything
+ * `unevaluated`/empty. The publish gate (bundle-snapshot) excludes such WIP
+ * tokens from Release; previews build on the partial data.
+ */
+const readJsonOr = (p: string, fallback: T): T =>
+ existsSync(p) ? (readJson(p) as T) : fallback
+
const SCORED_STATUSES = new Set(["positive", "warning", "at_risk"])
function getMetricScore(metric: any) {
@@ -91,17 +103,23 @@ export function composeAll(dir: string = contentDir) {
const metrics: any[] = []
for (const fm of framework) {
const metricDir = join(dir, "evaluations", tokenId, fm.id)
- const editorial = readJson(
- join(dir, "summaries", tokenId, `${fm.id}.json`)
+ // Missing summary → empty editorial (token still composing).
+ const editorial = readJsonOr<{ summary: string; tags: string[] }>(
+ join(dir, "summaries", tokenId, `${fm.id}.json`),
+ { summary: "", tags: [] }
)
const criteria = fm.criteria.map((fc: any) => {
- const atom = readJson(join(metricDir, `${fc.id}.json`))
+ // Missing criterion atom → unevaluated (no notes/evidence yet).
+ const atom = readJsonOr(join(metricDir, `${fc.id}.json`), {
+ status: "unevaluated",
+ notes: "",
+ })
const composed: any = {
id: fc.id,
name: atom.name ?? fc.name,
about: fc.about,
status: atom.status,
- notes: atom.notes,
+ notes: atom.notes ?? "",
}
if ("tags" in atom) composed.tags = atom.tags
if ("evidence" in atom) composed.evidence = atom.evidence
@@ -153,7 +171,9 @@ export function composeAll(dir: string = contentDir) {
// gate meaningful); changes exactly when published data changes. The future
// publish pipeline reuses this as the R2 snapshot key component.
const snapshotId = createHash("sha256")
- .update(JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials }))
+ .update(
+ JSON.stringify({ index, tokenDocs, frameworkDoc, faq, testimonials })
+ )
.digest("hex")
.slice(0, 16)
diff --git a/src/components/evidence-card.tsx b/src/components/evidence-card.tsx
index ce010f5..3a13abc 100644
--- a/src/components/evidence-card.tsx
+++ b/src/components/evidence-card.tsx
@@ -1,6 +1,7 @@
import ReactMarkdown from "react-markdown"
import remarkBreaks from "remark-breaks"
import type { Evidence, EvidenceUrl } from "@/lib/metrics-data"
+import { isPlaceholder } from "@/lib/utils"
import { EvidenceLink } from "./ui/evidence-link.tsx"
interface MarkdownComponentProps {
@@ -32,16 +33,20 @@ interface IEvidenceCardProps {
export const EvidenceCard: React.FC = (props) => {
const { evidence } = props
+ // "TK"/empty urls are placeholders from WIP tokens — never render them as
+ // live links (only the resolved ones are shown).
+ const urls = evidence.urls.filter((url) => !isPlaceholder(url.url))
+
return (
- {(evidence.name || evidence.summary) && (
+ {(!isPlaceholder(evidence.name) || !isPlaceholder(evidence.summary)) && (
- {evidence.name && (
+ {!isPlaceholder(evidence.name) && (
{evidence.name}
)}
- {evidence.summary && (
+ {!isPlaceholder(evidence.summary) && (
= (props) => {
)}
- {evidence.urls.map((url, index) => (
+ {urls.map((url, index) => (
- {url.name}
+ {isPlaceholder(url.name) ? url.url : url.name}
))}
diff --git a/src/components/info-sidebar.tsx b/src/components/info-sidebar.tsx
index f5b3b8e..46d66c3 100644
--- a/src/components/info-sidebar.tsx
+++ b/src/components/info-sidebar.tsx
@@ -6,7 +6,7 @@ import {
// @ts-expect-error by default it imports from cjs build and triggers server-side error
} from "@tabler/icons-react/dist/esm/tabler-icons-react.mjs"
import { useEffect, useState } from "react"
-import { copyToClipboard, truncateAddress } from "@/lib/utils"
+import { copyToClipboard, isPlaceholder, truncateAddress } from "@/lib/utils"
import type { TokenInfo } from "./token-detail"
import { Button } from "./ui/button"
import { ExplorerIcon } from "./ui/explore-icon.tsx"
@@ -100,7 +100,7 @@ export default function InfoSidebar({ token }: { token: TokenInfo }) {
)}
{truncateAddress(token.address)}
- {token.links.scan && (
+ {!isPlaceholder(token.links.scan) && (
)}
- {token.links.website && (
+ {!isPlaceholder(token.links.website) && (
)}
- {token.links.twitter && (
+ {!isPlaceholder(token.links.twitter) && (
- {metric.summary && (
+ {!isPlaceholder(metric.summary) && (
// div, not p: ReactMarkdown renders its own
and nested
// paragraphs are invalid HTML (causes hydration mismatches)
{match(criteria.notes)
- .with(P.string, (notes) => (
- //
-
-
!isPlaceholder(notes))),
+ (notes) => (
+ //
+
- {notes}
-
-
- ))
+
+ {notes}
+
+
+ )
+ )
.otherwise(() => null)}
{match(criteria.evidence)
.with(P.union(P.nullish, []), () => null)
diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx
index a14b205..9a3e1d0 100644
--- a/src/components/site-header.tsx
+++ b/src/components/site-header.tsx
@@ -24,7 +24,7 @@ import {
} from "@/components/ui/navigation-menu"
import { useTokenSearch } from "@/hooks/use-token-search"
import { getFrameworkBaseUrl } from "@/lib/framework"
-import { cn } from "@/lib/utils"
+import { cn, isPlaceholder } from "@/lib/utils"
export function SiteHeader() {
const [submitDialogOpen, setSubmitDialogOpen] = useState(false)
@@ -187,7 +187,14 @@ export function SiteHeader() {
to="/tokens/$tokenId"
>
-
+
{token.name.slice(0, 2)}
@@ -288,7 +295,12 @@ export function SiteHeader() {
to="/tokens/$tokenId"
>
-
+
{token.name.slice(0, 2)}
diff --git a/src/components/token-detail.tsx b/src/components/token-detail.tsx
index 1d2cc12..d408c54 100644
--- a/src/components/token-detail.tsx
+++ b/src/components/token-detail.tsx
@@ -16,7 +16,7 @@ import { useMarketData } from "@/hooks/use-market-data"
import { trackExpandAllCriteria } from "@/lib/analytics"
import { getMetricsByTokenId, type Metric } from "@/lib/metrics-data"
import { getTokenById } from "@/lib/token-data"
-import { formatUnixTimestamp } from "@/lib/utils"
+import { formatUnixTimestamp, isPlaceholder } from "@/lib/utils"
import AnalyticsContent from "./analytics-content"
import InfoSidebar from "./info-sidebar"
import { NewsletterSignup } from "./newsletter-signup.tsx"
@@ -73,7 +73,10 @@ function TokenHero({ token }: { token: TokenInfo }) {
-
+
{token.name.slice(0, 2)}
diff --git a/src/components/token-ownership-analytics.tsx b/src/components/token-ownership-analytics.tsx
index c3b2e00..4930617 100644
--- a/src/components/token-ownership-analytics.tsx
+++ b/src/components/token-ownership-analytics.tsx
@@ -60,7 +60,11 @@ import { type EnrichedToken, useMarketData } from "@/hooks/use-market-data"
import { useTokens } from "@/hooks/use-tokens"
import { CRITERIA_STATUS, getCriteriaStatus } from "@/lib/metrics-data"
import { getTokenOwnershipScore } from "@/lib/scoring"
-import { formatUnixTimestamp, truncateAddress } from "@/lib/utils"
+import {
+ formatUnixTimestamp,
+ isPlaceholder,
+ truncateAddress,
+} from "@/lib/utils"
function formatMarketCap(value?: number): string {
if (value == null) return "—"
@@ -159,7 +163,12 @@ const columns: ColumnDef[] = [
cell: ({ row }) => (
-
+
{row.original.name.slice(0, 2)}
diff --git a/src/components/ui/evidence-link.tsx b/src/components/ui/evidence-link.tsx
index e19dcc1..094a5cd 100644
--- a/src/components/ui/evidence-link.tsx
+++ b/src/components/ui/evidence-link.tsx
@@ -1,6 +1,6 @@
import { FileTextIcon, GithubIcon } from "lucide-react"
import type { ComponentProps } from "react"
-import { cn } from "@/lib/utils"
+import { cn, isPlaceholder } from "@/lib/utils"
import { ExplorerIcon } from "./explore-icon.tsx"
export type EvidenceLinkType =
@@ -15,7 +15,13 @@ interface IEvidenceLinkProps extends ComponentProps<"a"> {
}
export const EvidenceLink: React.FC = (props) => {
- const { type = "generic", className, children, ...otherProps } = props
+ const { type = "generic", className, children, href, ...otherProps } = props
+
+ // A "TK"/empty href is a placeholder from a WIP token — never emit a dead
+ // link (callers already filter these out; this is a defensive guard).
+ if (isPlaceholder(href)) {
+ return null
+ }
const renderIcon = () => {
switch (type) {
@@ -40,6 +46,7 @@ export const EvidenceLink: React.FC = (props) => {
"transition-colors duration-200",
className
)}
+ href={href}
rel="noopener noreferrer"
target="_blank"
{...otherProps}
diff --git a/src/lib/schemas/.vendor-lock.json b/src/lib/schemas/.vendor-lock.json
index f403405..865e057 100644
--- a/src/lib/schemas/.vendor-lock.json
+++ b/src/lib/schemas/.vendor-lock.json
@@ -1,11 +1,12 @@
{
"source": "aragon/otf-cms",
- "source_commit": "8170271c4873c0a3ca3f028e01dcc61dfba1589d",
+ "source_commit": "467c059f22c9f18746bdb23993df8adbac769410",
"files": {
- "src/lib/schemas/atoms.ts": "156caa321c5dc9641d42f84e41d8f771c0ae5c736bbf649accfca91e786bdf27",
- "src/lib/schemas/common.ts": "ea0c3fba07fd48b495f6cd0c177584df1249dfe0367738f51ef5b7bb1da1c2d2",
- "src/lib/schemas/index.ts": "77626d4b97d528032ba32b2152a80457ab3f77da06ef90db089b885228e96f2a",
+ "src/lib/schemas/atoms.ts": "fa37e43dc9a43f4fa4597160b789d5f1abfbef362d4310f465a89dbd32ae8caf",
+ "src/lib/schemas/common.ts": "f24a880ed2a539baaa51f7ad142e77be3f4c600ab8db063dcb9879689157d1f4",
+ "src/lib/schemas/index.ts": "3a7200ea0eacf042c31b1548d9ed82b2bad1387114fe7a11a705afedd952ee6b",
"src/lib/schemas/read-models.ts": "9af495412eb22c6ac7a9ced07e976b9e960582f46e4dcf2c4f2dcc6f51868041",
- "scripts/lib/compose-data.ts": "f271c040c4605bad94fc550dfeac94ff025878036ebb1176b948795fe7624346"
+ "src/lib/schemas/readiness.ts": "31597d72f8c66cc4734838a4556e78bb6871054cb244af5a43d4612bbdc29f4c",
+ "scripts/lib/compose-data.ts": "7644578dfa2afa5944c4160da7d35b4f42a9704c7f4834976736d49e1c869642"
}
}
diff --git a/src/lib/schemas/atoms.ts b/src/lib/schemas/atoms.ts
index c2d20ea..4f99732 100644
--- a/src/lib/schemas/atoms.ts
+++ b/src/lib/schemas/atoms.ts
@@ -6,7 +6,7 @@
* absent and produced at composition time (scripts/compose-data.mjs).
*/
import { z } from "zod"
-import { criteriaStatusSchema, evidenceSchema } from "./common"
+import { criteriaStatusSchema, evidenceSchema, tkUrlSchema } from "./common"
/** content/tokens/.json — registry atom: identity, display, chain data. */
export const tokenAtomSchema = z.strictObject({
@@ -15,14 +15,15 @@ export const tokenAtomSchema = z.strictObject({
name: z.string(),
symbol: z.string(),
address: z.string(),
- icon: z.string(),
+ /** Icon url, or "TK" while deferred (lenient so partial tokens compose). */
+ icon: tkUrlSchema,
description: z.string(),
infoDescription: z.string(),
network: z.string(),
links: z.strictObject({
- website: z.string(),
- twitter: z.string(),
- scan: z.string(),
+ website: tkUrlSchema,
+ twitter: tkUrlSchema,
+ scan: tkUrlSchema,
}),
/** Editorial provenance; future home is Git history (publish pipeline). */
lastUpdated: z.number(),
diff --git a/src/lib/schemas/common.ts b/src/lib/schemas/common.ts
index 3415fda..e9133e6 100644
--- a/src/lib/schemas/common.ts
+++ b/src/lib/schemas/common.ts
@@ -1,5 +1,20 @@
import { z } from "zod"
+/**
+ * Publish-readiness sentinel. A field is either a real value or the literal
+ * "TK" (a deferral marker borrowed from editorial usage). Schemas stay lenient
+ * so partial tokens still validate and previews build; the publish gate
+ * (schemas/readiness.ts) treats "TK" — like empty and `unevaluated` — as
+ * UNRESOLVED and excludes the token from Release.
+ */
+export const TK = "TK" as const
+
+/** A url field that may be deferred with the TK sentinel. */
+export const tkUrlSchema = z.union([z.url(), z.literal(TK)])
+
+/** A free-text field that may be deferred with the TK sentinel. */
+export const tkTextSchema = z.string()
+
/**
* Canonical criteria workflow statuses — the ONLY valid vocabulary.
* Non-canonical values are a validation failure by design (ADR 0002):
@@ -26,7 +41,7 @@ export const criteriaStatusSchema = z.enum([
export const evidenceUrlSchema = z.strictObject({
name: z.string(),
- url: z.string(),
+ url: tkUrlSchema,
type: z.enum(["docs", "explorer", "github", "vote", "website"]).optional(),
})
diff --git a/src/lib/schemas/index.ts b/src/lib/schemas/index.ts
index f9bc84b..a825e6a 100644
--- a/src/lib/schemas/index.ts
+++ b/src/lib/schemas/index.ts
@@ -2,10 +2,11 @@
* OTF data contract — a checked-in COPY of otf-cms's source (i.e. "vendored").
* DO NOT EDIT HERE: a change to this copy fails CI's drift check.
*
- * Source of truth: https://github.com/aragon/otf-cms (copied at 8170271c4873c0a3ca3f028e01dcc61dfba1589d).
+ * Source of truth: https://github.com/aragon/otf-cms (copied at 467c059f22c9f18746bdb23993df8adbac769410).
* To change it, edit the file in otf-cms, then refresh the copies here by
* re-running: node scripts/vendor-schemas.mjs
*/
export * from "./atoms"
export * from "./common"
export * from "./read-models"
+export * from "./readiness"
diff --git a/src/lib/schemas/readiness.ts b/src/lib/schemas/readiness.ts
new file mode 100644
index 0000000..9c0c586
--- /dev/null
+++ b/src/lib/schemas/readiness.ts
@@ -0,0 +1,207 @@
+/**
+ * Publish-readiness detector — the keystone of the two-tier (preview / Release)
+ * model. Given a COMPOSED token doc (read-model shape), it returns a granular
+ * list of every UNRESOLVED item. A token is publish-ready ⟺ that list is empty.
+ *
+ * "Unresolved" items carry a reason, and reasons split by SEVERITY:
+ * - BLOCKING (hold the token out of the production Release):
+ * - "tk": a field literally equal to the "TK" sentinel (explicit
+ * "not done" marker — the deliberate deferral signal)
+ * - "regression": a field that was non-empty in the last published Release
+ * and is now blank/removed (accidental-deletion guard; this
+ * reason is attached by the CI-side baseline diff, not here)
+ * - ADVISORY (surfaced on the PR for visibility, but shippable — legacy
+ * content is grandfathered, so these never gut the current board):
+ * - "empty": a field that is blank
+ * - "missing": a field absent from the doc
+ *
+ * `unevaluated` is NOT a gap: it's a complete verdict ("we have not
+ * evaluated"), tracked separately as coverage (see `coverage()`), never here.
+ *
+ * Hard-required identity (id/name/symbol) is enforced by Zod upstream, so a
+ * token can never compose without them — this layer governs the softer
+ * completeness (notes, evidence, optional identity, summaries) plus TK.
+ *
+ * Pure (no fs, no app imports) so the bundle gate, the preview app, and a CI
+ * comment can all call it. This module is vendored by the app verbatim — keep
+ * it dependency-light and self-contained.
+ */
+import { TK } from "./common"
+
+/** One unresolved field, addressed by a dotted path into the token doc. */
+export type UnresolvedItem = {
+ path: string
+ reason: "tk" | "empty" | "missing" | "regression"
+}
+
+/** Coverage stat for a token: how many criteria are evaluated vs `unevaluated`. */
+export type Coverage = { evaluated: number; unevaluated: number; total: number }
+
+/**
+ * Reasons that hold a token out of the production Release. Everything else is
+ * advisory — reported on the PR, but the token still publishes (grandfathered).
+ */
+export const BLOCKING_REASONS: ReadonlySet = new Set([
+ "tk",
+ "regression",
+])
+
+/** Identity fields that must be present, non-empty, and not "TK". */
+const IDENTITY_FIELDS = [
+ "id",
+ "coingeckoId",
+ "name",
+ "symbol",
+ "address",
+ "icon",
+ "description",
+ "infoDescription",
+ "network",
+] as const
+
+/** links.* sub-fields that must be present, non-empty, and not "TK". */
+const LINK_FIELDS = ["website", "twitter", "scan"] as const
+
+/** Statuses that don't require notes/evidence to be considered resolved. */
+const EXEMPT_STATUSES = new Set(["reference", "unevaluated"])
+
+const isTk = (v: unknown): boolean => v === TK
+const isBlank = (v: unknown): boolean =>
+ v === undefined || v === null || (typeof v === "string" && v.trim() === "")
+
+/**
+ * Classify a required string field. Returns the unresolved reason, or null if
+ * the field carries a real value. Order matters: TK is reported as "tk" even
+ * though it is also non-blank, so editors see the sentinel called out.
+ */
+function classifyText(v: unknown): UnresolvedItem["reason"] | null {
+ if (v === undefined) return "missing"
+ if (isTk(v)) return "tk"
+ if (isBlank(v)) return "empty"
+ return null
+}
+
+/** Classify a required url field (TK sentinel → "tk", blank → "empty"). */
+function classifyUrl(v: unknown): UnresolvedItem["reason"] | null {
+ if (v === undefined) return "missing"
+ if (isTk(v)) return "tk"
+ if (isBlank(v)) return "empty"
+ return null
+}
+
+/**
+ * Return every unresolved item in a composed token doc. Empty ⟺ publish-ready.
+ * `doc` is typed loosely on purpose: this runs over composer output that has
+ * not necessarily passed Zod yet (partial tokens are schema-valid but WIP).
+ */
+export function unresolved(doc: any): UnresolvedItem[] {
+ const items: UnresolvedItem[] = []
+
+ // 1. Identity fields: present, non-empty, not "TK".
+ for (const field of IDENTITY_FIELDS) {
+ const reason =
+ field === "icon" ? classifyUrl(doc?.[field]) : classifyText(doc?.[field])
+ if (reason) items.push({ path: field, reason })
+ }
+
+ // 2. links.* — url fields; a "TK" url is unresolved.
+ const links = doc?.links
+ if (isBlank(links) || typeof links !== "object") {
+ items.push({
+ path: "links",
+ reason: links === undefined ? "missing" : "empty",
+ })
+ } else {
+ for (const key of LINK_FIELDS) {
+ const reason = classifyUrl(links[key])
+ if (reason) items.push({ path: `links.${key}`, reason })
+ }
+ }
+
+ // 3. Metrics: each criterion status must be evaluated; notes + evidence must
+ // be resolved for any verdict that isn't reference/unevaluated; each
+ // metric summary must be non-empty / not-TK.
+ const metrics: any[] = Array.isArray(doc?.metrics) ? doc.metrics : []
+ for (const metric of metrics) {
+ const mId = metric?.id ?? "?"
+
+ const summaryReason = classifyText(metric?.summary)
+ if (summaryReason) {
+ items.push({ path: `metrics.${mId}.summary`, reason: summaryReason })
+ }
+
+ const criteria: any[] = Array.isArray(metric?.criteria)
+ ? metric.criteria
+ : []
+ for (const c of criteria) {
+ const cId = c?.id ?? "?"
+ const base = `metrics.${mId}.criteria.${cId}`
+ const status = c?.status
+
+ // `unevaluated` is a COMPLETE verdict ("we have not evaluated"), not a
+ // gap — it's tracked as coverage (see `coverage()`), never as unresolved.
+ // Notes/evidence are only required for real verdicts; reference and
+ // unevaluated are exempt.
+ if (!EXEMPT_STATUSES.has(status)) {
+ const notesReason = classifyText(c?.notes)
+ if (notesReason) {
+ items.push({ path: `${base}.notes`, reason: notesReason })
+ }
+ const evidence = c?.evidence
+ if (!Array.isArray(evidence) || evidence.length === 0) {
+ items.push({ path: `${base}.evidence`, reason: "empty" })
+ }
+ }
+ }
+ }
+
+ return items
+}
+
+/**
+ * Blocking subset of unresolved items — the ones that hold a token out of the
+ * production Release. Advisory items (empty/unevaluated/missing) are excluded.
+ * Pass `extra` to fold in items computed elsewhere (e.g. the CI baseline diff's
+ * "regression" items) before deciding readiness.
+ */
+export function blockingUnresolved(
+ doc: any,
+ extra: UnresolvedItem[] = []
+): UnresolvedItem[] {
+ return [...unresolved(doc), ...extra].filter((i) =>
+ BLOCKING_REASONS.has(i.reason)
+ )
+}
+
+/**
+ * A composed token doc is publish-ready ⟺ it has no BLOCKING unresolved items.
+ * Advisory gaps (legacy empty) are grandfathered and still ship. `extra` lets
+ * the caller include CI-computed regression items in the decision.
+ */
+export function isPublishReady(
+ doc: any,
+ extra: UnresolvedItem[] = []
+): boolean {
+ return blockingUnresolved(doc, extra).length === 0
+}
+
+/**
+ * Evaluation coverage for a token — how many criteria carry a real verdict vs
+ * are still `unevaluated`. This is informational ("12/18 evaluated"), NOT a
+ * gap: an `unevaluated` criterion is a complete, shippable answer.
+ */
+export function coverage(doc: any): Coverage {
+ const metrics: any[] = Array.isArray(doc?.metrics) ? doc.metrics : []
+ let unevaluated = 0
+ let total = 0
+ for (const metric of metrics) {
+ const criteria: any[] = Array.isArray(metric?.criteria)
+ ? metric.criteria
+ : []
+ for (const c of criteria) {
+ total++
+ if (c?.status === "unevaluated") unevaluated++
+ }
+ }
+ return { evaluated: total - unevaluated, unevaluated, total }
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 172de8a..c8f2b27 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -9,6 +9,17 @@ export function copyToClipboard(value: string) {
navigator.clipboard.writeText(value)
}
+/**
+ * A field is a placeholder — not real, renderable content — when it is absent,
+ * empty, or the "TK" deferral sentinel. Previews build from partial (WIP)
+ * tokens, so composed docs reaching the UI may carry "TK" in url/text fields;
+ * the UI must treat it exactly like empty (never an , , or
+ * literal text). See src/lib/schemas/common.ts (TK) and readiness.ts.
+ */
+export function isPlaceholder(value: unknown): boolean {
+ return value == null || value === "" || value === "TK"
+}
+
export function truncateAddress(address: string, start = 6, end = 4) {
if (address.includes("...")) {
return address