+ {getGreeting()} +
++ Tell me your financial goal and I will deploy a team of AI agents to find the best DeFi strategy for you — live yields, risk-adjusted, ready to execute. +
+ + {!walletConnected && ( +{msg.content}
+⚠️ {msg.content}
+diff --git a/examples/crypto-butler/.env.example b/examples/crypto-butler/.env.example new file mode 100644 index 0000000..3d38419 --- /dev/null +++ b/examples/crypto-butler/.env.example @@ -0,0 +1,18 @@ +# .env.local +# Copy this file to .env.local and fill in your values + +# ── ANTHROPIC ────────────────────────────────────── +ANTHROPIC_API_KEY=sk-ant-your-key-here + +# ── WALLETCONNECT (get free projectId at cloud.walletconnect.com) ── +NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here + +# ── OPTIONAL: ALCHEMY for Base Sepolia RPC ──────── +NEXT_PUBLIC_ALCHEMY_ID=your_alchemy_id_here + +# ── UTXOs.dev Project ID (server-side only) ──────── +UTXOS_PROJECT_ID=your_project_id + +# ── Blockfrost API Keys (server-side only) ──────── +BLOCKFROST_API_KEY_PREPROD=preprodxxxxxxxx +BLOCKFROST_API_KEY_MAINNET=mainnetxxxxxxxx diff --git a/examples/crypto-butler/CONTRIBUTING.md b/examples/crypto-butler/CONTRIBUTING.md new file mode 100644 index 0000000..17740a4 --- /dev/null +++ b/examples/crypto-butler/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Crypto Butler + +Contributions are welcome. Please open an issue before submitting a pull request. + +## Development Setup +```bash +git clone https://github.com/your-username/crypto-butler +cd crypto-butler +npm install +cp .env.example .env.local +npm run dev +``` + +## Areas Where Contributions Are Needed + +- Additional Cardano protocol integrations for yield data +- Improved risk scoring logic in the Risk Agent +- M-Pesa API integration +- Mobile-responsive UI improvements +- Smart contract development for on-chain execution + +## Pull Request Guidelines + +- One feature or fix per pull request +- Include a clear description of what changed and why +- Test on Cardano Preprod testnet before submitting diff --git a/examples/crypto-butler/README.md b/examples/crypto-butler/README.md new file mode 100644 index 0000000..f9c7f46 --- /dev/null +++ b/examples/crypto-butler/README.md @@ -0,0 +1,527 @@ +# Crypto Butler + +An AI-powered DeFi wealth management agent built on Cardano. Users describe their financial goals in plain English and a multi-agent AI swarm analyzes live yield opportunities, builds a personalized strategy, and simulates execution on Cardano Preprod testnet. + +--- + +## Table of Contents + +- [Overview](#overview) +- [Architecture](#architecture) +- [Tech Stack](#tech-stack) +- [Multi-Agent System](#multi-agent-system) +- [UTXOS.dev Integration](#utxosdev-integration) +- [Wallet Connection](#wallet-connection) +- [Yield Data](#yield-data) +- [Testnet Simulation](#testnet-simulation) +- [Getting Started](#getting-started) +- [Environment Variables](#environment-variables) +- [Project Structure](#project-structure) +- [Open Source Contributions](#open-source-contributions) +- [Roadmap](#roadmap) + +--- + +## Overview + +Crypto Butler is a conversational DeFi agent. Instead of navigating complex protocol interfaces, users simply describe what they want: + +> "Grow my 5000 USDC at moderate risk over 12 months" + +The system deploys three specialized AI agents that research live yields, profile risk tolerance, and return a plain-English allocation strategy with projected returns — all simulated on Cardano Preprod testnet. + +The product targets two audiences: +- Crypto-native users who want intelligent yield optimization without manual research +- Emerging market users (starting with Kenya) who need a simple, mobile-first entry point into DeFi with M-Pesa integration planned for a future release + +--- + +## Architecture +``` +User Input (natural language goal) + | + v + Orchestrator (Next.js API Route) + | + +-----+-----+ + | | | + v v v +Research Risk CFO +Agent Agent Agent + | | | + +-----+-----+ + | + v + Recommendation + (allocation + projections) + | + v + Testnet Simulation + (Cardano Preprod) + | + v + UI Dashboard + (charts + tx log) +``` + +--- + +## Tech Stack + +| Layer | Technology | +|---|---| +| Frontend | Next.js 14, Tailwind CSS | +| AI Agents | Anthropic Claude claude-sonnet-4-20250514 | +| Wallet (Social) | UTXOS.dev Wallet-as-a-Service | +| Wallet (Native) | CIP-30 direct browser API | +| Yield Data | DeFiLlama API | +| Blockchain | Cardano Preprod Testnet | +| Blockchain Data | Blockfrost | +| Charts | Recharts | +| Deployment | Vercel | + +--- + +## Multi-Agent System + +The core of Crypto Butler is a three-agent swarm. Each agent has a single responsibility and passes structured JSON to the next. + +### Agent 1: Researcher + +Fetches live yield data from DeFiLlama and identifies the top opportunities across risk categories. +```javascript +// app/api/butler/route.js + +async function researcherAgent(yields) { + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 1000, + system: `You are a DeFi yield researcher. + Analyze yield opportunities and return ONLY valid JSON.`, + messages: [{ + role: 'user', + content: `Analyze these yield pools and identify the top 6 + opportunities across risk categories. + + Pools: ${JSON.stringify(yields, null, 2)} + + Return ONLY this JSON structure: + { + "conservative": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}], + "moderate": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}], + "aggressive": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}] + }` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} +``` + +### Agent 2: Risk Analyst + +Parses the user's natural language goal to extract risk tolerance, time horizon, and target amount. Scores each opportunity for fit. +```javascript +async function riskAgent(userGoal, researcherOutput) { + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 800, + system: `You are a risk analyst for DeFi portfolios. + Return ONLY valid JSON.`, + messages: [{ + role: 'user', + content: `User goal: "${userGoal}" + Available opportunities: ${JSON.stringify(researcherOutput)} + + Extract: + 1. Risk tolerance (conservative/moderate/aggressive) + 2. Time horizon in months + 3. Target amount in USD + 4. Primary goal (grow/preserve/income) + + Score each opportunity 1-10 for fit. + + Return ONLY this JSON: + { + "riskProfile": { + "tolerance": "moderate", + "timeHorizonMonths": 12, + "targetAmountUsd": 5000, + "primaryGoal": "grow" + }, + "scoredOpportunities": [ + { + "protocol": "", + "pool": "", + "apy": 0, + "fitScore": 8, + "rationale": "" + } + ] + }` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} +``` + +### Agent 3: CFO + +Takes the scored opportunities and builds a complete portfolio allocation with projections, risks, and plain-English explanation. +```javascript +async function cfoAgent(userGoal, riskOutput) { + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 1500, + system: `You are a personal CFO and DeFi wealth manager. + Explain complex finance simply. Return ONLY valid JSON.`, + messages: [{ + role: 'user', + content: `User goal: "${userGoal}" + Risk profile: ${JSON.stringify(riskOutput.riskProfile)} + Top opportunities: ${JSON.stringify(riskOutput.scoredOpportunities)} + + Return ONLY this JSON: + { + "greeting": "", + "summary": "", + "allocation": [ + { + "protocol": "", + "pool": "", + "chain": "", + "apy": 0, + "percentage": 40, + "amountUsd": 2000, + "role": "Core yield engine", + "reasoning": "" + } + ], + "projections": { + "months3": 0, + "months6": 0, + "months12": 0, + "blendedApy": 0 + }, + "risks": [], + "butlerNote": "" + }` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} +``` + +--- + +## UTXOS.dev Integration + +Crypto Butler uses UTXOS.dev to enable social login wallet creation. This removes the requirement for users to have an existing Cardano wallet or browser extension — critical for the emerging market use case. + +### The Problem It Solves + +Standard Cardano wallet onboarding requires: +- Installing a browser extension +- Writing down a 24-word seed phrase +- Funding the wallet manually + +For a first-time user in Nairobi, this is a fatal barrier. UTXOS.dev replaces it with a Google or Apple login. + +### How It Is Integrated + +All UTXOS SDK calls run server-side in a Next.js API route. This avoids the WebAssembly SSR conflict that occurs when Cardano SDKs are imported in client components. +```javascript +// app/api/wallet/enable/route.js + +import { Web3Wallet } from '@utxos/sdk'; +import { BlockfrostProvider } from '@meshsdk/core'; + +export async function POST(req) { + try { + const provider = new BlockfrostProvider('/api/blockfrost/preprod/'); + + const wallet = await Web3Wallet.enable({ + projectId: process.env.UTXOS_PROJECT_ID, + networkId: 0, // 0 = preprod, 1 = mainnet + fetcher: provider, + submitter: provider, + }); + + const address = await wallet.cardano.getChangeAddress(); + const balance = await wallet.cardano.getBalance(); + + return Response.json({ address, balance }); + } catch (err) { + return Response.json({ error: err.message }, { status: 500 }); + } +} +``` + +The Blockfrost API key is kept server-side via a proxy route: +```javascript +// app/api/blockfrost/[network]/[...path]/route.js + +export async function GET(req, { params }) { + const { network, path } = params; + + const apiKey = network === 'preprod' + ? process.env.BLOCKFROST_API_KEY_PREPROD + : process.env.BLOCKFROST_API_KEY_MAINNET; + + const url = `https://cardano-${network}.blockfrost.io/api/v0/${path.join('/')}`; + + const res = await fetch(url, { + headers: { project_id: apiKey } + }); + + const data = await res.json(); + return Response.json(data); +} +``` + +### Why Server-Side +``` +Browser Server (API Route) + | | + | POST /api/wallet/enable | + |------------------------------> | + | | UTXOS SDK runs here + | | Blockfrost called here + | | WebAssembly runs here + | { address, balance } | + | <-----------------------------| + | | +No SDK in browser No SSR conflict +``` + +--- + +## Wallet Connection + +The app supports two wallet connection methods side by side. + +### Method 1: Social Login via UTXOS.dev + +For new users with no existing Cardano wallet. Login with Google or Apple creates a non-custodial wallet automatically. No seed phrase. No browser extension. +```javascript +// components/WalletConnect.jsx + +async function connectSocial(provider) { + try { + const res = await fetch('/api/wallet/enable', { method: 'POST' }); + const { address, balance } = await res.json(); + setAddress(address.slice(0, 8) + '...' + address.slice(-4)); + setConnected(true); + onConnected?.({ address, balance }, 'social'); + } catch (err) { + console.error('Social login failed:', err); + } +} +``` + +### Method 2: CIP-30 Native Wallet + +For existing Cardano users with Eternl, Nami, Vespr, or other CIP-30 compatible wallets. Uses the standard `window.cardano` browser API directly — no SDK required. +```javascript +// components/WalletConnect.jsx + +useEffect(() => { + if (typeof window === 'undefined') return; + const knownWallets = ['eternl', 'nami', 'vespr', 'flint', 'typhon']; + const detected = knownWallets + .filter(name => window.cardano?.[name]) + .map(name => ({ + name, + icon: window.cardano[name].icon, + api: window.cardano[name] + })); + setWallets(detected); +}, []); + +async function connectWallet(wallet) { + const api = await wallet.api.enable(); + const addresses = await api.getUsedAddresses(); + const addr = addresses[0]; + setAddress(addr.slice(0, 8) + '...' + addr.slice(-4)); + setConnected(true); + onConnected?.(api, 'cip30'); +} +``` + +--- + +## Yield Data + +Live yield data is fetched from the DeFiLlama Pools API at request time. No API key required. +```javascript +// app/api/butler/route.js + +async function fetchYields() { + const res = await fetch('https://yields.llama.fi/pools', { + next: { revalidate: 300 }, // cache for 5 minutes + }); + const data = await res.json(); + + return data.data + .filter(p => + p.stablecoin && + p.tvlUsd > 1_000_000 && + p.apy > 0 && + p.apy < 100 && + ['Cardano', 'Ethereum', 'Arbitrum'].includes(p.chain) + ) + .sort((a, b) => b.tvlUsd - a.tvlUsd) + .slice(0, 20) + .map(p => ({ + protocol: p.project, + pool: p.symbol, + chain: p.chain, + apy: parseFloat(p.apy.toFixed(2)), + tvlUsd: p.tvlUsd, + })); +} +``` + +Cardano-native protocols included in the filter: Liqwid, Minswap, Indigo, Splash. + +--- + +## Testnet Simulation + +After the CFO agent builds an allocation, the system generates a simulated set of Cardano Preprod transactions. Each transaction represents one deposit step in the strategy. +```javascript +function generateTestnetSimulation(allocation) { + return { + network: 'Cardano Preprod Testnet', + transactions: allocation.map((alloc, i) => ({ + step: i + 1, + action: `Deposit ${alloc.amountUsd.toFixed(0)} USDC + into ${alloc.protocol} ${alloc.pool}`, + protocol: alloc.protocol, + chain: 'Cardano Preprod', + amount: alloc.amountUsd, + txHash: generateMockTxHash(), + status: 'simulated', + explorerUrl: `https://preprod.cardanoscan.io/transaction/${generateMockTxHash()}`, + })), + disclaimer: 'Simulated on Cardano Preprod testnet. No real funds used.', + }; +} +``` + +--- + +## Getting Started + +### Prerequisites + +- Node.js 18 or higher +- An Anthropic API key +- A UTXOS.dev project ID +- A Blockfrost API key (Preprod) +- Eternl wallet browser extension (for CIP-30 testing) + +### Installation +```bash +git clone https://github.com/your-username/crypto-butler +cd crypto-butler +npm install +cp .env.example .env.local +``` + +Fill in your environment variables then run: +```bash +npm run dev +``` + +Open http://localhost:3000 and type a goal such as: +``` +Grow my 5000 USDC at moderate risk over 12 months +``` + +--- + +## Environment Variables +```bash +# Anthropic +ANTHROPIC_API_KEY=sk-ant-your-key-here + +# UTXOS.dev +UTXOS_PROJECT_ID=your_project_id + +# Blockfrost +BLOCKFROST_API_KEY_PREPROD=preprodxxxxxxxx +BLOCKFROST_API_KEY_MAINNET=mainnetxxxxxxxx + +# WalletConnect (optional for CIP-30) +NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id +``` + +--- + +## Project Structure +``` +crypto-butler/ + app/ + api/ + butler/ + route.js - Multi-agent orchestration + wallet/ + enable/ + route.js - UTXOS.dev wallet initialization + blockfrost/ + [network]/ + [...path]/ + route.js - Blockfrost proxy + globals.css + layout.jsx + page.jsx - Main chat interface + providers.jsx + components/ + AgentPanel.jsx - Live agent activity display + Charts.jsx - Allocation pie + projection chart + SimulationPanel.jsx - Testnet transaction log + WalletConnect.jsx - Dual wallet connection UI + .env.example + next.config.js + README.md +``` + +--- + +## Open Source Contributions + +During development we encountered a critical incompatibility between Mesh SDK and Next.js 15. Mesh SDK's dependency on `libsodium-wrappers-sumo` (WebAssembly cryptography) causes build failures when imported in any client component, even with `ssr: false` and dynamic imports. + +The root cause is that Next.js 15 with Turbopack attempts to bundle WebAssembly modules server-side during the compilation step, before the `ssr: false` directive can take effect. + +Our solution was to move all Cardano SDK usage to server-side API routes where WebAssembly runs without conflict, and implement a direct CIP-30 wallet connection for the client that requires zero SDK dependencies. + +We have documented this issue and the fix in a pull request to the MeshJS repository at github.com/MeshJS/mesh. + +--- + +## Roadmap + +**Post-Hackathon Phase 1** +- M-Pesa onramp and offramp integration (Kenya) +- Real transaction execution on Cardano mainnet +- Performance fee smart contract (10-20% of yield) + +**Phase 2** +- Autonomous rebalancing agent +- Multi-chain expansion (Base, Solana) +- Mobile application + +**Phase 3** +- TEE-based key management +- DAO governance for strategy parameters +- Expansion to Nigeria, Ghana, Tanzania diff --git a/examples/crypto-butler/app/api/blockfrost/[network]/[...path]/route.js b/examples/crypto-butler/app/api/blockfrost/[network]/[...path]/route.js new file mode 100644 index 0000000..b52bba1 --- /dev/null +++ b/examples/crypto-butler/app/api/blockfrost/[network]/[...path]/route.js @@ -0,0 +1,35 @@ +export async function GET(req, { params }) { + const { network, path } = params; + const apiKey = network === 'preprod' + ? process.env.BLOCKFROST_API_KEY_PREPROD + : process.env.BLOCKFROST_API_KEY_MAINNET; + + const url = `https://cardano-${network}.blockfrost.io/api/v0/${path.join('/')}`; + + const res = await fetch(url, { + headers: { project_id: apiKey } + }); + + const data = await res.json(); + return Response.json(data); +} + +export async function POST(req) { + try { + const { token } = await req.json(); + + const res = await fetch('https://api.utxos.dev/v1/wallet/cardano/address', { + headers: { + 'Authorization': `Bearer ${token}`, + 'x-project-id': process.env.UTXOS_PROJECT_ID, + } + }); + + const data = await res.json(); + return Response.json({ address: data.address, balance: data.balance }); + + } catch (err) { + console.error('Wallet error:', err.message); + return Response.json({ error: err.message }, { status: 500 }); + } +} diff --git a/examples/crypto-butler/app/api/butler/.route.js.swp b/examples/crypto-butler/app/api/butler/.route.js.swp new file mode 100644 index 0000000..498e0d9 Binary files /dev/null and b/examples/crypto-butler/app/api/butler/.route.js.swp differ diff --git a/examples/crypto-butler/app/api/butler/route.js b/examples/crypto-butler/app/api/butler/route.js new file mode 100644 index 0000000..d4e171c --- /dev/null +++ b/examples/crypto-butler/app/api/butler/route.js @@ -0,0 +1,248 @@ +// app/api/butler/route.js +// Multi-agent swarm: Researcher → Risk Agent → CFO Agent + +import Anthropic from '@anthropic-ai/sdk'; + +const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); + +async function fetchYields() { + try { + const res = await fetch('https://yields.llama.fi/pools', { + next: { revalidate: 300 }, + }); + const data = await res.json(); + + return data.data + .filter(p => + p.stablecoin && + p.tvlUsd > 1_000_000 && + p.apy > 0 && + p.apy < 100 && + ['Cardano', 'Ethereum', 'Arbitrum'].includes(p.chain) + ) + .sort((a, b) => b.tvlUsd - a.tvlUsd) + .slice(0, 20) + .map(p => ({ + protocol: p.project, + pool: p.symbol, + chain: p.chain, + apy: parseFloat(p.apy.toFixed(2)), + tvlUsd: p.tvlUsd, + })); + } catch (err) { + console.error('Yield fetch failed:', err); + return FALLBACK_YIELDS; + } +} + +function categorize(apy) { + if (apy < 5) return 'conservative'; + if (apy < 12) return 'moderate'; + return 'aggressive'; +} + +async function researcherAgent(yields) { + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 1000, + system: `You are a DeFi yield researcher. + Analyze yield opportunities and return ONLY valid JSON.`, + messages: [{ + role: 'user', + content: `Analyze these yield pools and identify the top 6 + opportunities across risk categories. + + Pools: ${JSON.stringify(yields, null, 2)} + + Return ONLY this JSON structure: + { + "conservative": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}], + "moderate": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}], + "aggressive": [{"protocol": "", "pool": "", "chain": "", + "apy": 0, "reasoning": ""}] + }` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} + +async function riskAgent(userGoal, researcherOutput) { + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 800, + system: `You are a risk analyst for DeFi portfolios. + Return ONLY valid JSON.`, + messages: [{ + role: 'user', + content: `User goal: "${userGoal}" + Available opportunities: ${JSON.stringify(researcherOutput)} + + Extract: + 1. Risk tolerance (conservative/moderate/aggressive) + 2. Time horizon in months + 3. Target amount in USD + 4. Primary goal (grow/preserve/income) + + Score each opportunity 1-10 for fit. + + Return ONLY this JSON: + { + "riskProfile": { + "tolerance": "moderate", + "timeHorizonMonths": 12, + "targetAmountUsd": 5000, + "primaryGoal": "grow" + }, + "scoredOpportunities": [ + { + "protocol": "", + "pool": "", + "apy": 0, + "fitScore": 8, + "rationale": "" + } + ] + }` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} + +async function cfoAgent(userGoal, riskOutput) { + const { riskProfile, scoredOpportunities } = riskOutput; + const amount = riskProfile.targetAmountUsd; + + const res = await client.messages.create({ + model: 'claude-sonnet-4-20250514', + max_tokens: 1500, + system: `You are a personal CFO and DeFi wealth manager. You explain complex finance simply, like a trusted friend who happens to be an expert. Preferred stablecoins on Cardano are iUSD, DJED, and USDM instead of USDC. Return ONLY valid JSON, no markdown.`, + messages: [{ + role: 'user', + content: `User goal: "${userGoal}" +Risk profile: ${JSON.stringify(riskProfile)} +Top opportunities (scored): ${JSON.stringify(scoredOpportunities.slice(0, 6))} + +Build an optimal portfolio allocation for $${amount}. + +Return ONLY this JSON: +{ + "greeting": "A warm 1-sentence greeting addressing their specific goal", + "summary": "2-3 sentence plain-English explanation of the strategy", + "allocation": [ + { + "protocol": "", + "pool": "", + "chain": "", + "apy": 0, + "percentage": 40, + "amountUsd": 2000, + "role": "Core yield engine", + "reasoning": "Why this fits their goal" + } + ], + "projections": { + "months3": 0, + "months6": 0, + "months12": 0, + "blendedApy": 0 + }, + "risks": ["Risk 1", "Risk 2"], + "nextSteps": "One clear action sentence", + "butlerNote": "A charming, butler-style closing remark" +}` + }] + }); + + const text = res.content[0].text.replace(/```json|```/g, '').trim(); + return JSON.parse(text); +} + +// ── MAIN ROUTE ────────────────────────────────────────────────── +export async function POST(req) { + try { + const { message, conversationHistory = [] } = await req.json(); + + if (!message) { + return Response.json({ error: 'Message required' }, { status: 400 }); + } + + // Stream agent status updates via a simple object + const agentLog = []; + + // Step 1: Fetch live yields + agentLog.push({ agent: 'researcher', status: 'fetching live yields from DeFiLlama...' }); + const yields = await fetchYields(); + + // Step 2: Researcher agent analyzes yields + agentLog.push({ agent: 'researcher', status: 'analyzing 20+ yield opportunities...' }); + const researcherOutput = await researcherAgent(yields); + + // Step 3: Risk agent scores against user goal + agentLog.push({ agent: 'risk', status: 'profiling your risk tolerance...' }); + const riskOutput = await riskAgent(message, researcherOutput); + + // Step 4: CFO builds the recommendation + agentLog.push({ agent: 'cfo', status: 'building your personalized strategy...' }); + const cfoOutput = await cfoAgent(message, riskOutput); + + // Step 5: Generate testnet simulation + const simulation = generateTestnetSimulation(cfoOutput.allocation, riskOutput.riskProfile); + + return Response.json({ + success: true, + agentLog, + recommendation: cfoOutput, + riskProfile: riskOutput.riskProfile, + simulation, + yieldsAnalyzed: yields.length, + }); + + } catch (error) { + console.error('Butler error:', error); + return Response.json({ error: error.message }, { status: 500 }); + } +} + +function generateTestnetSimulation(allocation, riskProfile) { + const txs = allocation.map((alloc, i) => ({ + step: i + 1, + action: `Deposit ${alloc.amountUsd.toFixed(0)} USDC → ${alloc.protocol} ${alloc.pool}`, + protocol: alloc.protocol, + chain: 'Cardano Preprod', + amount: alloc.amountUsd, + txHash: `0x${randomHex(64)}`, + status: 'simulated', + gasEstimate: `~$${(Math.random() * 0.05 + 0.01).toFixed(3)}`, + explorerUrl: `https://preprod.cardanoscan.io/transaction/${randomHex(64)}`, + })); + + return { + network: 'Cardano Preprod Testnet', + totalTransactions: txs.length, + totalGasEstimate: `~$${(txs.length * 0.02).toFixed(3)}`, + transactions: txs, + disclaimer: 'Simulated on Cardano Preprod testnet. No real funds used.', + }; +} + +function randomHex(len) { + return Array.from({ length: len }, () => + Math.floor(Math.random() * 16).toString(16) + ).join(''); +} + +// ── FALLBACK YIELDS (if DeFiLlama is down) ───────────────────── +const FALLBACK_YIELDS = [ + { protocol: 'liqwid', pool: 'USDC', chain: 'Cardano', apy: 7.2, tvlUsd: 45_000_000, category: 'moderate' }, + { protocol: 'minswap', pool: 'ADA/USDC', chain: 'Cardano', apy: 9.1, tvlUsd: 22_000_000, category: 'moderate' }, + { protocol: 'indigo', pool: 'iUSD', chain: 'Cardano', apy: 5.8, tvlUsd: 18_000_000, category: 'conservative' }, + { protocol: 'splash', pool: 'USDC', chain: 'Cardano', apy: 8.4, tvlUsd: 15_000_000, category: 'moderate' }, + { protocol: 'wingriders', pool: 'USDC', chain: 'Cardano', apy: 6.5, tvlUsd: 12_000_000, category: 'moderate' }, + { protocol: 'sundae', pool: 'USDC', chain: 'Cardano', apy: 7.8, tvlUsd: 10_000_000, category: 'moderate' }, +]; diff --git a/examples/crypto-butler/app/globals.css b/examples/crypto-butler/app/globals.css new file mode 100644 index 0000000..f16495c --- /dev/null +++ b/examples/crypto-butler/app/globals.css @@ -0,0 +1,95 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --navy-900: #0a0e27; + --navy-800: #1a1f3a; + --navy-700: #2d3561; + --gold-500: #fbbf24; + --gold-400: #f59e0b; + --success: #10b981; + --danger: #ef4444; +} + +* { + font-family: 'Inter', sans-serif; +} + +body { + background: linear-gradient(135deg, var(--navy-900) 0%, var(--navy-800) 100%); + color: #e2e8f0; + min-height: 100vh; +} + +/* Scrollbar styling */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--navy-800); +} + +::-webkit-scrollbar-thumb { + background: var(--navy-700); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--navy-600); +} + +/* Animations */ +@keyframes pulse-gold { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +.animate-pulse-gold { + animation: pulse-gold 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +/* Glass morphism effect */ +.glass { + background: rgba(26, 31, 58, 0.8); + backdrop-filter: blur(10px); + border: 1px solid rgba(251, 191, 36, 0.1); +} + +/* Custom button styles */ +.btn-primary { + background: linear-gradient(135deg, var(--gold-500), var(--gold-400)); + color: var(--navy-900); + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-primary:hover { + transform: translateY(-1px); + box-shadow: 0 10px 25px rgba(251, 191, 36, 0.3); +} + +/* Chat message styling */ +.message-user { + background: linear-gradient(135deg, var(--navy-700), var(--navy-600)); + border-left: 3px solid var(--gold-500); +} + +.message-butler { + background: rgba(26, 31, 58, 0.6); + border: 1px solid rgba(251, 191, 36, 0.2); +} + +/* Agent status indicators */ +.agent-active { + background: linear-gradient(135deg, var(--gold-500), var(--gold-400)); + color: var(--navy-900); +} + +.agent-idle { + background: var(--navy-700); + color: #94a3b8; +} diff --git a/examples/crypto-butler/app/layout.jsx b/examples/crypto-butler/app/layout.jsx new file mode 100644 index 0000000..c8d3a01 --- /dev/null +++ b/examples/crypto-butler/app/layout.jsx @@ -0,0 +1,37 @@ +// app/layout.jsx +import { Playfair_Display, DM_Sans, DM_Mono } from 'next/font/google'; +import './globals.css'; +import { Providers } from './providers'; + +const display = Playfair_Display({ + subsets: ['latin'], + variable: '--font-display', + weight: ['400', '600', '700'], +}); + +const body = DM_Sans({ + subsets: ['latin'], + variable: '--font-body', + weight: ['300', '400', '500', '600'], +}); + +const mono = DM_Mono({ + subsets: ['latin'], + variable: '--font-mono', + weight: ['300', '400', '500'], +}); + +export const metadata = { + title: 'Crypto Butler — Your DeFi Wealth Agent', + description: 'AI-powered DeFi portfolio management. Set your goals, let the Butler work.', +}; + +export default function RootLayout({ children }) { + return ( + +
+Your DeFi Wealth Agent · Cardano Preprod
++ Tell me your financial goal and I will deploy a team of AI agents to find the best DeFi strategy for you — live yields, risk-adjusted, ready to execute. +
+ + {!walletConnected && ( +{msg.content}
+⚠️ {msg.content}
+{rec.greeting}
+ {riskProfile && ( +{rec.summary}
+ +Blended APY
+{rec.projections?.blendedApy?.toFixed(1)}%
+Protocols
+{rec.allocation?.length}
+⚠️ Key Risks
++ "{rec.butlerNote}" +
++ {a.protocol} {a.pool} +
+ {a.apy}% APY +{a.role} · {a.chain}
+{a.reasoning}
+See the Testnet panel on the right →
++ Agent Swarm +
+ + {allAgents.map((agentKey) => { + const agent = AGENTS[agentKey]; + const isActive = isLoading && activeAgent === agentKey; + const isDone = completed.has(agentKey) && !isActive; + const log = agentLog.filter(l => l.agent === agentKey).pop(); + + return ( ++ {log.status} +
+ )} +Projected at 12mo
++ ${projections.months12?.toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',')} +
+Total gain
++${gain.toFixed(0)} ({gainPct}%)
++ Testnet Simulation +
+Transactions
+{simulation.totalTransactions}
+Est. Gas
+{simulation.totalGasEstimate}
+{tx.action}
+{tx.txHash}
+{simulation.disclaimer}
++ No wallet needed — powered by UTXOs.dev +
++ Connect your Cardano wallet +
+ {wallets.length === 0 ? ( +No wallet detected.
+ + Install Eternl → + +