Review Date: 2026-02-21 Scope: Product UI/UX audit against QuickLend's vision of seamless lending interaction accessible to new crypto users Methodology: Full codebase review of frontend/, landing-page/, backend/, smart-contract/, and all documentation
QuickLend's vision is to provide the best UI/UX for supplying and borrowing tokens -- so intuitive that even first-time crypto users can navigate it confidently. The current implementation demonstrates strong visual design foundations: a polished glassmorphism aesthetic, the innovative Health Dial, real-time projected Health Factor preview, transaction lifecycle toasts, and a well-structured component architecture.
A previous review cycle addressed several critical bugs (withdraw/repay action mapping, hardcoded liquidation prices, history page showing raw addresses) and added important UX features (tooltips, WelcomeModal, toast notifications, landing page). These improvements have moved the product forward significantly.
However, this fresh review reveals new critical gaps that were not previously identified -- most notably a broken token approval flow that blocks all first-time supply attempts, missing confirmation steps before irreversible transactions, and absent error recovery mechanisms. The product still caters more to users who already understand DeFi than to the newcomers it aspires to onboard.
| Dimension | Score | Delta from Previous | Notes |
|---|---|---|---|
| Visual Design | 8.5/10 | +0.5 | Strong glassmorphism, consistent palette, good motion, but token "icons" are still letter circles |
| New-User Onboarding | 6/10 | -1 | WelcomeModal is informational-only; no guided first action; no progressive disclosure |
| DeFi Literacy Support | 7/10 | = | Tooltips cover major terms; still no "Learn" section or deeper education |
| Core User Flow (Supply) | 4/10 | -4 | Token approval hook exists but is NOT wired into ActionCard -- first supply attempts fail |
| Core User Flow (Borrow) | 7/10 | -1 | Works, but borrow button uses red "danger" styling creating negative friction |
| Transaction Safety | 5/10 | NEW | No confirmation step before signing; no collateral toggle guard; no error boundaries |
| Mobile UX | 4/10 | = | Sidebar collapses but no bottom nav, no hamburger menu |
| Trust & Safety Signals | 7/10 | = | Landing page has audit section; main app still lacks in-app trust signals |
| Product Marketing | 7.5/10 | +0.5 | Landing page is comprehensive; SEO/social metadata still minimal |
| Accessibility | 3/10 | NEW | No focus traps in modals, missing ARIA attributes, no keyboard navigation |
| Strength | Implementation | File Reference |
|---|---|---|
| Glassmorphism theme | Consistent glass-panel / glass-panel-strong CSS classes with backdrop blur |
globals.css:28-43 |
| Dark mode by default | Deep space background (#05050A) with vibrant accent contrasts |
globals.css:5-6, layout.tsx:20 |
| Color-coded risk signals | Green (#42e695) / Amber (#FFB800) / Red (#FF4B4B) consistently applied | HealthDial.tsx:25-29, ActionCard.tsx:59-63 |
| Monospace numbers | Roboto Mono prevents layout jitter during real-time updates | layout.tsx:13-16 |
| Smooth micro-interactions | Framer Motion throughout -- spring physics on dial, button scale, entrance animations | Button.tsx:33-34, HealthDial.tsx:74-78 |
| Ambient background orbs | Soft colored gradients create depth without distraction | layout.tsx:34-37 |
| Strength | Details | File Reference |
|---|---|---|
| Health Factor Dial | Semi-circular SVG gauge with animated needle; spatial processing is faster than reading decimals | HealthDial.tsx |
| Dual-Action Input | ActionCard shows current HF -> projected HF in real-time as user types |
ActionCard.tsx:191-209 |
| Projected Liquidation Price | Dynamic calculation shown during borrow/repay with color-coded direction | ActionCard.tsx:213-243 |
| Welcome Modal | First-visit onboarding with 3 steps, persisted via localStorage | WelcomeModal.tsx, page.tsx:39-48 |
| Contextual tooltips | Key DeFi terms explained in plain language on hover/focus | Tooltip.tsx, used in dashboard/markets/ActionCard |
| Empty state CTAs | Dashboard shows best APY and direct supply button when no positions exist | page.tsx:163-186 |
| Toast lifecycle | Pending -> Confirming -> Success/Error tracking through full tx lifecycle | useActionModal.ts:28-85, ToastContainer.tsx |
| Supply/Withdraw toggle | One modal handles paired actions via tab toggle | ActionCard.tsx:114-166 |
| Personalized greeting | Time-aware navbar greeting with wallet address | Navbar.tsx:24-55 |
- Atomic design with atoms (
Button,GlassCard,Tooltip,TokenIcon,TickerNumber), organisms, and page templates - Hook-based logic cleanly separates data fetching (
useMarkets,useUserPositions), write actions (useLendingActions), UI orchestration (useActionModal), and token approval (useTokenApproval) - 5 distinct pages (Dashboard, Markets, Portfolio, History, Settings) providing a complete navigation structure
- RainbowKit integration with dark theme provides familiar wallet connection
- TanStack Query with 15s refetch interval keeps data fresh without manual refreshing
- Separate landing page project with comprehensive marketing sections
The following items from the prior review have been confirmed as implemented:
- ActionCard supports all 4 action types (supply/withdraw/borrow/repay) with correct toggle switching
- Liquidation price is dynamically calculated from
calculateHealthFactor(), not hardcoded - History page resolves contract addresses to token symbols using market data
- Transaction toasts track the full wallet confirmation -> chain confirmation -> success/error lifecycle
- Wallet dropdown has working copy-address and view-on-explorer functions
- Portfolio page has a functional collateral toggle wired to
setCollateralcontract call - Navbar shows contextual greeting based on time of day and connection status
Problem: The useTokenApproval hook (hooks/useTokenApproval.ts) is fully implemented -- it reads ERC-20 allowances, checks if approval is needed, and can execute approve() calls. However, it is never integrated into the ActionCard or useActionModal. The ActionCard directly calls supply() or repay() without first checking or requesting token approval.
Evidence:
useTokenApproval.tsexportsneedsApproval(),approveMax(),approveAmount()-- none called anywhereuseActionModal.ts:107-108callssupply(assetAddress, amount, decimals)directlyActionCard.tsx:257-265firesonConfirm(parseFloat(amount), action)with no approval check
Impact: Every first-time supply or repay attempt will fail with a contract revert. This is the single most damaging UX bug because it blocks the very first meaningful user action. The error message shown in the toast will be a truncated Solidity revert string, which is incomprehensible to new users.
Recommendation:
- Integrate
useTokenApprovalintouseActionModalor the ActionCard - Show a two-step flow when allowance is insufficient:
- "Approve USDC" button (with explanation: "This gives QuickLend permission to use your tokens. One-time step per token.")
- "Supply USDC" button (enabled only after approval confirms)
- Show approval status with a checkmark and "Approved" label
- Consider supporting Permit2 for gasless approvals as a future enhancement
Problem: Clicking "Supply USDC" in the ActionCard immediately fires the blockchain transaction (ActionCard.tsx:261). There is no intermediate summary screen. The Design Philosophy document explicitly calls for showing estimated gas, but this is absent.
Impact: Users, especially newcomers, need a moment to review before committing irreversible on-chain actions. Without a review step:
- Users may accidentally supply the wrong amount (they typed "100" meaning $100 but it was 100 tokens)
- No gas fee visibility means unexpected costs
- No explicit "this is irreversible" warning
Recommendation:
- After clicking the action button, show a confirmation panel (within the same modal) summarizing:
- Action + amount + USD value
- Resulting Health Factor (already calculated)
- Estimated gas fee (use wagmi's
estimateGas) - "Confirm in Wallet" primary button + "Back" secondary button
- For actions that would push HF below 1.5, add a warning banner
Problem: There are no React Error Boundary components anywhere in the frontend. An unhandled error in any component (e.g., a contract read returning unexpected data, a wallet disconnect during rendering) will crash the entire app with a white screen.
Impact: Users lose all context and must manually reload. This is especially problematic during wallet interactions, network switches, and contract calls where errors are common.
Recommendation:
- Add error boundaries at the page level and around
Web3Provider - Show a recovery UI: "Something went wrong. Your funds are safe. [Reload Page]"
- Log errors to a tracking service for monitoring
Problem: In the Portfolio page (portfolio/page.tsx:119-131) and UserSuppliesTable (UserSuppliesTable.tsx:95-108), toggling collateral off triggers an immediate contract call with no confirmation dialog. Disabling collateral can push Health Factor below 1.0 and trigger liquidation.
Impact: One accidental tap could cause significant financial loss. This is a safety-critical interaction that needs a guard.
Recommendation:
- Show a confirmation dialog before disabling collateral, displaying:
- Current and projected Health Factor
- Warning if projected HF < 1.5
- Block the action entirely if projected HF < 1.0
- Enabling collateral (safe action) can remain one-click
Problem: The Borrow buttons use variant="danger" (red gradient #FF4B4B -> #FF416C) in the Assets to Borrow table (page.tsx:329) and in the ActionCard toggle (ActionCard.tsx:143-149). Red universally signals "warning" or "destructive action."
Impact: Borrowing is a core feature, not an inherently dangerous action. Red creates negative psychological friction that discourages a primary user flow. New users may avoid borrowing because the color signals risk.
Recommendation:
- Use the amber/gold color (
#FFB800) or primary blue for Borrow buttons -- matching the borrow APY color creates visual consistency - Reserve red exclusively for destructive actions (disconnect, liquidation warnings, withdraw-all)
Problem: TokenIcon.tsx renders a colored circle with the first letter of the token symbol (e.g., blue "U" for USDC). While the colors are brand-appropriate, there are no actual token logos.
Impact: Real token logos are universal trust signals in crypto UIs. Their absence makes the protocol feel like a prototype and makes token identification slower.
Recommendation:
- Use actual SVG token logos (source from the trustwallet/assets repository or CoinGecko)
- Fall back to the current letter-circle for unknown/unlisted tokens
- Show full token names in at least one view (e.g., "USDC" + "USD Coin" subtitle)
Problem: While data loads, the UI shows either nothing (zero/empty states) or a single Loader2 spinner (History page only). The dashboard shows "infinity" Health Factor and $0.00 stats during initial load, which is confusing.
Impact: Users cannot distinguish "loading" from "you have no data." A Health Factor of infinity looks like a bug, not a loading state.
Recommendation:
- Add shimmer skeleton components for tables, stat cards, and the Health Dial
- Show
---or a skeleton placeholder instead ofinfinity/$0.00while data is loading - Health Dial should show a neutral gray needle position during load
Problem: The sidebar collapses from 256px to 80px on mobile (Sidebar.tsx:46), showing only icons without labels. There is no bottom navigation bar, which is the standard mobile pattern.
Impact: Mobile users must reach to the far-left corner for navigation, which is poor ergonomics. Icon-only navigation without labels fails discoverability for new users.
Recommendation:
- Add a fixed bottom tab bar for screens < 768px: Dashboard, Markets, Portfolio, History
- Hide the sidebar entirely on mobile
- Keep Settings accessible from a profile icon in the navbar
Problem: The History page shows truncated tx hashes with an ExternalLink icon (history/page.tsx:128-130), but these are rendered as a <span>, not an <a> tag. Users cannot click to verify transactions on a block explorer.
Impact: Reduces trust and makes transaction debugging impossible. Block explorer verification is a fundamental DeFi UX expectation.
Recommendation:
- Wrap tx hashes in
<a>tags linking to the chain's block explorer - Use
chain.blockExplorers.default.url(already available via wagmi) to construct URLs
Problem: The liquidation price is only visible inside the ActionCard modal during borrow/repay actions (ActionCard.tsx:213-243). On the dashboard, users cannot see at a glance what price movement would trigger liquidation.
Impact: The most critical risk metric is hidden behind an action modal that users have no reason to open just to check risk.
Recommendation:
- Add a liquidation price indicator to the dashboard hero section, next to the Health Factor
- Show per-asset liquidation prices in the Your Borrows section
- Consider: "Your WETH will be liquidated if its price drops to $X"
Problem: Neither ActionCard nor WelcomeModal implements focus trapping. Pressing Tab moves focus to elements behind the modal. Pressing Escape doesn't close the modal. No role="dialog" or aria-modal="true" attributes.
Impact: WCAG 2.1 compliance failure. Also poor experience for keyboard users and screen reader users.
Recommendation:
- Add focus trap to all modals (use a library like
focus-trap-reactor implement manually) - Close modals on Escape key
- Add
role="dialog",aria-modal="true", andaria-labelledbyattributes - Ensure all interactive elements have visible focus indicators (currently some only show on hover)
Problem: The landing page exists as a separate Next.js project (landing-page/), but the main frontend app (frontend/) drops all visitors -- authenticated or not -- directly onto the Dashboard at /. There is no routing from the landing page to the app, no shared navigation, and no in-app hero for disconnected users.
Impact: The landing page's marketing value is disconnected from the app experience. A user who arrives at the app URL directly (not through the landing page) sees a dashboard with a "Connect Wallet" prompt but no value proposition or context.
Recommendation:
- Option A: Integrate a lightweight hero section into the main app's disconnected state (expand the current "Connect Your Wallet" card into a mini landing page with feature highlights)
- Option B: Set up routing so the app root redirects to the landing page for unauthenticated visitors
- Either way, the landing page's "Launch App" CTA should link to the frontend app URL
Problem: While the landing page has SecuritySection and StatsSection, the main application UI shows no trust signals -- no TVL, no audit badge, no user count, no "non-custodial" label.
Impact: Users who arrive at the app directly (bookmarked, shared link) see no social proof. DeFi users evaluate protocol safety partly through visible trust indicators.
Recommendation:
- Add a subtle footer to the app with: audit badge, open-source link, TVL counter
- Show total TVL in the Markets page header (data available from backend
/api/v1/analytics/tvl) - Add a small "Audited" badge near the logo in the sidebar
Problem: QuickLend targets new crypto users but provides no educational content beyond brief tooltip text. DeFi concepts (over-collateralization, liquidation, interest rate models, Health Factor management strategies) are never explained in depth.
Impact: New users must learn DeFi from external sources, creating friction and abandonment risk.
Recommendation:
- Add a "Learn" section accessible from the sidebar with beginner-friendly articles:
- "What is DeFi Lending?"
- "Understanding Health Factor and Avoiding Liquidation"
- "Supply vs. Borrow: Which Strategy Is Right for You?"
- Add contextual "Learn more" links in tooltips
- Consider an interactive risk simulator: "See how different amounts affect your Health Factor"
Problem: The main app has minimal metadata: title: "QuickLend", description: "Hyper-Modern DeFi Lending Protocol" (layout.tsx:18-21). No Open Graph tags, no Twitter Card meta, no branded favicon.
Impact: Shared links on Twitter/Discord show no preview. Search engine discoverability is minimal.
Recommendation:
- Add OG and Twitter Card meta tags with a preview image showing the Health Dial UI
- Write a compelling description for each route
- Add branded favicons and Apple touch icons
Problem: The Settings page currency selector (USD/EUR/GBP) and language dropdown are local React state only. They don't persist on refresh and don't affect the app. formatCurrency() in utils.ts:8-15 is hardcoded to USD. Notification toggles are cosmetic only.
Impact: Users who change settings see them reset on reload. Creates a broken experience.
Recommendation:
- Either implement with persistence (localStorage + context) and wire into
formatCurrency() - Or remove non-functional controls to avoid false expectations
- Wire notification preferences to the backend
notificationPreferencestable (schema already exists)
Problem: The components/molecules/ directory has no components. The architecture jumps from atoms to organisms.
Impact: Repeated UI patterns are implemented inline rather than as reusable composables.
Recommendation:
- Extract common patterns:
StatCard(label + monospace value + optional tooltip) -- used in dashboard, markets, portfolioAssetRow(token icon + symbol + value) -- used in every tableSearchInput(glass input + search icon) -- duplicated between pages
Problem: No manifest.json, no service worker, no installability. The design philosophy states "Mobile-First" but there's no progressive web app support.
Recommendation:
- Add a web app manifest with icons and theme color
- Implement a service worker for the app shell
- This aligns with the mobile-first philosophy and enables home-screen installation
| Feature | Competitive Edge | Marketing Angle |
|---|---|---|
| Health Factor Dial | No other lending protocol uses a visual gauge. Aave and Compound show raw numbers. | "See your risk, don't just read it." |
| Real-time Projected HF | Users see impact before signing. Aave shows this but less visually. | "Know your outcome before you commit." |
| Glassmorphism Design | Distinctive visual brand vs "corporate DeFi" look of Aave/Compound. | "DeFi that looks as modern as it works." |
| One-Modal Actions | Supply/withdraw and borrow/repay toggle in one modal. No page navigation needed. | "Supply, withdraw, borrow, repay -- all in one place." |
| Animated Transitions | Spring physics, entrance animations, ticker numbers create a premium feel. | "Every interaction feels intentional." |
| Feature | Why It Matters | Priority |
|---|---|---|
| One-Click Approve+Supply | Eliminate the multi-step approval dance. Detect missing allowance, batch approve+supply seamlessly. | Critical |
| Interactive Risk Simulator | Let users drag a slider to see "what if ETH drops 30%?" -- Health Dial updates live. No competitor offers this. | High |
| Plain-English Liquidation Alerts | Instead of "HF < 1.0", show "If ETH drops to $1,850, your collateral will be partially sold to repay debt." | High |
| Portfolio Performance Graph | Show historical net worth and APY using marketSnapshots data (already indexed by backend). |
Medium |
| Health Factor Push Alerts | Notify via email/push when HF approaches danger. Backend notificationPreferences schema exists. |
Medium |
| Mobile-Native PWA | Bottom nav + swipe gestures + home screen install. | Medium |
| APY Sparkline Charts | 7/30-day APY trends per market using stored marketSnapshots. |
Low |
| Feature | Aave | Compound | QuickLend |
|---|---|---|---|
| Real-time HF preview as you type | Partial | No | Yes |
| Visual health gauge | No | No | Yes (Dial) |
| UI learning curve | High | Very High | Lower |
| New user onboarding | Minimal | None | WelcomeModal (improve to guided flow) |
| Mobile experience | Adequate | Poor | Needs bottom nav |
| Gasless approvals (EIP-2612) | Yes (some tokens) | No | Not yet (roadmap) |
| Educational content | Academy (separate) | Docs only | Not yet (add Learn section) |
These must be fixed before any user acquisition effort.
| # | Item | Type | Impact |
|---|---|---|---|
| 1 | Wire useTokenApproval into ActionCard supply/repay flow |
Bug | Unblocks all first-time supply attempts |
| 2 | Add transaction confirmation/review step before wallet popup | UX | Prevents accidental transactions |
| 3 | Add collateral toggle confirmation dialog with projected HF | Safety | Prevents accidental liquidation |
| 4 | Add React error boundaries at page and provider level | Stability | Prevents white-screen crashes |
| 5 | Make tx hashes clickable links to block explorer in History | UX | Enables transaction verification |
Close the gap between "polished dashboard" and "accessible for everyone."
| # | Item | Type | Impact |
|---|---|---|---|
| 6 | Replace WelcomeModal with step-by-step guided first-action flow | UX | Guides new users through their first supply |
| 7 | Add fiat on-ramp guidance for zero-balance wallets | UX | Eliminates "I have no tokens" dead-end |
| 8 | Fix borrow button color (amber/blue instead of danger red) | UX | Removes negative friction from core action |
| 9 | Add loading skeleton states for all data-dependent views | UX | Eliminates confusing zero/infinity states |
| 10 | Connect landing page to main app (routing or in-app hero) | Product | Creates coherent entry experience |
Differentiate and retain users.
| # | Item | Type | Impact |
|---|---|---|---|
| 11 | Add in-app trust signals (TVL, audit badge, non-custodial label) | Trust | Builds confidence for new users |
| 12 | Replace letter-circle token icons with real SVG logos | Polish | Makes the app feel production-ready |
| 13 | Add liquidation price indicator to dashboard | Safety | Surfaces critical risk info without modal |
| 14 | Add educational "Learn" section with DeFi explainers | Education | Reduces concept barrier for newcomers |
| 15 | Implement settings persistence (localStorage + context) | Completeness | Settings that actually work |
Build features no competitor has.
| # | Item | Type | Impact |
|---|---|---|---|
| 16 | Interactive risk simulator (slider + live Health Dial) | Differentiator | Unique feature for risk education |
| 17 | Portfolio performance charts (historical net worth + APY) | Engagement | Uses existing marketSnapshots data |
| 18 | Mobile bottom navigation bar | Mobile | Standard mobile UX pattern |
| 19 | PWA support (manifest + service worker) | Mobile | Home-screen installability |
| 20 | Modal accessibility (focus traps, Escape key, ARIA) | Accessibility | WCAG compliance |
| 21 | Push/email alerts for Health Factor thresholds | Retention | Backend schema already exists |
QuickLend's design system and core interaction patterns are above average for the DeFi space. The Health Dial, projected Health Factor preview, and glassmorphism aesthetic create a distinctive brand identity that differentiates it from the utilitarian interfaces of Aave and Compound.
However, the product has a critical functional gap: the token approval flow is implemented but not connected, meaning every first-time supply attempt will fail. This must be fixed before any marketing or user acquisition effort.
Beyond that, the product currently assumes its users understand DeFi concepts, have tokens ready, and know how wallet approvals work. Closing the gap between "polished DeFi dashboard" and "accessible lending for everyone" requires:
- Quick to start -- Fix the approval flow, add a confirmation step, connect the landing page
- Quick to understand -- Build guided onboarding, add educational content, use plain language for risk
- Quick to act -- Already strong; maintain the one-modal design and real-time previews
The "Quick" in QuickLend should mean: quick to understand, quick to start, quick to act. The current implementation delivers well on "quick to act" but needs focused work on "quick to understand" and "quick to start."