A hands-on Blockchain DIY guide to building a simple DeFi risk dashboard that scores protocols across smart-contract risk, liquidity risk, stablecoin risk, oracle risk, bridge exposure, and governance risk.
DeFi looks transparent because the code, pools, wallets, and transactions are on-chain. But transparency does not automatically mean safety.
A protocol may have high total value locked, attractive yields, a polished interface, and a large community while still carrying serious hidden risks. The smart contracts may be upgradeable by a small admin group. The token may depend on a fragile peg. Liquidity may disappear during stress. The price oracle may be easy to manipulate. A bridge may introduce cross-chain risk. Governance may be controlled by a few wallets. A high APY may exist only because the protocol is paying users with unsustainable token incentives.
That is why a DeFi risk dashboard is a useful project for students.
Instead of asking only, “Which pool has the highest yield?”, this project teaches students to ask:
- What can break?
- Who controls the protocol?
- How liquid is the market?
- How much bridge exposure exists?
- Is the stablecoin actually stable?
- Is the oracle fresh and manipulation-resistant?
- Is the protocol audited?
- Can governance change the rules quickly?
- Is the yield worth the risk?
In this tutorial, you will build a working DeFi Risk Dashboard using JavaScript, Vite, local protocol data, and a transparent scoring engine. The dashboard will classify each protocol as Low Risk, Moderate Risk, High Risk, or Extreme Risk based on multiple indicators.
This project is educational. It is not investment advice, a protocol recommendation engine, or a substitute for professional security review.
This article is part of Blockgeni’s Blockchain DIY series. If you are new to blockchain development, start with Blockgeni’s guides on how blockchain technology works, Ethereum, Solidity and Web3.js programming, and how to build a crypto dashboard. For related security context, read Blockgeni’s article on why private-key compromise remains one of crypto’s biggest loss drivers and why the crypto industry is entering its infrastructure era.
1. What You Will Build
You will build a browser-based dashboard that compares fictional DeFi protocols across six risk categories:
- Smart-contract risk
- Liquidity risk
- Stablecoin or asset-peg risk
- Oracle risk
- Bridge and cross-chain risk
- Governance and admin risk
The dashboard will show:
- protocol name;
- chain;
- protocol type;
- TVL;
- APY;
- overall risk score;
- risk level;
- risk breakdown by category;
- key warnings;
- filter by risk level;
- compare protocols side by side;
- educational explanation of each risk factor.
You will use fictional protocol data first so that the dashboard is stable and easy to understand. After that, the article explains how to upgrade it with live data from sources such as DeFiLlama, block explorers, subgraphs, oracle feeds, and protocol APIs.
The final dashboard will answer a practical question:
“Which DeFi opportunity looks attractive only because I am ignoring risk?”
2. Why a DeFi Risk Dashboard Matters
Most beginner dashboards focus on price, TVL, APY, or token performance.
That is not enough.
A DeFi protocol can fail for many reasons that do not show up in a simple yield table:
- a smart contract bug;
- a compromised admin key;
- a manipulated oracle;
- a depegged stablecoin;
- a bridge exploit;
- poor liquidity;
- hidden leverage;
- governance capture;
- unaudited upgradeable contracts;
- unsustainable rewards;
- dependency on another risky protocol.
DeFi research often classifies protocols into categories such as liquidity pools, pegged or synthetic tokens, and aggregator protocols. It also highlights that user risk depends not only on the protocol itself, but also on how the protocol is used and which tokens are involved.
For example:
- lending USDC on a large protocol is different from farming a new algorithmic stablecoin;
- depositing into a bridged asset pool is different from holding native assets;
- a pool with high APY and low liquidity may be much riskier than it looks;
- an audited protocol may still carry governance or oracle risk;
- a stablecoin pool may be exposed to peg risk even if the smart contract is secure.
The goal of this dashboard is not to predict the future. The goal is to make risk visible.
3. What This Dashboard Will Not Do
Before building, understand the limits.
This dashboard will not:
- tell users what to buy;
- guarantee protocol safety;
- predict hacks;
- replace audits;
- verify all on-chain data;
- detect every governance risk;
- prove reserves;
- calculate real legal or regulatory risk;
- certify a protocol as safe.
It will teach a method.
A good DeFi risk dashboard is a decision-support tool, not a magic answer machine.
4. The Risk Model
We will score each protocol from 0 to 100.
In this tutorial:
0means very low observed risk;100means very high observed risk.
The dashboard will classify scores as:
| Score | Risk level |
|---|---|
0–24 |
Low Risk |
25–49 |
Moderate Risk |
50–74 |
High Risk |
75–100 |
Extreme Risk |
The overall score will be a weighted average of six category scores.
| Category | Weight |
|---|---|
| Smart-contract risk | 20% |
| Liquidity risk | 20% |
| Stablecoin / asset risk | 15% |
| Oracle risk | 15% |
| Bridge risk | 15% |
| Governance risk | 15% |
These weights are educational. In a real dashboard, you should adjust them based on protocol type. A lending market, stablecoin, bridge, DEX, RWA protocol, and derivatives platform should not all use the exact same scoring model.
5. Risk Factor Breakdown
Smart-contract risk
Smart-contract risk measures whether the protocol’s code is mature, audited, and protected from common vulnerabilities.
Example indicators:
- audit status;
- number of audits;
- contract age;
- bug bounty;
- upgradeability;
- admin controls;
- history of incidents.
A young, unaudited, upgradeable protocol with no bug bounty should score higher risk than a mature, audited protocol with a long operating history.
Liquidity risk
Liquidity risk measures how easily users can enter or exit without major slippage or stress.
Example indicators:
- total value locked;
- daily trading volume;
- liquidity depth;
- pool concentration;
- withdrawal limits;
- volume-to-TVL ratio;
- number of liquidity providers.
A protocol with very high APY but shallow liquidity may be dangerous because users may not be able to exit when conditions change.
Stablecoin or asset risk
Many DeFi systems depend on stablecoins, liquid staking tokens, wrapped assets, or synthetic tokens.
Example indicators:
- peg deviation;
- reserve transparency;
- collateral type;
- issuer risk;
- redemption mechanism;
- dependence on yield strategies;
- history of depegging.
Stablecoin risk is not only about whether the price is close to $1 today. It is also about whether redemption, reserves, liquidity, and market confidence can survive stress.
Oracle risk
Oracles provide off-chain or cross-market data to smart contracts.
Example indicators:
- oracle provider;
- price update frequency;
- number of data sources;
- stale price threshold;
- use of time-weighted average price;
- fallback oracle;
- whether the protocol depends on a thinly traded market.
Oracle manipulation is one of the recurring risk categories in smart-contract security. A lending protocol, derivatives exchange, or synthetic asset protocol can become unsafe if it trusts bad prices.
Bridge risk
Bridge risk measures exposure to wrapped or bridged assets.
Example indicators:
- percentage of assets that are bridged;
- bridge provider;
- bridge security history;
- chain dependency;
- validator or multisig design;
- liquidity on source and destination chains;
- whether the asset is native or wrapped.
Bridges add another layer of trust. A user may think they are holding ETH, BTC, or USDC, but they may actually be holding a wrapped representation controlled by bridge infrastructure.
Governance and admin risk
Governance risk measures who can change the protocol.
Example indicators:
- multisig threshold;
- number of signers;
- timelock duration;
- governance token concentration;
- emergency pause controls;
- upgrade permissions;
- admin key management;
- transparency of governance proposals.
A protocol can be technically sound and still carry high governance risk if a small group can upgrade contracts instantly.
6. Project Setup
We will build the dashboard with Vite and plain JavaScript.
Create the project:
npm create vite@latest defi-risk-dashboard -- --template vanilla
cd defi-risk-dashboard
npm install
Start the development server:
npm run dev
Your project should look like this:
defi-risk-dashboard/
index.html
src/
main.js
protocols.js
riskEngine.js
style.css
package.json
We will replace the default files.
7. Create the Protocol Dataset
Create src/protocols.js:
export const protocols = [
{
id: "safestable-lend",
name: "SafeStable Lend",
chain: "Ethereum",
type: "Lending",
tvlUsd: 850000000,
apy: 4.8,
dailyVolumeUsd: 42000000,
auditCount: 4,
contractAgeDays: 1200,
hasBugBounty: true,
isUpgradeable: true,
adminControl: "timelocked-multisig",
pegDeviationBps: 8,
reserveTransparency: "high",
assetType: "native-stablecoin",
oracleType: "decentralized",
oracleFreshnessMinutes: 4,
oracleSourceCount: 18,
usesTwap: true,
bridgedAssetShare: 0.05,
bridgeHistory: "none",
multisigSigners: 9,
multisigThreshold: 6,
timelockHours: 48,
governanceTokenTop10Share: 0.32
},
{
id: "bridgeboost-pool",
name: "BridgeBoost Pool",
chain: "Arbitrum",
type: "Yield Farming",
tvlUsd: 42000000,
apy: 38.5,
dailyVolumeUsd: 900000,
auditCount: 1,
contractAgeDays: 95,
hasBugBounty: false,
isUpgradeable: true,
adminControl: "multisig-no-timelock",
pegDeviationBps: 65,
reserveTransparency: "medium",
assetType: "bridged-stablecoin",
oracleType: "single-source",
oracleFreshnessMinutes: 45,
oracleSourceCount: 1,
usesTwap: false,
bridgedAssetShare: 0.82,
bridgeHistory: "minor-incident",
multisigSigners: 5,
multisigThreshold: 3,
timelockHours: 0,
governanceTokenTop10Share: 0.71
},
{
id: "newyield-max",
name: "NewYield Max",
chain: "Base",
type: "Aggregator",
tvlUsd: 8500000,
apy: 74.2,
dailyVolumeUsd: 210000,
auditCount: 0,
contractAgeDays: 22,
hasBugBounty: false,
isUpgradeable: true,
adminControl: "single-admin",
pegDeviationBps: 140,
reserveTransparency: "low",
assetType: "algorithmic-stablecoin",
oracleType: "internal",
oracleFreshnessMinutes: 180,
oracleSourceCount: 1,
usesTwap: false,
bridgedAssetShare: 0.45,
bridgeHistory: "unknown",
multisigSigners: 1,
multisigThreshold: 1,
timelockHours: 0,
governanceTokenTop10Share: 0.88
},
{
id: "bluechip-dex",
name: "BlueChip DEX",
chain: "Ethereum",
type: "DEX",
tvlUsd: 3100000000,
apy: 2.9,
dailyVolumeUsd: 960000000,
auditCount: 6,
contractAgeDays: 1800,
hasBugBounty: true,
isUpgradeable: false,
adminControl: "immutable-core",
pegDeviationBps: 3,
reserveTransparency: "high",
assetType: "major-assets",
oracleType: "market-based",
oracleFreshnessMinutes: 1,
oracleSourceCount: 25,
usesTwap: true,
bridgedAssetShare: 0.02,
bridgeHistory: "none",
multisigSigners: 12,
multisigThreshold: 8,
timelockHours: 72,
governanceTokenTop10Share: 0.28
},
{
id: "liquid-stake-loop",
name: "Liquid Stake Loop",
chain: "Optimism",
type: "Leveraged Staking",
tvlUsd: 120000000,
apy: 18.7,
dailyVolumeUsd: 3500000,
auditCount: 2,
contractAgeDays: 260,
hasBugBounty: true,
isUpgradeable: true,
adminControl: "timelocked-multisig",
pegDeviationBps: 35,
reserveTransparency: "medium",
assetType: "liquid-staking-token",
oracleType: "decentralized",
oracleFreshnessMinutes: 12,
oracleSourceCount: 8,
usesTwap: true,
bridgedAssetShare: 0.28,
bridgeHistory: "none",
multisigSigners: 7,
multisigThreshold: 4,
timelockHours: 24,
governanceTokenTop10Share: 0.58
}
];
This dataset is fictional, but the fields are realistic.
Students can later replace this file with data from:
- DeFiLlama;
- The Graph;
- Etherscan;
- Chainlink feeds;
- Dune;
- protocol APIs;
- their own indexer.
8. Build the Risk Scoring Engine
Create src/riskEngine.js:
function clamp(value, min = 0, max = 100) {
return Math.min(max, Math.max(min, value));
}
function scoreByThresholds(value, thresholds) {
if (value <= thresholds.low) return 10;
if (value <= thresholds.moderate) return 35;
if (value <= thresholds.high) return 65;
return 90;
}
function inverseScoreByThresholds(value, thresholds) {
if (value >= thresholds.lowRisk) return 10;
if (value >= thresholds.moderateRisk) return 35;
if (value >= thresholds.highRisk) return 65;
return 90;
}
export function getRiskLevel(score) {
if (score < 25) {
return {
label: "Low Risk",
className: "risk-low",
explanation: "Few major warning signs in this educational model."
};
}
if (score < 50) {
return {
label: "Moderate Risk",
className: "risk-moderate",
explanation: "Some risk indicators need deeper review."
};
}
if (score < 75) {
return {
label: "High Risk",
className: "risk-high",
explanation: "Multiple serious risk indicators are present."
};
}
return {
label: "Extreme Risk",
className: "risk-extreme",
explanation: "The protocol shows severe risk indicators in this model."
};
}
export function scoreSmartContractRisk(protocol) {
let score = 0;
score += protocol.auditCount >= 3 ? 5 : protocol.auditCount === 2 ? 15 : protocol.auditCount === 1 ? 35 : 70;
score += inverseScoreByThresholds(protocol.contractAgeDays, {
lowRisk: 1000,
moderateRisk: 365,
highRisk: 90
});
score += protocol.hasBugBounty ? 5 : 45;
if (protocol.isUpgradeable && protocol.adminControl === "single-admin") {
score += 80;
} else if (protocol.isUpgradeable && protocol.adminControl === "multisig-no-timelock") {
score += 55;
} else if (protocol.isUpgradeable && protocol.adminControl === "timelocked-multisig") {
score += 25;
} else {
score += 10;
}
return clamp(score / 4);
}
export function scoreLiquidityRisk(protocol) {
const tvlScore = inverseScoreByThresholds(protocol.tvlUsd, {
lowRisk: 500000000,
moderateRisk: 100000000,
highRisk: 25000000
});
const volumeToTvl = protocol.dailyVolumeUsd / protocol.tvlUsd;
let volumeScore;
if (volumeToTvl >= 0.05) {
volumeScore = 15;
} else if (volumeToTvl >= 0.02) {
volumeScore = 35;
} else if (volumeToTvl >= 0.005) {
volumeScore = 60;
} else {
volumeScore = 85;
}
let apyScore;
if (protocol.apy <= 8) {
apyScore = 15;
} else if (protocol.apy <= 20) {
apyScore = 40;
} else if (protocol.apy <= 45) {
apyScore = 65;
} else {
apyScore = 90;
}
return clamp((tvlScore * 0.4) + (volumeScore * 0.3) + (apyScore * 0.3));
}
export function scoreAssetRisk(protocol) {
const pegScore = scoreByThresholds(protocol.pegDeviationBps, {
low: 10,
moderate: 50,
high: 100
});
const transparencyScore = {
high: 10,
medium: 45,
low: 80
}[protocol.reserveTransparency] ?? 70;
const assetTypeScore = {
"native-stablecoin": 20,
"major-assets": 15,
"liquid-staking-token": 45,
"bridged-stablecoin": 65,
"algorithmic-stablecoin": 90
}[protocol.assetType] ?? 60;
return clamp((pegScore * 0.4) + (transparencyScore * 0.3) + (assetTypeScore * 0.3));
}
export function scoreOracleRisk(protocol) {
const oracleTypeScore = {
decentralized: 15,
"market-based": 20,
"single-source": 70,
internal: 85
}[protocol.oracleType] ?? 65;
const freshnessScore = scoreByThresholds(protocol.oracleFreshnessMinutes, {
low: 10,
moderate: 30,
high: 120
});
const sourceScore = inverseScoreByThresholds(protocol.oracleSourceCount, {
lowRisk: 10,
moderateRisk: 5,
highRisk: 2
});
const twapScore = protocol.usesTwap ? 15 : 65;
return clamp(
(oracleTypeScore * 0.35) +
(freshnessScore * 0.25) +
(sourceScore * 0.25) +
(twapScore * 0.15)
);
}
export function scoreBridgeRisk(protocol) {
let exposureScore;
if (protocol.bridgedAssetShare <= 0.05) {
exposureScore = 10;
} else if (protocol.bridgedAssetShare <= 0.25) {
exposureScore = 35;
} else if (protocol.bridgedAssetShare <= 0.60) {
exposureScore = 65;
} else {
exposureScore = 90;
}
const historyScore = {
none: 10,
"minor-incident": 55,
unknown: 70,
"major-incident": 90
}[protocol.bridgeHistory] ?? 70;
return clamp((exposureScore * 0.7) + (historyScore * 0.3));
}
export function scoreGovernanceRisk(protocol) {
let multisigScore;
if (protocol.multisigSigners >= 9 && protocol.multisigThreshold >= 6) {
multisigScore = 15;
} else if (protocol.multisigSigners >= 5 && protocol.multisigThreshold >= 3) {
multisigScore = 40;
} else if (protocol.multisigSigners >= 3) {
multisigScore = 65;
} else {
multisigScore = 90;
}
let timelockScore;
if (protocol.timelockHours >= 48) {
timelockScore = 10;
} else if (protocol.timelockHours >= 24) {
timelockScore = 35;
} else if (protocol.timelockHours >= 6) {
timelockScore = 60;
} else {
timelockScore = 85;
}
let concentrationScore;
if (protocol.governanceTokenTop10Share <= 0.35) {
concentrationScore = 20;
} else if (protocol.governanceTokenTop10Share <= 0.55) {
concentrationScore = 45;
} else if (protocol.governanceTokenTop10Share <= 0.75) {
concentrationScore = 70;
} else {
concentrationScore = 90;
}
return clamp(
(multisigScore * 0.35) +
(timelockScore * 0.35) +
(concentrationScore * 0.30)
);
}
export function calculateProtocolRisk(protocol) {
const breakdown = {
smartContract: scoreSmartContractRisk(protocol),
liquidity: scoreLiquidityRisk(protocol),
asset: scoreAssetRisk(protocol),
oracle: scoreOracleRisk(protocol),
bridge: scoreBridgeRisk(protocol),
governance: scoreGovernanceRisk(protocol)
};
const overall =
breakdown.smartContract * 0.20 +
breakdown.liquidity * 0.20 +
breakdown.asset * 0.15 +
breakdown.oracle * 0.15 +
breakdown.bridge * 0.15 +
breakdown.governance * 0.15;
const roundedOverall = Math.round(overall);
const riskLevel = getRiskLevel(roundedOverall);
return {
overall: roundedOverall,
level: riskLevel,
breakdown
};
}
export function getWarnings(protocol, risk) {
const warnings = [];
if (protocol.auditCount === 0) {
warnings.push("No public audits recorded in the demo dataset.");
}
if (protocol.contractAgeDays < 90) {
warnings.push("Contract is very new; operating history is limited.");
}
if (protocol.apy > 30) {
warnings.push("High APY may indicate incentive, liquidity, or sustainability risk.");
}
if (protocol.pegDeviationBps > 50) {
warnings.push("Peg deviation is elevated and should be reviewed.");
}
if (protocol.oracleType === "single-source" || protocol.oracleType === "internal") {
warnings.push("Oracle design may be vulnerable to manipulation or stale pricing.");
}
if (protocol.bridgedAssetShare > 0.5) {
warnings.push("Large share of assets are bridged or wrapped.");
}
if (protocol.timelockHours === 0) {
warnings.push("No governance timelock in this model.");
}
if (protocol.governanceTokenTop10Share > 0.7) {
warnings.push("Governance token concentration is high.");
}
if (risk.overall >= 75) {
warnings.push("Overall score is extreme; this protocol requires deep review.");
}
return warnings;
}
This file is the heart of the dashboard.
The scoring model is intentionally transparent. Students can change the thresholds, weights, and warnings to see how the ranking changes.
9. Create the Dashboard UI
Replace src/main.js with:
import "./style.css";
import { protocols } from "./protocols.js";
import { calculateProtocolRisk, getWarnings } from "./riskEngine.js";
const app = document.querySelector("#app");
let selectedRiskFilter = "all";
let sortMode = "risk-desc";
function formatCurrency(value) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
notation: "compact",
maximumFractionDigits: 2
}).format(value);
}
function formatPercent(value) {
return `${value.toFixed(2)}%`;
}
function getScoredProtocols() {
return protocols.map((protocol) => {
const risk = calculateProtocolRisk(protocol);
const warnings = getWarnings(protocol, risk);
return {
...protocol,
risk,
warnings
};
});
}
function filterProtocols(items) {
if (selectedRiskFilter === "all") {
return items;
}
return items.filter((item) => item.risk.level.className === selectedRiskFilter);
}
function sortProtocols(items) {
const sorted = [...items];
if (sortMode === "risk-desc") {
sorted.sort((a, b) => b.risk.overall - a.risk.overall);
}
if (sortMode === "risk-asc") {
sorted.sort((a, b) => a.risk.overall - b.risk.overall);
}
if (sortMode === "apy-desc") {
sorted.sort((a, b) => b.apy - a.apy);
}
if (sortMode === "tvl-desc") {
sorted.sort((a, b) => b.tvlUsd - a.tvlUsd);
}
return sorted;
}
function renderRiskBar(label, value) {
return `
<div class="risk-row">
<div class="risk-row-header">
<span>${label}</span>
<strong>${Math.round(value)}</strong>
</div>
<div class="risk-track">
<div class="risk-fill" style="width:${Math.round(value)}%"></div>
</div>
</div>
`;
}
function renderProtocolCard(protocol) {
return `
<article class="protocol-card">
<div class="protocol-header">
<div>
<h2>${protocol.name}</h2>
<p>${protocol.chain} · ${protocol.type}</p>
</div>
<span class="risk-badge ${protocol.risk.level.className}">
${protocol.risk.level.label}
</span>
</div>
<div class="metrics-grid">
<div>
<span>Risk Score</span>
<strong>${protocol.risk.overall}/100</strong>
</div>
<div>
<span>TVL</span>
<strong>${formatCurrency(protocol.tvlUsd)}</strong>
</div>
<div>
<span>APY</span>
<strong>${formatPercent(protocol.apy)}</strong>
</div>
<div>
<span>Audits</span>
<strong>${protocol.auditCount}</strong>
</div>
</div>
<div class="breakdown">
${renderRiskBar("Smart Contract", protocol.risk.breakdown.smartContract)}
${renderRiskBar("Liquidity", protocol.risk.breakdown.liquidity)}
${renderRiskBar("Asset / Peg", protocol.risk.breakdown.asset)}
${renderRiskBar("Oracle", protocol.risk.breakdown.oracle)}
${renderRiskBar("Bridge", protocol.risk.breakdown.bridge)}
${renderRiskBar("Governance", protocol.risk.breakdown.governance)}
</div>
<details>
<summary>View risk warnings</summary>
<ul class="warning-list">
${
protocol.warnings.length > 0
? protocol.warnings.map((warning) => `<li>${warning}</li>`).join("")
: "<li>No major warning triggered in this educational model.</li>"
}
</ul>
</details>
</article>
`;
}
function renderSummary(items) {
const total = items.length;
const averageRisk = Math.round(
items.reduce((sum, item) => sum + item.risk.overall, 0) / total
);
const extremeCount = items.filter((item) => item.risk.overall >= 75).length;
const highCount = items.filter(
(item) => item.risk.overall >= 50 && item.risk.overall < 75
).length;
return `
<section class="summary-grid">
<div class="summary-card">
<span>Protocols Scored</span>
<strong>${total}</strong>
</div>
<div class="summary-card">
<span>Average Risk</span>
<strong>${averageRisk}/100</strong>
</div>
<div class="summary-card">
<span>High Risk</span>
<strong>${highCount}</strong>
</div>
<div class="summary-card">
<span>Extreme Risk</span>
<strong>${extremeCount}</strong>
</div>
</section>
`;
}
function renderTable(items) {
return `
<section class="table-section">
<h2>Protocol Comparison Table</h2>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Protocol</th>
<th>Chain</th>
<th>Type</th>
<th>TVL</th>
<th>APY</th>
<th>Risk</th>
<th>Risk Level</th>
</tr>
</thead>
<tbody>
${items.map((item) => `
<tr>
<td>${item.name}</td>
<td>${item.chain}</td>
<td>${item.type}</td>
<td>${formatCurrency(item.tvlUsd)}</td>
<td>${formatPercent(item.apy)}</td>
<td>${item.risk.overall}/100</td>
<td>${item.risk.level.label}</td>
</tr>
`).join("")}
</tbody>
</table>
</div>
</section>
`;
}
function render() {
const scored = getScoredProtocols();
const filtered = filterProtocols(scored);
const sorted = sortProtocols(filtered);
app.innerHTML = `
<main class="page">
<section class="hero">
<p class="eyebrow">Blockchain DIY Project</p>
<h1>DeFi Risk Dashboard</h1>
<p>
Compare DeFi protocols using a transparent educational scoring model
across smart-contract, liquidity, peg, oracle, bridge, and governance risk.
</p>
</section>
${renderSummary(scored)}
<section class="controls">
<label>
Filter by risk
<select id="riskFilter">
<option value="all">All protocols</option>
<option value="risk-low">Low Risk</option>
<option value="risk-moderate">Moderate Risk</option>
<option value="risk-high">High Risk</option>
<option value="risk-extreme">Extreme Risk</option>
</select>
</label>
<label>
Sort by
<select id="sortMode">
<option value="risk-desc">Highest risk first</option>
<option value="risk-asc">Lowest risk first</option>
<option value="apy-desc">Highest APY first</option>
<option value="tvl-desc">Highest TVL first</option>
</select>
</label>
</section>
<section class="cards-grid">
${
sorted.length > 0
? sorted.map(renderProtocolCard).join("")
: "<p>No protocols match this filter.</p>"
}
</section>
${renderTable(sorted)}
<section class="note">
<h2>Important Warning</h2>
<p>
This dashboard is educational. It does not recommend deposits,
investments, trades, or protocol usage. Real DeFi risk assessment
requires contract review, data verification, oracle analysis,
liquidity analysis, governance review, and legal/compliance judgment.
</p>
</section>
</main>
`;
document.querySelector("#riskFilter").value = selectedRiskFilter;
document.querySelector("#sortMode").value = sortMode;
document.querySelector("#riskFilter").addEventListener("change", (event) => {
selectedRiskFilter = event.target.value;
render();
});
document.querySelector("#sortMode").addEventListener("change", (event) => {
sortMode = event.target.value;
render();
});
}
render();
This builds the entire dashboard from your local dataset and scoring engine.
10. Add the Styling
Replace src/style.css with:
:root {
font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #172033;
background: #f5f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.page {
width: min(1180px, calc(100% - 32px));
margin: 0 auto;
padding: 40px 0;
}
.hero {
background: #101827;
color: white;
border-radius: 24px;
padding: 40px;
margin-bottom: 24px;
}
.eyebrow {
text-transform: uppercase;
letter-spacing: 0.12em;
font-size: 0.78rem;
color: #9fb4d8;
margin: 0 0 8px;
}
.hero h1 {
margin: 0;
font-size: clamp(2rem, 4vw, 4rem);
}
.hero p {
max-width: 760px;
color: #dbe7ff;
line-height: 1.6;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin-bottom: 24px;
}
.summary-card,
.protocol-card,
.table-section,
.note,
.controls {
background: white;
border: 1px solid #e5eaf3;
border-radius: 20px;
box-shadow: 0 12px 30px rgba(16, 24, 39, 0.06);
}
.summary-card {
padding: 20px;
}
.summary-card span {
display: block;
color: #64748b;
font-size: 0.9rem;
}
.summary-card strong {
display: block;
margin-top: 8px;
font-size: 2rem;
}
.controls {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
padding: 20px;
margin-bottom: 24px;
}
label {
display: grid;
gap: 8px;
font-weight: 600;
}
select {
width: 100%;
border: 1px solid #d7deea;
border-radius: 12px;
padding: 12px;
font: inherit;
background: white;
}
.cards-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.protocol-card {
padding: 22px;
}
.protocol-header {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: flex-start;
margin-bottom: 18px;
}
.protocol-header h2 {
margin: 0 0 4px;
}
.protocol-header p {
margin: 0;
color: #64748b;
}
.risk-badge {
white-space: nowrap;
border-radius: 999px;
padding: 8px 12px;
font-weight: 700;
font-size: 0.85rem;
}
.risk-low {
background: #e8f7ee;
color: #146c38;
}
.risk-moderate {
background: #fff5d6;
color: #8a5a00;
}
.risk-high {
background: #ffe8d9;
color: #9a3412;
}
.risk-extreme {
background: #ffe4e6;
color: #9f1239;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 20px;
}
.metrics-grid div {
background: #f8fafc;
border-radius: 14px;
padding: 12px;
}
.metrics-grid span {
display: block;
color: #64748b;
font-size: 0.78rem;
}
.metrics-grid strong {
display: block;
margin-top: 6px;
}
.breakdown {
display: grid;
gap: 12px;
}
.risk-row-header {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
font-size: 0.9rem;
}
.risk-track {
height: 10px;
background: #e5eaf3;
border-radius: 999px;
overflow: hidden;
}
.risk-fill {
height: 100%;
background: #3654ff;
border-radius: 999px;
}
details {
margin-top: 18px;
}
summary {
cursor: pointer;
font-weight: 700;
}
.warning-list {
color: #475569;
line-height: 1.5;
}
.table-section {
margin-top: 24px;
padding: 22px;
}
.table-wrap {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
min-width: 760px;
}
th,
td {
text-align: left;
padding: 12px;
border-bottom: 1px solid #e5eaf3;
}
th {
color: #64748b;
font-size: 0.85rem;
}
.note {
margin-top: 24px;
padding: 24px;
border-left: 6px solid #3654ff;
}
.note h2 {
margin-top: 0;
}
.note p {
line-height: 1.6;
color: #475569;
}
@media (max-width: 860px) {
.summary-grid,
.cards-grid,
.controls {
grid-template-columns: 1fr;
}
.metrics-grid {
grid-template-columns: repeat(2, 1fr);
}
.hero {
padding: 28px;
}
}
Run the app:
npm run dev
Open the local URL shown in your terminal.
You should now have a working DeFi risk dashboard.
11. How the Scoring Works
Each protocol receives a score in six categories. The category scores are combined into a weighted average.
Example:
Overall Risk =
Smart Contract Risk × 20%
+ Liquidity Risk × 20%
+ Asset Risk × 15%
+ Oracle Risk × 15%
+ Bridge Risk × 15%
+ Governance Risk × 15%
This is simple enough for students to understand, but flexible enough to extend.
The most important design principle is explainability. A user should not only see:
Risk Score: 74
They should also see why.
A dashboard that says “High Risk” without explanation is not useful. A dashboard that says “High Risk because of no audits, high bridged exposure, stale oracle data, and no timelock” is educational.
12. Why APY Is Treated as a Risk Signal
High APY is not automatically bad. But extremely high APY often deserves investigation.
A high yield may come from:
- real borrower demand;
- trading fees;
- token incentives;
- leverage;
- liquidity mining;
- early-stage bootstrapping;
- unsustainable emissions;
- hidden risk;
- low liquidity;
- temporary market distortion.
In this dashboard, APY contributes to liquidity risk because high yield can attract users before the underlying liquidity, audit history, or risk controls are mature.
A safe dashboard should never rank protocols only by APY.
13. Why TVL Is Useful but Imperfect
Total value locked is one of the most common DeFi metrics, but it has limitations.
TVL can be inflated by:
- token price increases;
- recursive deposits;
- double counting;
- protocol-owned assets;
- bridged assets;
- self-reported data;
- low-quality collateral;
- assets that cannot exit easily.
Research on TVL verifiability notes that although blockchain data is public, published TVL figures can be difficult to independently verify because methodologies vary and sometimes rely on non-standard or off-chain components.
That does not mean TVL is useless. It means TVL should be treated as one input, not a safety score.
In this project, TVL is combined with volume and APY to produce a basic liquidity-risk signal.
14. Add a Risk Details Modal
Students can improve the UI by adding a modal that explains each category.
A simple explanation object:
export const riskDescriptions = {
smartContract: "Measures audit history, contract age, bug bounty, upgradeability, and admin controls.",
liquidity: "Measures TVL, trading activity, and whether high APY may hide liquidity risk.",
asset: "Measures peg deviation, reserve transparency, and asset type risk.",
oracle: "Measures oracle design, price freshness, source count, and TWAP usage.",
bridge: "Measures exposure to bridged assets and bridge incident history.",
governance: "Measures multisig strength, timelock delay, and governance token concentration."
};
Add “What does this mean?” buttons for each category.
This turns the dashboard into a teaching tool, not just a scoring page.
15. Add a CSV Export
Students may want to export the risk table.
Add this function to main.js:
function exportCsv(items) {
const header = [
"Protocol",
"Chain",
"Type",
"TVL",
"APY",
"Risk Score",
"Risk Level"
];
const rows = items.map((item) => [
item.name,
item.chain,
item.type,
item.tvlUsd,
item.apy,
item.risk.overall,
item.risk.level.label
]);
const csv = [header, ...rows]
.map((row) => row.map((cell) => `"${cell}"`).join(","))
.join("\n");
const blob = new Blob([csv], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "defi-risk-dashboard.csv";
link.click();
URL.revokeObjectURL(url);
}
Then add a button:
<button id="exportCsv">Export CSV</button>
This teaches students how dashboards can support research workflows.
16. Add Custom Weight Controls
A serious risk dashboard should allow users to change weights.
For example, a conservative user may want:
- smart-contract risk: 30%;
- bridge risk: 25%;
- governance risk: 20%;
- APY risk: lower priority.
A yield farmer may care more about liquidity and less about governance.
A compliance team may care more about admin control, sanctions risk, and asset origin.
Create a weight object:
const weights = {
smartContract: 0.20,
liquidity: 0.20,
asset: 0.15,
oracle: 0.15,
bridge: 0.15,
governance: 0.15
};
Then pass it into the scoring function.
A student exercise is to create sliders for each weight and recalculate scores live.
Important rule:
All weights should add up to 1.
If they do not, normalize them before scoring.
17. Add Protocol-Type-Specific Scoring
A lending market, DEX, stablecoin, and bridge do not have the same risk profile.
For example:
Lending protocol
Higher weight on:
- oracle risk;
- collateral quality;
- liquidation design;
- smart-contract risk.
Stablecoin protocol
Higher weight on:
- peg risk;
- reserve transparency;
- redemption mechanism;
- liquidity.
Bridge
Higher weight on:
- validator security;
- custody model;
- cross-chain verification;
- incident history.
DEX
Higher weight on:
- liquidity depth;
- pool concentration;
- oracle use;
- fee sustainability.
A more advanced dashboard can use different weights by protocol type:
const weightsByType = {
Lending: {
smartContract: 0.20,
liquidity: 0.15,
asset: 0.15,
oracle: 0.25,
bridge: 0.10,
governance: 0.15
},
DEX: {
smartContract: 0.20,
liquidity: 0.30,
asset: 0.10,
oracle: 0.15,
bridge: 0.10,
governance: 0.15
},
Aggregator: {
smartContract: 0.20,
liquidity: 0.15,
asset: 0.15,
oracle: 0.15,
bridge: 0.20,
governance: 0.15
}
};
This is a strong classroom extension because it shows that risk is contextual.
18. Add Live Data Later
The tutorial uses local data because it is stable and easy to teach. But once students understand the model, they can add live data.
Possible live data sources:
| Data need | Possible source |
|---|---|
| TVL | DeFiLlama |
| Stablecoin supply | DeFiLlama stablecoin dashboard |
| Pool APY | DeFiLlama yield data |
| Contract source | Etherscan or block explorer APIs |
| Oracle feed data | Chainlink feed registry or protocol contracts |
| Governance proposals | Snapshot, Tally, Governor contracts |
| Token holders | Block explorer APIs |
| Bridge assets | Bridge dashboards, token contracts, protocol docs |
| Incident history | Rekt, DeFiLlama hacks, Immunefi reports, protocol postmortems |
DeFiLlama tracks categories such as TVL, stablecoins, yields, fees, revenue, bridges, fundraising, and security-related data, making it a useful starting point for DeFi analytics projects.
19. Optional: Add a DeFiLlama Data Fetcher
If you want to experiment with live TVL data, create a simple data fetcher.
Create src/liveData.js:
export async function fetchProtocolTvl(protocolSlug) {
const response = await fetch(`https://api.llama.fi/protocol/${protocolSlug}`);
if (!response.ok) {
throw new Error(`Failed to fetch TVL for ${protocolSlug}`);
}
const data = await response.json();
return {
name: data.name,
category: data.category,
chains: data.chains,
tvl: data.tvl,
change_1d: data.change_1d,
change_7d: data.change_7d
};
}
However, live APIs can change, fail, rate-limit, or return incomplete fields. For a student article, local data is better for the core lesson. Use live data only after the risk engine works.
20. Add On-Chain Contract Checks
A more advanced version can inspect contract properties.
Possible checks:
- Is the contract verified?
- Is the contract upgradeable?
- Is there a proxy admin?
- Who owns the admin role?
- Is ownership renounced?
- Is there a timelock?
- Are there emergency pause functions?
- Are there privileged mint or withdraw functions?
Some of this can be checked automatically. Some requires manual review.
A basic automated checklist:
const contractChecklist = {
sourceVerified: true,
proxyDetected: true,
timelockDetected: true,
adminMultisig: true,
pauseFunctionFound: true,
mintFunctionFound: false,
ownerCanWithdraw: false
};
Then score:
function scoreContractChecklist(checklist) {
let score = 0;
if (!checklist.sourceVerified) score += 30;
if (checklist.proxyDetected && !checklist.timelockDetected) score += 25;
if (!checklist.adminMultisig) score += 25;
if (checklist.mintFunctionFound) score += 20;
if (checklist.ownerCanWithdraw) score += 30;
return Math.min(score, 100);
}
This is a useful next step for students interested in smart-contract security.
21. Add Oracle Risk Checks
Oracle risk deserves special attention.
For lending, derivatives, and synthetic assets, a bad price can trigger:
- wrongful liquidations;
- undercollateralized borrowing;
- bad debt;
- pool imbalance;
- arbitrage losses;
- protocol insolvency.
A simple oracle check can include:
const oracleCheck = {
sourceCount: 8,
updateDelayMinutes: 4,
usesTwap: true,
fallbackOracle: true,
thinMarketDependency: false
};
Score it:
function scoreOracleCheck(check) {
let score = 0;
if (check.sourceCount < 3) score += 30;
if (check.updateDelayMinutes > 30) score += 25;
if (!check.usesTwap) score += 20;
if (!check.fallbackOracle) score += 15;
if (check.thinMarketDependency) score += 25;
return Math.min(score, 100);
}
OWASP’s 2026 Smart Contract Top 10 includes price oracle manipulation as a major category, which makes oracle review a natural part of any DeFi risk dashboard.
22. Add Bridge Exposure Checks
Bridge exposure should be visible because wrapped assets introduce dependency risk.
A protocol may hold:
- native USDC;
- bridged USDC;
- wrapped BTC;
- bridged ETH;
- liquid staking tokens;
- synthetic assets;
- cross-chain receipt tokens.
A dashboard can show:
const assetComposition = [
{ symbol: "USDC", type: "native", share: 0.45 },
{ symbol: "USDC.e", type: "bridged", share: 0.30 },
{ symbol: "wETH", type: "wrapped", share: 0.15 },
{ symbol: "LST", type: "liquid-staking-token", share: 0.10 }
];
Calculate bridged exposure:
function calculateBridgedShare(assets) {
return assets
.filter((asset) => asset.type === "bridged" || asset.type === "wrapped")
.reduce((sum, asset) => sum + asset.share, 0);
}
Then show:
Bridge exposure: 45%
The risk is not that all bridged assets are bad. The risk is that the user depends on more systems than the frontend may show.
23. Add Stablecoin Peg Risk
Stablecoin risk can be measured through simple indicators:
- current peg deviation;
- maximum 24-hour deviation;
- liquidity depth near
$1; - redemption availability;
- reserve transparency;
- issuer or collateral model;
- chain-specific liquidity;
- historical depeg events.
Example:
const stablecoinRisk = {
symbol: "USDC",
currentPrice: 0.9994,
maxDeviation24hBps: 12,
reserveTransparency: "high",
redemptionStatus: "active",
liquidityDepthUsd: 500000000
};
A basic peg deviation formula:
function pegDeviationBps(price) {
return Math.abs(price - 1) * 10000;
}
If USDC trades at 0.9994, deviation is:
6 basis points
This kind of calculation helps students connect price data to risk scoring.
For stablecoin infrastructure context, Blockgeni has covered Circle’s OCC approval and USDC’s move toward regulated infrastructure.
24. Add Governance Risk Analysis
Governance risk is often ignored by beginners.
A governance dashboard should ask:
- Who can upgrade contracts?
- How long is the timelock?
- How many multisig signers exist?
- What threshold is required?
- Can the admin pause withdrawals?
- Can governance change fees?
- Can governance change collateral parameters?
- Can governance mint tokens?
- Is voting power concentrated?
- Are proposals visible before execution?
A simplified governance record:
const governanceProfile = {
multisigSigners: 9,
multisigThreshold: 6,
timelockHours: 48,
top10TokenHolderShare: 0.32,
emergencyPause: true,
upgradeableContracts: true
};
A dashboard should not automatically punish every upgradeable system. Upgradeability can be useful for fixing bugs. But upgradeability without timelock, transparency, or multisig controls increases risk.
25. Add a Watchlist
A student dashboard becomes more useful if it can track a watchlist.
Create:
let watchlist = new Set();
function toggleWatchlist(protocolId) {
if (watchlist.has(protocolId)) {
watchlist.delete(protocolId);
} else {
watchlist.add(protocolId);
}
}
Add a button to each protocol card:
<button class="watchlist-button" data-id="${protocol.id}">
Add to Watchlist
</button>
This helps students think like analysts. The goal is not to review everything every day. The goal is to track the protocols where the risk/reward question is most important.
26. Add Risk Alerts
A simple alert engine can flag changes.
Example:
function generateRiskAlerts(previous, current) {
const alerts = [];
if (current.risk.overall - previous.risk.overall >= 15) {
alerts.push("Overall risk increased sharply.");
}
if (current.pegDeviationBps > 50 && previous.pegDeviationBps <= 50) {
alerts.push("Peg deviation moved above warning threshold.");
}
if (current.timelockHours < previous.timelockHours) {
alerts.push("Governance timelock was reduced.");
}
if (current.bridgedAssetShare > previous.bridgedAssetShare + 0.20) {
alerts.push("Bridge exposure increased materially.");
}
return alerts;
}
This teaches an important analytics idea: absolute risk matters, but risk changes also matter.
A protocol moving from 20 to 42 may deserve more attention than a protocol that stays at 55.
27. Add a Backtesting Exercise
Students can simulate historical events.
Create a fictional timeline:
const timeline = [
{ day: 1, tvlUsd: 100000000, pegDeviationBps: 5, oracleFreshnessMinutes: 3 },
{ day: 2, tvlUsd: 94000000, pegDeviationBps: 9, oracleFreshnessMinutes: 4 },
{ day: 3, tvlUsd: 76000000, pegDeviationBps: 38, oracleFreshnessMinutes: 15 },
{ day: 4, tvlUsd: 51000000, pegDeviationBps: 125, oracleFreshnessMinutes: 80 }
];
Ask students:
- When should the dashboard have flagged early warning?
- Which metric moved first?
- Did APY rise as risk increased?
- Did liquidity disappear before the peg broke?
- Was the oracle stale before the largest drawdown?
This teaches students to think in sequences, not static screenshots.
28. Add Unit Tests for the Risk Engine
Install Vitest:
npm install --save-dev vitest
Update package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest"
}
}
Create src/riskEngine.test.js:
import { describe, expect, it } from "vitest";
import {
calculateProtocolRisk,
getRiskLevel
} from "./riskEngine.js";
describe("risk engine", () => {
it("classifies low scores as low risk", () => {
const level = getRiskLevel(10);
expect(level.label).toBe("Low Risk");
});
it("classifies extreme scores as extreme risk", () => {
const level = getRiskLevel(90);
expect(level.label).toBe("Extreme Risk");
});
it("assigns higher risk to weak protocol controls", () => {
const riskyProtocol = {
auditCount: 0,
contractAgeDays: 15,
hasBugBounty: false,
isUpgradeable: true,
adminControl: "single-admin",
tvlUsd: 5000000,
apy: 80,
dailyVolumeUsd: 100000,
pegDeviationBps: 150,
reserveTransparency: "low",
assetType: "algorithmic-stablecoin",
oracleType: "internal",
oracleFreshnessMinutes: 180,
oracleSourceCount: 1,
usesTwap: false,
bridgedAssetShare: 0.80,
bridgeHistory: "unknown",
multisigSigners: 1,
multisigThreshold: 1,
timelockHours: 0,
governanceTokenTop10Share: 0.90
};
const result = calculateProtocolRisk(riskyProtocol);
expect(result.overall).toBeGreaterThan(75);
});
});
Run:
npm test
Testing the risk engine is important because scoring bugs can mislead users. Even educational dashboards should test their logic.
29. Production Architecture
A production DeFi risk dashboard would need more than this tutorial.
A serious architecture may include:
Data ingestion
├── TVL APIs
├── on-chain indexers
├── oracle feeds
├── governance APIs
├── bridge data
├── audit databases
└── incident databases
Processing layer
├── normalization
├── scoring engine
├── anomaly detection
├── historical trend storage
└── alert rules
Storage
├── protocol metadata
├── daily risk scores
├── incident records
├── asset composition
└── governance state
Frontend
├── protocol comparison
├── risk breakdown
├── warnings
├── watchlists
├── alerts
└── reports
This tutorial gives students the first version of the scoring and UI layer.
30. Production Data Challenges
Real DeFi data is messy.
Common problems include:
Different definitions of TVL
One platform may count staked assets differently from another.
Duplicated assets
A token may appear in multiple protocols, causing double-counting.
Bridged assets
The same economic asset may have different wrapped versions across chains.
Fast-changing liquidity
A pool that looks liquid in the morning may be thin by evening.
Incomplete audit data
Some audits are old, limited in scope, or not publicly available.
Governance changes
Admin rights, signers, thresholds, and timelocks can change.
Oracle complexity
The frontend may not reveal which oracle a protocol actually uses.
Incentive distortion
A high APY may be caused by temporary token emissions.
A good dashboard should show uncertainty, not hide it.
31. How to Display Uncertainty
Avoid false precision.
Do not say:
This protocol is 63.42% risky.
Say:
Risk Score: 63/100
Risk Level: High
Main drivers: bridge exposure, limited audit history, no timelock.
Use warnings such as:
- data incomplete;
- audit status unverified;
- oracle source unknown;
- bridge exposure estimated;
- TVL source may vary;
- governance controls require manual review.
This makes the dashboard more trustworthy.
32. Common Mistakes Students Make
Mistake 1: Treating APY as safety
High yield can be a warning sign.
Mistake 2: Treating TVL as safety
Large TVL does not eliminate contract, governance, oracle, or bridge risk.
Mistake 3: Ignoring admin keys
A small admin group can sometimes change or pause a protocol.
Mistake 4: Ignoring bridges
Wrapped assets add another dependency layer.
Mistake 5: Ignoring oracle design
A bad oracle can break a lending or derivatives protocol.
Mistake 6: Ignoring stablecoin design
Not every $1 token carries the same risk.
Mistake 7: Creating black-box scores
Users need to understand why the score exists.
Mistake 8: Using stale data
DeFi risk changes quickly. A dashboard without timestamps can mislead users.
33. Student Exercises
Exercise 1: Change the weights
Make oracle risk more important for lending protocols and bridge risk more important for aggregators.
Exercise 2: Add a custom protocol form
Let users add a protocol manually and calculate a score.
Exercise 3: Add live TVL data
Use a public API to update TVL and 24-hour change.
Exercise 4: Add stablecoin peg tracking
Track current price deviation from $1.
Exercise 5: Add governance proposal tracking
Show active governance proposals for selected protocols.
Exercise 6: Add a risk history chart
Store daily scores and show how risk changes over time.
Exercise 7: Add incident history
Add past exploit data and increase risk for protocols with unresolved incidents.
Exercise 8: Add wallet exposure
Let a user enter a wallet address and estimate exposure by protocol.
Exercise 9: Add chain-level risk
Compare Ethereum, Arbitrum, Optimism, Base, BNB Chain, Polygon, and Solana risk assumptions.
Exercise 10: Add report generation
Generate a PDF-style risk report for a selected protocol.
34. Why This Project Matters
A DeFi risk dashboard teaches students to think beyond price.
It connects multiple disciplines:
- smart-contract security;
- market liquidity;
- stablecoin design;
- oracle infrastructure;
- bridge architecture;
- governance systems;
- frontend dashboards;
- data normalization;
- risk communication.
That is why it is one of the most useful blockchain projects for students.
A basic token tutorial teaches how assets move.
A DeFi dashboard teaches how assets fail.
Both skills matter.
As crypto becomes more institutional, tools that explain risk will matter more than tools that only display yield. Blockgeni has covered how stablecoin infrastructure, RWA tokenization, private-key security, and crypto regulation are becoming central to the next phase of blockchain adoption. A DeFi risk dashboard sits directly inside that transition.
Final Takeaway
A DeFi risk dashboard is not about predicting the next exploit. It is about building a structured way to ask better questions.
The dashboard you built in this tutorial scores protocols across smart-contract risk, liquidity risk, stablecoin risk, oracle risk, bridge risk, and governance risk. It uses transparent logic, visible warnings, and editable assumptions. That makes it useful for learning.
The most important lesson is this:
DeFi risk is not one number. It is a stack.
A protocol can be strong in one layer and weak in another. A pool can have deep liquidity but poor governance. A stablecoin can hold its peg today but depend on weak reserves. A protocol can be audited but still rely on risky bridges. A high APY can look attractive while hiding fragile economics.
Students who understand that stack will be better prepared to build safer blockchain products, analyze DeFi protocols, and design more responsible financial dashboards.
This project is a practical first step.











