Production-grade Stellar dApp with advanced Soroban smart contracts
A full-featured Stellar testnet faucet and smart contract platform built with Next.js, Soroban, and Stellar SDK. Features multi-wallet support, real-time event streaming, on-chain governance, token staking, and achievement badges.
- Features
- Architecture
- Smart Contracts
- Quick Start
- Development
- Testing
- Deployment
- CI/CD
- API Reference
- Environment Variables
- Project Structure
- Demo
- Multi-Wallet Faucet β Request 10,000 testnet XLM with Freighter, xBull, Albedo, LOBSTR, or WalletConnect
- Send Payments β Transfer XLM between any Stellar testnet addresses
- Smart Contract Interaction β Deploy and interact with Soroban smart contracts
- Real-time Event Streaming β Live contract events via SSE with polling fallback
- Admin Dashboard β Analytics and transaction monitoring at
/admin
| Contract | Description | Features |
|---|---|---|
| StellarDripzCounter | Simple counter + greeting | Increment, get_global, set_greeting, get_user |
| DripToken | Soroban fungible token (SEP-41 inspired) | Mint (admin + authorized minter), transfer, approve, transfer_from, burn |
| DripPool | Staking pool with rewards | Stake, unstake, claim rewards, lock periods, admin controls |
| DripGovernance | On-chain governance | Proposals, voting (For/Against/Abstain), execute |
| DripBadge | Achievement NFT badges | Create, claim, grant (Bronze β Silver β Gold β Platinum) |
- API Gateway Pattern β All Stellar ops routed through Next.js API routes
- Rate Limiting β Per-IP and per-address rate limiting with configurable windows
- Event Streaming β Server-Sent Events (SSE) with automatic polling fallback
- Health Checks β
/api/healthendpoint with service status monitoring - Error Boundaries β Graceful error recovery with retry UI
- Loading Skeletons β Polished loading states for all async operations
- Mobile Responsive β Fully responsive design from 320px to 4K
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β StellarDripz Frontend β
β (Next.js 14 + React 18 + Tailwind + TypeScript) β
β β
β βββββββββββ ββββββββββββ ββββββββββββ βββββββββββββββ β
β β Wallet β β Faucet β β Payment β β Contract β β
β β Connect β β Button β β SendForm β β SorobanDemo β β
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββββ¬βββββββ β
βββββββββΌβββββββββββββΌβββββββββββββΌββββββββββββββββΌβββββββββ
β β β β
βΌ βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API Client Layer (src/lib/client/) β
β apiClient.ts β walletClient, faucetClient, etc. β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β HTTP
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Next.js API Routes (src/app/api/) β
β /wallet/connect /faucet/fund /payment/send β
β /contract/invoke /balance/:addr /history /analytics β
β /events (SSE) /health /batch /status β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Server Services (src/lib/server/) β
β sorobanService horizonService dbService β
β rateLimiter sessionManager β
ββββββββββββ¬βββββββββββββββββββββββββββββ¬βββββββββββββββββββ
β β
βΌ βΌ
ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
β Soroban RPC β β Stellar Horizon β
β (Smart Contracts)β β (Transactions, Balances) β
ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Stellar Network (Testnet/Mainnet) β
β βββββββββββββ βββββββββββββ ββββββββββββ βββββββββββββ β
β β Counter β β DripToken β β DripPool β β Governanceβ β β
β β Contract β β Contract β β Contract β β + Badge β β β
β βββββββββββββ βββββββββββββ ββββββββββββ βββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The contracts are designed for composability:
DripToken βββ DripPool (transfers on stake/unstake)
DripToken βββ DripGovernance (voting power from token balance)
DripPool βββ DripGovernance (parameter changes via proposals)
DripBadge βββ DripPool (grant badges based on staking milestones)
# 1. Build WASM
npm run contracts:build
# 2. Set deployer secret key
export DEPLOYER_SECRET_KEY="SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# 3. Deploy
npm run contracts:deployDeployment status: All 5 smart contracts are deployed to Stellar Testnet (2026-08-11). Deployer:
GCNIK6CGM3DXD3NJPZBG4Z76NGCU6YNID3TK7OSTKOJXF3ALBVJWESXKLedger: 4,085,848
Deployed Contract IDs:
| Contract | Contract ID | Explorer |
|---|---|---|
| Counter | CCAIIGMOBRZ2P6OHSYABBB35TJDSXBTC2T5IX7KVPXNIQKXGDJ46R2AE |
View β |
| DripToken | CD3YTU3JCBEMNNVISPTLPVYQATDGIRBJPLVJ2MIO3W56O7TYSWDG3GY6 |
View β |
| DripPool | CCBNJTZ22HDJTQHIINS22FNIK5KRYIW3CPORFAKNCBMWWL7SRJMZIR6X |
View β |
| Governance | CD3NIJCGVECTGPOUQOWYERWXQMOXJFSX6AKVI4KZVXGO4ZBYO7G6AIVH |
View β |
| Badge | CAZFH3S7JUEI7LZSQGHMM6OF5UKWLNZ3CSOX2KNUX3RBFPP5Q6GEEUWE |
View β |
contracts/src/
βββ lib.rs # Module registry & re-exports
βββ test.rs # Cross-module integration tests
βββ counter/
β βββ mod.rs # StellarDripzCounter (existing)
βββ token/
β βββ mod.rs # DripToken (SEP-41)
βββ pool/
β βββ mod.rs # DripPool (Staking)
βββ governance/
β βββ mod.rs # DripGovernance
βββ badge/
β βββ mod.rs # DripBadge (NFT)
βββ common/
βββ mod.rs
βββ storage.rs # Shared storage helpers
βββ events.rs # Common event emitters
βββ types.rs # Shared types
- Node.js 18+
- Rust 1.84+ with
wasm32v1-nonetarget - A Stellar wallet (Freighter recommended)
- Testnet XLM (get from https://friendbot.stellar.org)
# Clone
git clone https://github.com/StellarDripz/StellarDripz.git
cd stellardripz
# Install dependencies
npm install
# Copy env template
cp .env.example .env.local
# Install Rust + wasm target (for contracts)
rustup target add wasm32v1-none
# Build contracts
npm run contracts:build
# Run tests
npm run contracts:test
npm test
# Start dev server
npm run devVisit http://localhost:3000
npm run contracts:testOutput:
running 19 tests
test badge::badge_test::test_create_and_claim_badge ... ok
test badge::badge_test::test_duplicate_claim_prevented ... ok
test badge::badge_test::test_grant_badge ... ok
test governance::governance_test::test_create_proposal ... ok
test governance::governance_test::test_vote_and_execute ... ok
test pool::pool_test::test_admin_controls ... ok
test pool::pool_test::test_reward_calculation ... ok
test pool::pool_test::test_stake_and_unstake ... ok
test test::counter_test::test_counter_increment ... ok
test test::counter_test::test_greeting ... ok
test test::counter_test::test_user_counter_independent ... ok
test test::token_test::test_approve_and_transfer_from ... ok
test test::token_test::test_burn ... ok
test test::token_test::test_initialize_and_mint ... ok
test test::token_test::test_transfer ... ok
test token::token_test::test_approve_and_transfer_from ... ok
test token::token_test::test_burn ... ok
test token::token_test::test_initialize_and_mint ... ok
test token::token_test::test_transfer ... ok
test result: ok. 19 passed
npm testTest suites:
addressBookService.test.tsβ 8 testsconfig.test.tsβ 2 testswalletService.test.tsβ 7 testsenv.test.tsβ 4 testsrateLimiter.test.tsβ 5 testscontractTypes.test.tsβ 7 testsdbService.test.tsβ 4 testsuseWallet.test.tsβ 8 testsuseBalance.test.tsβ 8 testsuseTransactionHistory.test.tsβ 8 testsuseFaucet.test.tsβ 7 testsdirectClient.test.tsβ 9 testsapi-faucet.test.tsβ 4 testsapi-wallet.test.tsβ 4 testsapi-payment.test.tsβ 5 testsapi-balance.test.tsβ 3 testsapi-history.test.tsβ 4 testsapi-contract.test.tsβ 4 testsapi-health.test.tsβ 5 tests
Total: 19 suites, 119 tests, all passing β
npm run build
npm start- Push to GitHub
- Connect to Vercel
- Set environment variables (see below)
- Deploy!
Production setup checklist (for a fully functional deployment):
- Deploy the smart contracts β set a funded testnet
DEPLOYER_SECRET_KEY, runnpm run contracts:deploy, and copy the printedNEXT_PUBLIC_CONTRACT_*IDs. - Configure persistence (recommended) β create a Supabase project, run
src/lib/server/supabase-schema.sql, and setNEXT_PUBLIC_SUPABASE_URL+SUPABASE_SERVICE_ROLE_KEY. Without this, analytics/transaction history fall back to an in-memory store that is ephemeral on serverless (data resets on cold start). - Add the variables below to GitHub (repo Variables/Secrets) β the CI/CD pipeline forwards them to every Vercel deployment.
Required GitHub Variables (forwarded to Vercel by the CI/CD pipeline):
NEXT_PUBLIC_SOROBAN_RPC_URL
NEXT_PUBLIC_HORIZON_URL
NEXT_PUBLIC_STELLAR_NETWORK
NEXT_PUBLIC_CONTRACT_COUNTER # after contracts:deploy
NEXT_PUBLIC_CONTRACT_DRIP_TOKEN # after contracts:deploy
NEXT_PUBLIC_CONTRACT_DRIP_POOL # after contracts:deploy
NEXT_PUBLIC_CONTRACT_GOVERNANCE # after contracts:deploy
NEXT_PUBLIC_CONTRACT_BADGE # after contracts:deploy
NEXT_PUBLIC_SUPABASE_URL # if using Supabase
Required GitHub Secrets:
SUPABASE_SERVICE_ROLE_KEY # if using Supabase
π Live Demo: https://stellardripz.vercel.app
π₯ Demo: See demo/README.md for the walkthrough script. A recorded demo video is planned for the next release.
The app ships production security headers via next.config.js: CSP (with clickjacking protection via frame-ancestors 'self'), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy. No global Access-Control-Allow-Origin is set β only /api/health exposes CORS (for external monitoring), so cross-origin reads of API data remain blocked.
- SSE
/api/eventsβ Vercel caps function duration (maxDuration= 300s is set; Hobby plans may cut streams sooner). The frontend automatically falls back to direct Soroban RPC polling, so event streaming keeps working. - Rate limiting β the in-memory limiter is per-instance. For multi-instance deployments, migrate to a shared store (Upstash/Redis).
- DB fallback β the JSON fallback writes to
/tmpwhen the project dir is read-only; data is lost on cold start. Configure Supabase for durable storage.
# Build production bundle
NODE_ENV=production npm run build
# Deploy .next/ to your hosting providerThe pipeline runs on every push and PR to main:
| Job | Trigger | Actions |
|---|---|---|
| π§ Contract Tests | Push, PR | cargo test, cargo build --release |
| π§ͺ Frontend Tests | Push, PR | npm test, npx tsc --noEmit |
| π Lint | Push, PR | npm run lint |
| ποΈ Build | Push, PR | npm run build |
| π Deploy Preview | PR | Vercel preview deployment |
| π Deploy Production | Push to main | Vercel production |
VERCEL_TOKEN β Vercel API token
VERCEL_ORG_ID β Vercel organization ID
VERCEL_PROJECT_ID β Vercel project ID
NEXT_PUBLIC_SOROBAN_RPC_URL
NEXT_PUBLIC_HORIZON_URL
NEXT_PUBLIC_STELLAR_NETWORK
NEXT_PUBLIC_CONTRACT_COUNTER
NEXT_PUBLIC_CONTRACT_DRIP_TOKEN
NEXT_PUBLIC_CONTRACT_DRIP_POOL
NEXT_PUBLIC_CONTRACT_GOVERNANCE
NEXT_PUBLIC_CONTRACT_BADGE
NEXT_PUBLIC_SUPABASE_URL
SUPABASE_SERVICE_ROLE_KEY
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/health |
Service health status + uptime | None |
GET |
/api/events?contractId=X |
SSE event stream | None |
POST |
/api/wallet/connect |
Register wallet session | None |
GET |
/api/balance/:address |
Fetch account balance | None |
POST |
/api/faucet/fund |
Request testnet XLM | Rate-limited |
POST |
/api/payment/send |
Build or submit payment | Rate-limited |
POST |
/api/contract/invoke |
Simulate, build, or submit contract call | Rate-limited |
GET |
/api/history |
Transaction history | None |
GET |
/api/analytics |
Usage analytics | None |
POST |
/api/batch |
Batch operations | Rate-limited |
GET |
/api/status |
Network status check | None |
See .env.example for the full list. Copy to .env.local for local development.
Required:
NEXT_PUBLIC_SOROBAN_RPC_URLβ Soroban RPC endpointNEXT_PUBLIC_HORIZON_URLβ Horizon API endpoint
Optional (for contract features):
NEXT_PUBLIC_CONTRACT_COUNTERβ Deployed Counter contract IDNEXT_PUBLIC_CONTRACT_DRIP_TOKENβ Deployed DripToken contract IDNEXT_PUBLIC_CONTRACT_DRIP_POOLβ Deployed DripPool contract IDNEXT_PUBLIC_CONTRACT_GOVERNANCEβ Deployed Governance contract IDNEXT_PUBLIC_CONTRACT_BADGEβ Deployed Badge contract ID
Deployer:
DEPLOYER_SECRET_KEYβ Secret key for contract deployment
stellardripz/
βββ .github/workflows/
β βββ ci-cd.yml # CI/CD pipeline
βββ contracts/ # Soroban smart contracts (Rust)
β βββ Cargo.toml
β βββ src/
β βββ lib.rs
β βββ test.rs
β βββ counter/mod.rs
β βββ token/mod.rs
β βββ pool/mod.rs
β βββ governance/mod.rs
β βββ badge/mod.rs
β βββ common/
βββ scripts/
β βββ deploy-contract.ts # Contract deployment
β βββ build-contracts.sh # Build script
βββ src/
β βββ app/
β β βββ page.tsx # Main page
β β βββ layout.tsx # Root layout + ErrorBoundary
β β βββ admin/page.tsx # Admin dashboard
β β βββ api/ # API routes (10 endpoints)
β βββ components/ # React components (15+)
β βββ context/AppContext.tsx # Global state manager
β βββ hooks/ # Custom hooks
β βββ lib/
β β βββ client/ # Frontend API clients
β β βββ server/ # Backend services
β β βββ stellar/ # Stellar integration
β β βββ wallets/ # Wallet connector
β β βββ db.ts # Database abstraction
β β βββ rateLimiter.ts # Client rate limiter
β β βββ logger.ts # Structured logger
β β βββ env.ts # Config validation
β βββ services/ # Re-exported service layer
β βββ types/index.ts # TypeScript types
β βββ __tests__/ # Test suites (7)
βββ .env.example
βββ Makefile
βββ package.json
βββ next.config.js
βββ tailwind.config.ts
βββ tsconfig.json
βββ jest.config.js
βββ postcss.config.js
βββ README.md
The UI is fully responsive with these breakpoints:
| Width | Layout | Changes |
|---|---|---|
| < 768px | Single column | Stacked cards, full-width inputs, hamburger navigation |
| 768-1024px | Two column grid | Balance/Faucet left, Send/History right |
| > 1024px | Max-width 5XL | Centered content, extended contract demos |
All components use relative units, flexbox/grid, and Tailwind responsive classes.
-
Introduction (0:00-0:20)
- Show project README and architecture diagram
- Explain StellarDripz purpose
-
Wallet Connection & Faucet (0:20-0:50)
- Connect Freighter wallet
- Click faucet to receive 10,000 testnet XLM
- Show balance update
-
Send Payment (0:50-1:15)
- Send XLM to another address
- Show transaction confirmation
- Transaction history update
-
Smart Contract Demo (1:15-2:00)
- Paste deployed contract ID
- Read counter value
- Increment counter (wallet signing)
- Set greeting message
- Show real-time event stream
-
Advanced Contracts (2:00-2:30)
- Show DripToken mint/transfer
- Show DripPool staking
- Show governance voting
- Show badge claims
-
CI/CD & Testing (2:30-3:00)
- Show GitHub Actions pipeline running
- Show test output (19 contract + 119 frontend tests passing)
- Show Vercel deployment
- Admin dashboard analytics
GitHub Actions workflow β contract tests, frontend tests, lint, build, and Vercel deploy all passing.
19 test suites, 119 tests passing with zero failures. TypeScript strict mode compiles cleanly.
Fully responsive layout from 320px to 4K β stacked cards on mobile, two-column on tablet, max-width 5XL on desktop.
Five smart contracts deployed to Stellar Testnet: Counter, DripToken, DripPool, DripGovernance, DripBadge.
Multi-wallet picker supporting Freighter, xBull, Albedo, LOBSTR, and WalletConnect.
Direct contract reads via Soroban RPC, proxied writes through API with real-time event streaming.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
We use Conventional Commits:
feat:β New featurefix:β Bug fixdocs:β Documentationtest:β Testsrefactor:β Code restructuringci:β CI/CD changeschore:β Maintenance
MIT Β© StellarDripz
Built with:
const { wallet, connecting, error, connect, disconnect, refreshWallets } = useWallet();Manages wallet connection state with auto-reconnection from persisted sessions.
const { balance, loading, error, refresh } = useBalance({ address, refreshInterval: 30000 });Fetches Stellar account balances with optional auto-refresh polling.
const { transactions, loading, error, total, refresh } = useTransactionHistory({ address, type: "faucet" });Retrieves filtered transaction history with auto-refresh support.
const { requesting, success, error, lastHash, canRequest, request, cooldownRemaining } = useFaucet({ address });Requests testnet XLM with built-in cooldown timer to prevent spamming.
const { events, connected, error, clearEvents } = useContractEvents({ contractId, pollInterval: 5000 });Subscribes to real-time Soroban contract events via SSE with automatic polling fallback.
| Category | Suites | Tests |
|---|---|---|
| Services | 5 | 25+ |
| Hooks | 5 | 30+ |
| API Routes | 7 | 30+ |
| Total | 19 | 119 |
All 119 tests pass with zero failures. TypeScript strict mode compiles cleanly.
```bash
npm test
npx jest src/tests/api-faucet.test.ts
npm run test:watch
npm run typecheck ```
StellarDripz uses a hybrid direct/proxied architecture:
For low-latency queries, the browser talks directly to Horizon and Soroban RPC:
- Balance fetching (
directFetchBalance) β direct HorizonloadAccount - Contract simulation (
directSimulateContract) β direct SorobansimulateTransaction - Event polling (
directFetchContractEvents) β direct SorobangetEvents - Latest ledger (
directGetLatestLedger) β direct SorobangetLatestLedger
For rate-limited, logged, and validated operations:
- Faucet funding β
/api/faucet/fundwith per-address cooldown - Payment sending β
/api/payment/sendwith build/sign/submit flow - Contract invocation β
/api/contract/invokewith fee estimation - Event streaming (SSE) β
/api/eventsserver-side event proxy - Transaction history β
/api/historyfrom server database - Analytics β
/api/analyticsfrom server database
ββββββββββββββββββββββββββββββββββββββββββββ
β Browser β
β ββββββββββββ ββββββββββββββββββββββββ β
β β Reads ββββ Horizon / Soroban β β
β β (direct) β β (direct connection) β β
β ββββββββββββ ββββββββββββββββββββββββ β
β ββββββββββββ ββββββββββ ββββββββββββ β
β β Writes ββββ API ββββ Stellar β β
β β (proxied)β β Routes β β Network β β
β ββββββββββββ ββββββββββ ββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββ
Decision: The browser talks directly to Stellar Horizon/Soroban RPC for read operations but routes writes through the Next.js API proxy.
Rationale:
- Reads are idempotent and latency-sensitive β direct connection eliminates a round-trip
- Writes need rate limiting, logging, and validation β proxying ensures consistent enforcement
- Horizon and Soroban RPC both allow CORS from browser contexts
- The API proxy remains the single source of truth for analytics and transaction history
Trade-off: Direct reads forgo server-side logging of balance queries, but the latency improvement (50-100ms) outweighs this for a testnet faucet.