Skip to content

divij-mot/basement

Repository files navigation

Basement

AI-Powered DeFi Trading on Base

Basement is an AI trading assistant which lets you swap tokens on Base using natural language. Sign in with Google or email — no MetaMask or browser extension needed. Tell the AI what you want ("buy $50 of UNI", "diversify into DeFi blue chips"), review the proposed swap plan, and click Execute. The server handles everything from there, even if you close your browser.

Architecture

+-------------------+       +------------------------+       +--------------------+
|   Client (React)  | ----> |   Next.js API Routes   | ----> | Uniswap Trade API  |
|                   |       |                        |       |       (Base)       |
|  Privy Auth       |       |  /api/agent   (Claude) |       +--------------------+
|  Zustand Store    |       |  /api/execute (Swaps)  |
|  Status Polling   |       |  /api/quote   (Proxy)  |       +--------------------+
|                   |       |  /api/swap    (Proxy)  | ----> | Privy Wallet API   |
+-------------------+       |  /api/order   (Proxy)  |       | (Server Signing)   |
                            |  /api/approval(Proxy)  |       +--------------------+
                            +------------------------+

Key insight: The user's embedded wallet is created and managed by Privy. When the user clicks Execute, the server signs and broadcasts transactions using Privy's server-side wallet API — no browser wallet interaction needed.

Tech Stack

Layer Technology
Framework Next.js 14 (App Router)
Auth & Wallets Privy (embedded wallets, email/Google login)
AI Claude (Anthropic) with tool use
DEX Uniswap Trade API (Classic + UniswapX)
Chain Base (Coinbase L2)
Blockchain viem (public client, wallet client)
State Zustand
Styling Tailwind CSS
Animations Framer Motion
Notifications Sonner

Getting Started

Prerequisites

Install

git clone <repo-url>
cd basement
npm install --legacy-peer-deps

Privy Dashboard Setup

  1. Create an app at dashboard.privy.io
  2. Login methods — enable Email and Google under "Login Methods"
  3. Embedded wallets — enable "Create embedded wallet on login" for Ethereum
  4. Generate a P256 key pair for server-side wallet signing:
    npx @privy-io/node generate-p256-key-pair
    This outputs a publicKey and privateKey (base64-encoded PKCS8)
  5. Register a Key Quorum — in the Privy dashboard under "Server Wallets", create a key quorum using the public key from step 4. Note the Key Quorum ID.
  6. Copy the App ID, App Secret, Authorization Private Key (from step 4), and Key Quorum ID into your .env.local

Environment Variables

Copy .env.example to .env.local and fill in values:

cp .env.example .env.local
Variable Description Where to get it
UNISWAP_API_KEY Uniswap Trade API key hub.uniswap.org
ANTHROPIC_API_KEY Claude API key console.anthropic.com
ALCHEMY_API_KEY Alchemy API key (server-side RPC) alchemy.com
NEXT_PUBLIC_ALCHEMY_API_KEY Alchemy RPC URL (client-side, optional) Same as above
COINGECKO_API_KEY CoinGecko API key (token prices) coingecko.com/en/api
NEXT_PUBLIC_PRIVY_APP_ID Privy App ID Privy Dashboard > Settings
PRIVY_APP_SECRET Privy App Secret Privy Dashboard > Settings
PRIVY_AUTHORIZATION_KEY Base64-encoded P256 private key Generated in step 4 above
NEXT_PUBLIC_PRIVY_KEY_QUORUM_ID Key Quorum ID for signer delegation Privy Dashboard > Server Wallets

Run

npm run dev

Open http://localhost:3000.

Project Structure

basement/
├── app/
│   ├── layout.tsx              # Root layout with fonts
│   ├── page.tsx                # Main page (sidebar + chat)
│   ├── providers.tsx           # PrivyProvider + Toaster
│   ├── globals.css             # Tailwind + custom properties
│   └── api/
│       ├── agent/route.ts      # Claude AI agent with tool use
│       ├── execute/route.ts    # Server-side swap execution + polling
│       ├── quote/route.ts      # Uniswap quote proxy
│       ├── swap/route.ts       # Uniswap classic swap proxy
│       ├── order/route.ts      # Uniswap UniswapX order proxy
│       └── approval/route.ts   # Token approval check proxy
├── components/
│   ├── layout/
│   │   ├── Header.tsx          # Logo + chain badge + Privy auth
│   │   ├── Sidebar.tsx         # Portfolio sidebar
│   │   └── MainArea.tsx        # Chat + swap plan area
│   ├── agent/
│   │   ├── AgentChat.tsx       # Chat message list
│   │   ├── IntentInput.tsx     # Natural language input
│   │   ├── MessageBubble.tsx   # Individual message
│   │   └── ThinkingIndicator.tsx
│   ├── portfolio/
│   │   ├── PortfolioHeader.tsx # Total value display
│   │   ├── TokenList.tsx       # Token balances
│   │   ├── AllocationChart.tsx # Pie chart
│   │   └── ActivityFeed.tsx    # Recent swaps
│   ├── swap/
│   │   ├── SwapPlanCard.tsx    # Proposed swap plan UI
│   │   ├── SwapRow.tsx         # Individual swap in plan
│   │   ├── SwapStatus.tsx      # Status indicator
│   │   └── ExecutionTracker.tsx# Progress during execution
│   └── ui/                     # Shared UI primitives
│       ├── Badge.tsx
│       ├── Button.tsx
│       ├── Card.tsx
│       ├── Input.tsx
│       ├── Skeleton.tsx
│       └── TokenIcon.tsx
└── lib/
    ├── privy/
    │   └── server.ts           # PrivyClient singleton + wallet helpers
    ├── hooks/
    │   ├── usePrivyAuth.ts     # Privy auth state + auto-delegation
    │   ├── useAgent.ts         # Chat with AI agent
    │   ├── usePortfolio.ts     # Portfolio data fetching
    │   └── useSwapExecution.ts # Server execution + polling
    ├── ai/
    │   ├── prompt.ts           # System prompt + tool definitions
    │   ├── tools.ts            # Tool call execution
    │   └── quoteEnricher.ts    # Quote enrichment for AI
    ├── uniswap/
    │   ├── client.ts           # Axios clients (direct + proxy)
    │   ├── types.ts            # TypeScript types for Uniswap API
    │   ├── serverExecutor.ts   # Server-side swap execution
    │   ├── quote.ts            # Quote helper
    │   ├── approval.ts         # Approval check helper
    │   ├── swap.ts             # Classic swap helper
    │   └── order.ts            # UniswapX order helper
    ├── web3/
    │   ├── tokens.ts           # Base token registry
    │   ├── balances.ts         # Portfolio balance fetching
    │   └── prices.ts           # CoinGecko price fetching
    └── store/
        └── useStore.ts         # Zustand global state

