A hands-on workshop for the Pulso Hackathon. You'll build a web wallet on Stellar using Privy for authentication and embedded wallets, then add yield-earning vaults with DeFindex.
🔗 Live demo: https://resilient-churros-c913d4.netlify.app/
The workshop is split into two steps:
- Step 1 — Wallet: A web app that lets users sign in and manage a Stellar wallet powered by Privy.
- Step 2 — DeFindex: Add DeFindex vaults so users can deposit funds and earn yield directly from the wallet.
- Node.js 18+
- pnpm 9+ (
npm install -g pnpm) - A Privy account and App ID
- A DeFindex account / API key (Step 2)
- A Netlify account for deployment
- Basic familiarity with React and Stellar (testnet for the workshop, mainnet for production)
The app is split into a backend and a frontend for modularity. The frontend never talks to Privy or DeFindex directly — it calls our own backend API, which holds the secrets (API keys) and orchestrates the integrations. This keeps concerns separated and makes each piece easy to swap or test.
The backend runs as Netlify Functions (serverless), so the whole app — UI and API — deploys to Netlify as a single site with no separate server to host.
┌──────────┐ /api/* (HTTP) ┌────────────────────┐ ┌──────────────────┐
│ Frontend │ ────────────────▶ │ Backend │ ───▶ │ Privy / DeFindex │
│ (Next.js)│ ◀──────────────── │ (Netlify Functions)│ ◀─── │ Stellar RPC │
└──────────┘ └────────────────────┘ └──────────────────┘
└────────── one Netlify site ──────────┘
Chosen so the whole app deploys to Netlify with one build and pnpm.
| Concern | Tool |
|---|---|
| Monorepo | pnpm workspaces |
| Frontend | Next.js (App Router) |
| Backend | Netlify Functions (TypeScript) |
| Auth + Wallets | Privy |
| Blockchain | Stellar (testnet + mainnet) |
| Yield / Vaults | DeFindex |
| Hosting | Netlify |
Why Netlify Functions instead of a standalone Express server? Netlify hosts static sites + serverless functions, not long-running processes. Making each endpoint a function keeps the modular backend/frontend split while deploying as one site — no second host, no CORS setup, no extra cost.
Goal: a web app where a user logs in (email / social / passkey) and gets an embedded Stellar wallet they can fund and send from.
- Scaffold the functions and configure the Privy server SDK with your App ID and secret.
- Expose endpoints the frontend needs, e.g.
GET /api/wallet/balance,POST /api/wallet/fund(testnet),POST /api/payments. - Keep secrets server-side — only the public App ID reaches the browser.
- Scaffold the app and install the Privy React SDK.
- Add login — wrap the app in the Privy provider and add a connect button.
- Show the wallet — read the user's Stellar address and call the backend for balance.
- Fund on testnet and send a test payment through the backend.
By the end of Step 1 a user can sign in and see/use their Stellar wallet.
Goal: let users deposit into a DeFindex vault from the wallet and track their yield.
- Get DeFindex API access and store the API key server-side.
- Wrap the DeFindex API behind your own endpoints, e.g.
GET /api/vaults,POST /api/vaults/deposit,GET /api/vaults/position,POST /api/vaults/withdraw.
- List vaults by calling the backend.
- Deposit funds from the user's wallet into a vault.
- Show balance & APY for the user's position.
- Withdraw funds back to the wallet.
By the end of Step 2 the wallet can put idle funds to work earning yield.
Each stage of the workshop lives on its own branch, so you can check out the point you want to start from and follow along.
| Branch | Where you start |
|---|---|
main |
Empty scaffold — build everything yourself |
step-1 |
Completed wallet (Privy + Stellar); start Step 2 from here |
step-2 |
Completed wallet and DeFindex vaults (final result) |
# e.g. begin Step 2 with the wallet already built
git checkout step-1A single pnpm-workspace monorepo so Netlify builds the whole site at once:
.
├── pnpm-workspace.yaml
├── netlify.toml # build + functions config
├── frontend/ # Next.js app (the deployed site)
├── netlify/functions/ # backend endpoints → /api/*
└── packages/shared/ # types shared between frontend & functions
# install all workspaces
pnpm install
# set up environment (see below)
cp .env.example .env
# run Next.js + Functions together for local development
pnpm run devpnpm run dev (which runs the Netlify CLI under the hood) serves the frontend
and proxies /api/* to your functions, so the app at http://localhost:8888
behaves exactly like production.
Set these in .env locally, and in Netlify → Site settings → Environment
variables for deployment.
Server-side secrets (used by functions, never sent to the browser):
PRIVY_APP_ID= # from the Privy dashboard
PRIVY_APP_SECRET= # from the Privy dashboard
DEFINDEX_API_KEY= # from DeFindex (Step 2)Public values (exposed to the Next.js frontend):
NEXT_PUBLIC_PRIVY_APP_ID= # public App ID for the Privy React SDK
NEXT_PUBLIC_STELLAR_NETWORK=testnet # "testnet" or "mainnet"Use
testnetto follow the workshop with Friendbot-funded accounts. Switch tomainnetfor a production deployment — same code, real funds. Note Friendbot funding only exists on testnet.The frontend calls the backend at the relative path
/api/*, so there's no API URL to configure — same origin in dev and in production.
-
Push the repo to GitHub and import the site in Netlify (or run
netlify init). -
Netlify auto-detects
pnpmfrompnpm-lock.yaml. Pin the version with aPNPM_VERSIONenv var if you want a specific one. -
The build config lives in
netlify.toml:[build] command = "pnpm build" publish = "frontend/.next" [functions] directory = "netlify/functions" node_bundler = "esbuild" [[redirects]] from = "/api/*" to = "/.netlify/functions/:splat" status = 200
-
Add the environment variables (above) in the Netlify dashboard.
-
Deploy a branch (e.g.
step-1) to get a preview URL for that stage.
- Privy Docs
- Stellar Developers
- Stellar Testnet Friendbot
- DeFindex Docs
- Netlify Functions
- pnpm Workspaces
MIT