Internal use only — not tracked in git. Living document: check off items as they ship. Add new items as scope expands.
Nester is a decentralized savings & liquidity protocol for emerging markets. It automates DeFi yield via Soroban smart vaults on Stellar, and bridges crypto earnings to local fiat through an offramp aggregator. An AI advisor layer (Prometheus, powered by Claude) provides personalized guidance without executing transactions.
Core value propositions:
- Optimized yield (8–15% APY) across multiple DeFi protocols
- ~3-second crypto-to-fiat settlement (Nigeria first → multi-region)
- Non-custodial — users retain full asset ownership
- AI-powered recommendations, never auto-execution
| Layer | Stack | Status |
|---|---|---|
| Smart Contracts | Rust / Soroban (Stellar) | Active |
| Backend API | Go + Chi + PostgreSQL + Redis | Active |
| Web DApp | Next.js 16 / React 19 / Stellar Freighter | Active |
| Intelligence Service | Python FastAPI + Claude (Anthropic SDK) | Active |
| Marketing Website | Next.js + Three.js / GSAP | Active |
| Mobile App | Flutter (Dart) | Skeleton only |
-
vaultcontract — deposit, withdraw, rebalance, yield accrual -
vault_tokencontract — ERC-4626-compatible shares token -
allocation_strategycontract — auto-allocate across protocols -
yield_registrycontract — multi-protocol APY tracking (Aave, Blend, Compound) -
access_controlcontract — RBAC (grant/revoke roles, has_role) -
nestercontract — primary orchestrator/router (execute_deposit, execute_withdrawal) -
treasurycontract — fund management & reserves -
timelockcontract — governance time-lock (schedule/execute/cancel) -
rent_escrowcontract — escrow lock/release/refund - Shared
commonlib — constants, errors, events - Shared
test_utilslib - Impairment regression test (vault: loss scenario → zero performance fee) (OSS_CLEANUP PR #275)
-
preview_withdraw— fix or document pre-fee gross return vs EIP-4626previewRedeemsemantics (OSS_CLEANUP PR #277) - Confirm
cargo test -p vault-contractpasses in CI with vault_token.wasm present (OSS_CLEANUP PR #277) - Contract security audit (pending — link when complete)
- Project scaffolding — Chi router, structured logging (slog), config via env
- PostgreSQL connection pool (pgx/v5)
- Redis client (sessions, challenge store)
- 16 database migrations
- Auth — challenge/verify (Stellar wallet signature + JWT issuance)
- Vault CRUD — create, get, list, allocations
- Transaction queries — get by ID, list by vault
- Settlement service — initiate, get status, admin patch
- User profile — get, update, KYC status
- Admin service — role management, audit logs
- Bank resolver — Paystack & Flutterwave provider integration
- Exchange rate oracle (Stellar Horizon)
- Performance service — APY snapshot history
- Intelligence relay — proxy to Python Prometheus service
- Soroban vault chain invoker — smart contract RPC calls
- WebSocket hub — real-time vault balance updates
- Health endpoints (
/health,/readyz,/health/detailed) - CORS, request logging, auth middleware
-
bootstrap-adminCLI tool - Event indexer (first pass — blocked, do not ship)
- [BLOCKING] Event indexer: persist last indexed ledger to DB (cursor resets on restart → doubles balances) (OSS_CLEANUP PR #276)
- [BLOCKING] Event indexer: seed
startLedgerfrom current tip, not 0 (RPC error on first boot) (OSS_CLEANUP PR #276) - [BLOCKING] Event indexer: make all balance updates idempotent (processed_events table or absolute SET) (OSS_CLEANUP PR #276)
- Event indexer: move logic into
internal/stellar/EventPoller.PollEvents(not in main.go) (OSS_CLEANUP PR #276) - Event indexer: remove
float64case inextractEventAmount(precision loss on large integers) (OSS_CLEANUP PR #276) - Event indexer: unit tests for
applyIndexedEventandextractEventAmount(OSS_CLEANUP PR #276) - [SECURITY]
initiateSettlement— extractuser_idfrom JWT, not request body (BOLA) (OSS_CLEANUP PR #271) - [SECURITY]
GET /settlements/{id}— add ownership check (return 404 for non-owner, not 403) (OSS_CLEANUP PR #271) - [SECURITY]
PATCH /settlements/{id}— return 404 (not 403) for non-owned UUIDs to prevent existence oracle (OSS_CLEANUP PR #271) -
GetRoles— pass rawuuid.UUIDto pgx, notid.String()(OSS_CLEANUP PR #270) -
bootstrap-admin— adddb.Ping()aftersql.Open()(OSS_CLEANUP PR #270) -
bootstrap-admin— validate Stellar address format before querying (OSS_CLEANUP PR #270) - Migration runner — wire
golang-migrate(or equivalent) into API startup behindRUN_MIGRATIONS=trueflag (OSS_CLEANUP General) - Document re-auth requirement after migration 009 deployment (existing admin tokens lack Roles claim) (OSS_CLEANUP PR #270)
-
001— users table -
002— vaults table -
003— transactions table -
005— allocations table -
006— settlements table -
007— vault soft-delete (deleted_at) -
007— users table update (wallet_address, kyc_status, rename name→display_name, drop email) -
008— vault_transactions table -
009— confirmed_at on transactions -
009— user_roles table -
010— audit_logs table -
010— event indexer tables -
011— sessions table -
012— vault_transactions update -
014— missing columns backfill -
015— indices and constraints -
016— vault_performance table - [BLOCKING] Fix migration number collisions: two
007files, two009files, two010files (OSS_CLEANUP General) - Fix
scripts/seed.sql— users INSERT still references oldemail/namecolumns (migration 007 removed them) (OSS_CLEANUP PR #268) - Add
user_rolesseed row (test user → admin) after PR #270 merges (OSS_CLEANUP PR #268)
-
docker-compose.yml— PostgreSQL 16, Redis 7, API, frontend, intelligence services - API
Dockerfile.devwith air hot-reload - Frontend
Dockerfile.dev - Intelligence
Dockerfile -
Makefile—dev,dev-logs,dev-db,dev-down,dev-resettargets - Fix healthcheck endpoint — compose probes
/healthzbut README/router uses/health(OSS_CLEANUP PR #268) - Add
AUTH_JWT_SECRET(dev placeholder) to compose API service environment block (OSS_CLEANUP PR #268) - Frontend Dockerfile: switch from
npm citopnpm install --frozen-lockfile(OSS_CLEANUP PR #268) - Go version pin: bump Dockerfiles from
golang:1.24-alpinetogolang:1.25-alpineonce image is on Docker Hub (OSS_CLEANUP PR #268)
- Automated rebalancing engine — triggered by APY threshold drift
- LP aggregator contract — finds optimal swap routes across liquidity pools
- Rebalancing scheduler in Go API
- Slippage protection integration with
preview_withdraw_net(post-fee) - Multi-hop swap routing (USDC → XLM → NGN via multiple DEXes)
- Paystack resolver (bank list, account resolution)
- Flutterwave resolver (bank list, account resolution)
- Settlement initiation + status tracking in API
-
treasurycontract — refund on failed settlement - Bank combobox UI (with suggested chips)
- Offramp page (crypto → fiat form)
- End-to-end live settlement flow (Paystack or Flutterwave — testnet)
- Settlement webhook handler (payment provider → API callback)
- Retry / fallback logic for failed settlements
- Mobile money support (M-Pesa, MTN MoMo)
- Card withdrawal support
- Multi-currency support beyond NGN
- FastAPI intelligence service scaffold
- Anthropic Claude integration (streaming, conversation history)
- Redis-backed conversation store per user
- Rate limiting (slowapi)
- JWT validation on intelligence endpoints
- HTTP chat endpoint (
POST /intelligence/chat) - WebSocket chat endpoint (
/intelligence/ws) - Structured analysis endpoint (
/analyze) - Prometheus chatbot UI component
- Prometheus insights cards
- Market sentiment component
- Prometheus panel (AI chat sidebar in DApp)
- DeFiLlama data integration (live TVL/APY feeds)
- CoinGecko price data integration
- On-chain vault data passed as context to Claude
- Confidence levels on AI recommendations
- Portfolio analysis endpoint with structured output
- Upgrade Anthropic SDK / model version (currently 0.42.0 — check for newer Claude models)
- Ghana (GHS) offramp support
- Kenya (KES) + M-Pesa integration
- South Africa (ZAR) support
- Multi-currency vault denomination
- Regional compliance / KYC per jurisdiction
- Stellar Freighter wallet connection
- Stellar Wallets Kit integration
- Challenge/verify auth flow
- Protected routes
- Dashboard — portfolio stats, recent activity, vault positions table
- Vault list page — create vault, drill-down
- Vault detail — allocations, deposit modal, performance chart
- Savings page
- Portfolio page with Recharts visualizations
- Offramp page — bank selector, amount form
- Notifications page
- Stocks page (stub)
- Animated balance display
- Guided onboarding tour + welcome modal
- Network selector (testnet / mainnet toggle)
- Responsive layout — bottom nav for mobile
- Dark mode (Tailwind)
- React Query data fetching
- Stocks page — implement real content (currently stub)
- Error boundaries on all major routes
- Offline / network-loss handling
- Skeleton loaders on all data-fetching components
- E2E tests (Playwright or Cypress)
- Accessibility audit (WCAG 2.1 AA)
- Landing page with 3D / Three.js animations
- GSAP + Babylon.js scroll effects
- Lenis smooth scrolling
- Docs content file
- Audit docs for stale references to deprecated Express backend
- Add audit reports page (pending external audit)
- SEO metadata / Open Graph tags audit
- Project scaffold (Flutter + Dart)
- Multi-platform targets (iOS, Android, macOS, Linux, Windows, Web)
- Authentication (wallet connect — mobile equivalent of Freighter)
- Dashboard screen
- Vault management screens
- Offramp screen
- Portfolio screen
- Prometheus AI chat screen
- Push notifications
- Biometric auth
- GitHub Actions CI — change detection, conditional jobs
- Go unit + integration tests (with PostgreSQL + Redis services)
- Rust WASM build + cargo test
- Python lint (ruff) + type-check (mypy) + pytest
- Next.js build + npm audit
- gitleaks — secret detection
- govulncheck — Go dependency vulnerabilities
- gosec — Go security issues (medium+)
- cargo audit — Rust dependency vulnerabilities
- pip-audit — Python dependency vulnerabilities
- bandit — Python security issues
- Dependabot (all ecosystems silenced with open-pull-requests-limit: 0)
- CODEOWNERS — all code owned by @0xDeon
- Contract audit — external security review
- Load / stress testing plan
- Penetration test (settlement + auth endpoints)
- SAST integration for TypeScript/Next.js (currently no JS/TS security scanner in CI)
- Remove remaining
dapp/backendreferences fromturbo.json(deprecated Express) (OSS_CLEANUP PR #269) - Remove remaining
dapp/backendreferences from rootREADME.md(OSS_CLEANUP PR #269) - README: update roadmap — Phases 3 & 4 are largely implemented, not "Planned" (current state is outdated)
- README: mention React Native → correct to Flutter in contribution table (backend section lists React Native)
- API: missing
013migration (gap between012and014— verify intentional or accidental skip)
See Diagnosis section below.
Complete audit of bugs, security issues, and enhancement opportunities as of 2026-05-18.
File: apps/api/cmd/api/main.go — startEventIndexer / startLedger
startLedger is a local uint64 initialized to 0 on every restart. All balance update SQL is additive (total_deposited + amount). Any restart replays all historical events and doubles every vault balance. Fix: persist last indexed ledger sequence in a system_state DB table; read on startup.
File: apps/api/cmd/api/main.go
Stellar getEvents rejects ledger sequence 0. On first boot with no persisted cursor, the indexer fails immediately. Fix: on first boot, seed from the current ledger tip.
File: apps/api/internal/handler/settlement_handler.go
Any authenticated user can create a settlement on behalf of any other user by supplying a different user_id in the JSON body. Fix: ignore body user_id; always extract from auth.GetUserFromContext.
File: apps/api/internal/handler/settlement_handler.go
Any authenticated user can read any settlement by UUID. Enables UUID enumeration as a precondition for the BOLA attack in B-03. Fix: return 404 (not 403) for settlements the caller doesn't own.
File: apps/api/internal/service/settlement_service.go
Non-existent UUIDs → 404; non-owned UUIDs → 403. An attacker can distinguish live from dead settlements. Fix: return 404 for both cases.
Directory: apps/api/migrations/
Three pairs of files share the same numeric prefix (007, 009, 010). Any lexicographic migration runner applies them in undefined order and may apply wrong schema changes or skip others. Fix: renumber colliding migrations consistently before running in production.
File: scripts/seed.sql
The users INSERT still references email and name columns removed in migration 007_update_users_table. Running make dev on a fresh clone will error at seeding. Fix: rewrite the users block to match the post-007 schema (wallet_address, display_name, kyc_status).
File: apps/api/internal/repository/postgres/user_repository.go
pgx v5 handles uuid.UUID natively; passing .String() forces implicit server-side cast and breaks the driver's type safety guarantee. Every other query in the repo passes raw UUIDs — this is an inconsistency that can surface as unexpected query errors under stricter pg configs.
File: apps/api/cmd/bootstrap-admin/main.go
sql.Open only validates DSN syntax; it does not connect. A bad DSN or unreachable host surfaces as a confusing query error rather than a clear connection failure. Fix: add db.Ping() with a wrapped error.
File: packages/contracts/contracts/vault/src/lib.rs
Returns amount_for_shares(shares) before management, early-withdrawal, and performance fees. Any DApp passing this directly as min_assets_out will hit SlippageExceeded on every fee-bearing withdrawal. Fix: either add preview_withdraw_net that applies fee estimates on-chain, or document explicitly and have the DApp subtract fees.
File: apps/api/cmd/api/main.go
A float64 case is handled for Soroban event amounts. float64 loses precision above 2^53 — Soroban amounts come as strings and can exceed this range. Fix: treat any non-string amount type as unparseable; only accept string.
File: apps/api/ (no migration runner wired)
Migrations only apply via scripts/seed.sql on Docker initdb. New migrations added after initial setup require make dev-reset (wipes all data). Fix: wire golang-migrate behind a RUN_MIGRATIONS=true flag so incremental migrations apply without data loss.
File: docker-compose.yml vs apps/api/cmd/api/main.go
docker-compose probes /healthz; README and API docs say /health. One of them is wrong — if the Go router serves /health only, the compose healthcheck never passes and the API container never becomes healthy. Fix: verify the actual router and align everything.
After migration 009_add_user_roles deploys, all active JWT tokens were issued without a Roles field. Admins using those tokens will hit authorization failures silently until they re-authenticate. Needs a deployment runbook entry.
File: apps/api/cmd/bootstrap-admin/main.go
A typo in the wallet address produces no user found rather than invalid address format. A basic format check (G prefix, 56 chars) would surface the error before hitting the DB.
File: packages/contracts/contracts/vault/src/test.rs
The vault handles losses correctly (yield_part < 0 → fee skipped), but there is no test proving this. Without it, a future refactor can silently break the zero-fee invariant under impairment.
File: turbo.json
The Express backend was removed but the turbo pipeline may still contain its entries, causing confusing build cache misses or warnings. Verify with grep -r "dapp/backend" turbo.json.
File: README.md, line ~194
The mobile app is Flutter/Dart, not React Native. Misleads contributors looking to work on mobile.
Directory: apps/api/migrations/
Migration numbering jumps from 012 to 014. If this was an intentional deletion, it should be documented. If accidental, the missing migration may have left a schema gap that 014_add_missing_columns is patching around.
File: apps/intelligence/app/services/claude.py
If no model ID is pinned, the Anthropic SDK defaults may shift with library upgrades. Pin explicitly to claude-sonnet-4-6 (or latest) and document the version in config.
File: apps/dapp/frontend/ (WebSocket client)
Real-time balance updates via WebSocket will silently fail after network interruptions with no automatic reconnect. Users would see stale balances until page refresh.
File: apps/api/internal/service/challenge_store.go
Auth challenges stored in memory have a TTL, but the store uses a simple map with no background cleanup goroutine — expired challenges accumulate in memory until the process restarts. Low risk in dev; becomes a memory leak under high auth traffic in production.
File: .github/workflows/ci.yml
The contributor left "verify CI passes" unchecked in PR #277. Integration tests that depend on the compiled WASM artifact may skip silently if the artifact isn't built first, giving a false green.
Return net amount after all fees so the DApp can pass it directly as min_assets_out without manual fee math. Aligns with EIP-4626 previewRedeem semantics.
Store (event_id, ledger_sequence) in a dedicated table. Check before applying any balance mutation. This is a prerequisite for safe event indexer operation (B-01 / B-02).
Add an env-flag-gated migration runner so make dev (or a fresh deployment) applies all pending migrations without wiping data. Removes the make dev-reset requirement for schema changes.
Replace blank loading states with Tailwind skeleton placeholders to prevent layout shift and improve perceived performance.
Wrap routes in React error boundaries so a single component crash doesn't take down the entire page.
Add a ping/pong heartbeat on the WebSocket client, with exponential-backoff reconnect logic. Show a "reconnecting…" badge in the UI when the connection drops.
GitHub Actions currently scans Go (gosec), Rust (cargo audit), and Python (bandit) but has no static analysis for Next.js/TypeScript. Add eslint-plugin-security or Semgrep with a JS/TS ruleset.
Explicit CLAUDE_MODEL=claude-sonnet-4-6 in .env.example and config.py. Prevents silent model version drift on SDK upgrade.
A generic (key TEXT PRIMARY KEY, value TEXT, updated_at TIMESTAMPTZ) table would solve both the event indexer cursor (B-01) and any future startup-state needs without adding one-off tables.
The /stocks route is a stub. Implement with yield-bearing asset suggestions from Prometheus AI or integrate a public equities/crypto data feed.
Create docs/DEPLOYMENT.md covering: migration steps, re-auth requirement after role migrations, env var checklist, contract deployment sequence, rollback procedure.
Flutter scaffold exists; prioritize the auth + dashboard screens to reach feature parity with the web DApp for the Nigeria market.
Before hitting the DB: strings.HasPrefix(wallet, "G") && len(wallet) == 56. Saves a round-trip on typo inputs.
Add Playwright tests for the golden paths: wallet connect → create vault → deposit → view dashboard → initiate offramp.
Wire live APY and market data into the intelligence service context so Claude has current on-chain data when making recommendations, instead of relying solely on training knowledge.