How It Works

1. Sign In

User clicks "Sign In" in the header. Privy opens a modal with email and Google options. On first login, an embedded Ethereum wallet is automatically created on Base. The wallet is then delegated to the server for server-side signing.

2. Natural Language Intent

User types something like "buy $50 of UNI" or "diversify $200 into DeFi tokens" in the chat input.

3. AI Parsing

The message is sent to /api/agent, which calls Claude with tool definitions for:

  • get_token_info — lookup token metadata
  • get_quote — fetch Uniswap quotes
  • create_swap_plan — build a multi-swap plan

Claude uses these tools to understand the intent, look up tokens, get live quotes, and construct a SwapPlan with one or more swaps.

4. Swap Plan Review

The AI returns a swap plan card showing each swap (token pair, amount, estimated output). The user reviews and can accept or dismiss.

5. Server-Side Execution

When the user clicks Execute:

  1. Client sends POST /api/execute with the plan + Privy JWT
  2. Server verifies the JWT, gets the user's embedded wallet
  3. Server starts execution in the background (fire-and-forget)
  4. For each swap: check approval → get quote → sign permit → submit swap/order
  5. All signing happens server-side via Privy's wallet API
  6. Client polls GET /api/execute?id=... every 1.5s for status updates

6. Status Polling

The swap plan card shows real-time progress: queued → approving → signing → pending → confirmed/failed. Toast notifications appear on completion or failure.

7. Close and Reopen

Because execution runs on the server, the user can close their browser. When they reopen, if they still have the executionId, they can check status.

Key Design Decisions

Why Privy over wagmi/RainbowKit?

  • Retail-friendly auth: email and Google sign-in, no wallet extension needed
  • Embedded wallets with server-side signing delegation
  • Enables "click Execute and close browser" UX

Why server-side execution?

  • User doesn't need to keep the browser open for multi-swap plans
  • No MetaMask popups for each approval/signature
  • More reliable — server retries, no browser tab suspension

In-memory state limitations

  • Execution status is stored in a Map in the API route
  • Lost on server restart or new deployment
  • For production: use Vercel KV, Redis, or a database

Deployment

Vercel

  1. Push to GitHub
  2. Import in vercel.com
  3. Add all environment variables in Vercel project settings
  4. Set Function Max Duration to 300s (requires Vercel Pro for multi-swap plans)
  5. Deploy

Timeout Considerations

  • Single-swap plans complete in ~10-30s (within default 60s limit)
  • Multi-swap plans with UniswapX order polling can take >60s
  • The /api/execute route sets maxDuration = 300 (Vercel Pro)
  • For Vercel Hobby: stick to 1-2 swap plans, or split into sequential calls

API Reference

POST /api/agent

AI agent endpoint. Processes natural language and returns a response with optional swap plan.

Body: { message: string, userId?: string, conversationHistory?: Array } Response: { type: 'text' | 'swap_plan', message: string, plan?: SwapPlan }

POST /api/execute

Start server-side swap execution. Requires Privy JWT.

Headers: Authorization: Bearer <privy-jwt> Body: { plan: SwapPlan } Response: { executionId: string }

GET /api/execute?id=<executionId>

Poll execution status.

Response: { planStatus: string, swapStatuses: Record<string, { status, txHash?, error? }> }

POST /api/quote

Proxy to Uniswap Trade API /quote.

Body: { tokenIn, tokenOut, amount, swapper, ... }

POST /api/swap

Proxy to Uniswap Trade API /swap.

Body: { quote, signature?, permitData? }

POST /api/order

Proxy to Uniswap Trade API /order.

Body: { quote, signature, permitData? }

GET /api/order?orderId=<id>

Proxy to Uniswap Trade API /orders for UniswapX order status.

POST /api/approval

Proxy to Uniswap Trade API /check_approval.

Body: { walletAddress, token, amount, chainId }

Hackathon Tracks

  • Uniswap Foundation — AI-powered natural language trading using Uniswap Trade API (Classic + UniswapX) on Base
  • 0g Labs — Decentralized AI agent infrastructure for DeFi trading

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors