Paste an Ethereum wallet, get a plain-English report of every DeFi position, an AI chat grounded in that data, and optimization suggestions — risk, yield, and idle assets. All financial math is computed deterministically; the LLM only translates pre-computed numbers into language, never invents them.
Live: https://defi-explainer.vercel.app
- Plain-English reports — lending, LPs, staking, borrows explained without jargon.
- AI chat — ask follow-ups ("what are my biggest risks?", "explain my health factor"); answers are grounded in your actual portfolio.
- Optimization suggestions — rate arbitrage, idle assets, concentration risk, impermanent-loss estimates.
- Free + bring-your-own-key (BYOK) — no subscription, no usage limits. You supply your own Anthropic / OpenAI key (encrypted at rest, tied to your wallet).
- MCP server — the same analysis exposed as tools any AI client (Claude Desktop / Code, Cursor) can call; the host's own model writes the prose. No key to manage. See MCP server.
Connect wallet ──► sign once (free, off-chain) ──► verify ownership
│ │
▼ ▼
paste / use any address encrypted API key
│ (tied to your wallet)
▼ │
Zerion positions ─► risk engine (decimal.js) ─► JSON ───┘
│
▼
LLM (your key) → report + chat
- The LLM never touches numbers. A deterministic risk engine (
lib/defi/risk-engine.ts) computes health factors, IL, APYs, and concentration withdecimal.js. The LLM receives pre-computed JSON and only writes prose. - No financial advice. Framed as "opportunities detected", with disclaimers on every report.
- Free, BYOK-only. No platform keys, tiers, or limits.
- Wallet ownership auth. A one-time off-chain signature proves you own the wallet, establishing a session. Your API key is AES-256-GCM encrypted, keyed by wallet address, and never returned to the browser (only a last-4 hint).
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router) + TypeScript |
| UI | Tailwind CSS + shadcn/ui (dark glass theme) |
| Wallet | wagmi + viem + RainbowKit |
| Auth | One-time EIP-191 signature → stateless HMAC session cookie (no email/DB auth) |
| LLM | Vercel AI SDK — Anthropic + OpenAI (+ Local/Ollama in dev) |
| Data | Zerion (positions) · DeFiLlama (yields) · Aave RPC (health factors) |
| DB | Supabase Postgres (encrypted key store only) |
| Math | decimal.js (no native floats) |
| Validation | zod |
- Node.js 20+ and pnpm
- A Supabase project (free tier is fine)
- A Zerion API key — https://zerion.io
- An Ethereum RPC URL (Alchemy / Infura)
- A WalletConnect project ID — https://cloud.walletconnect.com
- An Anthropic or OpenAI API key (entered in-app, not in env)
git clone https://github.com/tenderdeve/defi-explainer.git
cd defi-explainer
pnpm installCopy the example and fill it in:
cp .env.example .env.localGenerate the two secrets:
openssl rand -hex 32 # ENCRYPTION_SECRET — must be 32-byte hex (64 chars)
openssl rand -hex 32 # SESSION_SECRET| Variable | Required | Description |
|---|---|---|
ENCRYPTION_SECRET |
✅ | 32-byte hex; encrypts stored BYOK keys. Never change after keys are saved. |
SESSION_SECRET |
✅ | HMAC secret for wallet ownership session cookies |
NEXT_PUBLIC_SUPABASE_URL |
✅ | Supabase project URL |
SUPABASE_SERVICE_ROLE_KEY |
✅ | Supabase service-role key (server-only) |
ZERION_API_KEY |
✅ | Portfolio positions |
ETHEREUM_RPC_URL |
➖ | Aave health factors (degrades gracefully if absent) |
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID |
✅ (prod) | WalletConnect; without it only the MetaMask extension works |
LOCAL_LLM_BASE_URL / LOCAL_LLM_MODEL |
➖ | Optional local provider (Ollama), dev only |
BYOK means no
ANTHROPIC_API_KEY/OPENAI_API_KEYin env — users add their own key in the app's Settings.
In the Supabase SQL Editor, run supabase/apply_to_existing_db.sql
(or supabase/migrations/001_initial_schema.sql on a fresh project). Creates the
user_api_keys table keyed by wallet_address.
pnpm devOpen http://localhost:3000.
First-run flow: connect wallet → click Verify ownership (sign) → Settings → save your Anthropic/OpenAI key → analyze a wallet → chat.
In development the Local (Ollama) provider is available; it is automatically disabled in production.
pnpm dev # dev server (Turbopack)
pnpm build # production build
pnpm start # serve production build
pnpm lint # ESLintapp/
page.tsx # landing (paste / connect wallet)
dashboard/ # report + chat + suggestions
settings/ # wallet verify + BYOK key management
api/
auth/{nonce,verify,session,logout}/ # wallet ownership session
portfolio/ # orchestration: Zerion → risk engine → LLM report
chat/ # streaming chat grounded in portfolio
keys/ # BYOK key CRUD (encrypted)
components/ # UI (shadcn) + feature components
lib/
auth/ # session.ts (HMAC), use-wallet-session.ts
billing/keys.ts # encrypt/decrypt/validate, keyed by wallet
defi/ # zerion, defillama, risk-engine, suggestions, types
llm/ # provider + prompts
web3/config.ts # wagmi + RainbowKit
supabase/migrations/ # schema
The same analysis core (lib/defi/*) is also packaged as a Model Context Protocol
server in mcp/. It exposes Lucid's portfolio analysis as tools any MCP host
(Claude Desktop, Claude Code, Cursor) can call. The host's own model writes the prose; the
deterministic risk engine still computes every number. Because the host already has the model,
this variant needs no BYOK, no auth, no database.
| Tool | Input | Returns |
|---|---|---|
analyze_portfolio |
address |
Full assessment (value, positions, health factors, concentration, IL, idle assets, rate arbitrage, overall risk) |
get_positions |
address |
Normalized positions only (Zerion; cheap) |
get_suggestions |
address |
Prioritized opportunities |
get_health_factors |
address |
Aave V3 / Compound V3 health factors (needs RPC) |
compare_yields |
symbol, currentProtocol? |
Best / current-vs-best yield via DeFiLlama (no key) |
you ──prompt──► MCP host (Claude Desktop) ──tools/call──► lucid-defi-mcp ──► Zerion / DeFiLlama / Aave
▲ has the model │ has the tools
└──────── JSON (numbers as strings) ──────┘
│
model writes the report ──► you
- Host spawns
lucid-defi-mcpas a child process and pipes JSON-RPC over stdio. - Host asks
tools/list; the model sees the 5 tools (descriptions + zod input schemas). - You ask a question; the model picks a tool and fills its arguments.
- The handler runs
lib/defi/*, computes withdecimal.js, returns JSON (Decimals → strings) + a disclaimer. - The host feeds that JSON back to its model, which writes the answer. The server never calls an LLM.
Add to claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"lucid": {
"command": "npx",
"args": ["-y", "lucid-defi-mcp"],
"env": {
"ZERION_API_KEY": "your_zerion_key",
"ETHEREUM_RPC_URL": "https://eth-mainnet.g.alchemy.com/v2/your_key"
}
}
}
}Claude Code: claude mcp add lucid --env ZERION_API_KEY=... --env ETHEREUM_RPC_URL=... -- npx -y lucid-defi-mcp
ZERION_API_KEYis required for wallet tools;ETHEREUM_RPC_URLis optional (health factors skipped with a note if absent).compare_yieldsneeds no keys.
You: "I'm staking ETH on Lido — am I leaving yield on the table?"
The model calls compare_yields { symbol: "ETH", currentProtocol: "lido" }. The server returns:
{ "currentProtocol": "lido", "currentApy": "2.358",
"bestProtocol": "uniswap-v2", "bestApy": "176.7081", "differentialBps": "17435.01" }The model then writes: "Your Lido staking earns ~2.36% APY; the top ETH pool is ~176.7% on Uniswap V2 (~17,435 bps higher) — but that's volatile LP fees with far higher IL/contract risk. Opportunity detected, not a recommendation."
Full docs, dev commands, and publishing: mcp/README.md.
- Import the repo at vercel.com (auto-detects Next.js + pnpm).
- Add the env vars from the table above (scope Production).
- Apply the schema to your production Supabase project.
- Deploy, then add your domain to WalletConnect Cloud → Allowed Domains.
Session cookies require HTTPS (Vercel provides it). The local LLM provider is auto-disabled in production.
- API keys are AES-256-GCM encrypted at rest and only ever decrypted server-side; the client receives a masked hint, never the key.
- Key access requires a verified wallet ownership session (one-time signature). The nonce is single-use (httpOnly cookie cleared on verify); replay over HTTPS is mitigated.
- No private keys or transactions are ever requested — only a free off-chain signature.
- Supabase access is server-side via the service role; the anon key is not used.
Lucid is for informational purposes only and does not constitute financial advice. Always do your own research before making investment decisions.