A production-ready, event-driven trading platform for PumpFun tokens on Solana.
pumpfun-trading-platform/
├── apps/
│ ├── api/ # NestJS REST API + SSE (port 3001)
│ ├── ingestor/ # Helius LaserStream gRPC → Redis Events
│ ├── engine/ # Per-campaign FSM strategy engine
│ ├── executor/ # Intent → RPC send → Solana
│ ├── db-writer/ # Events → MongoDB bulk writer
│ └── web/ # Vite + React 19 SPA (port 5173)
└── packages/
├── domain/ # Zod types: DomainEvent, Intent
├── config/ # Typed env loader
├── state/ # Redis client + Lua scripts
├── mongo/ # Mongoose models + Change Stream watcher
├── solana/ # PumpFun instructions, SOL distribution
└── crypto/ # AES-256-GCM wallet key encryption
npm installcp .env.example .env
# Edit .env with your keysnpm run docker:upnpm run buildnpm run dev- Create Wallet Group —
POST /api/wallets/groups - Create Campaign —
POST /api/campaigns(set devWalletPublicKey, buyerWalletGroupId, config) - Generate Wallets —
POST /api/wallets/campaign/:id/generate - Distribute SOL —
POST /api/wallets/campaign/:id/distribute - Start Campaign —
POST /api/campaigns/:id/start - Monitor — SSE at
GET /api/stream/campaign/:id
idle → monitoring_launch → wait_time1 → gate_others_zero → buy_cycle
↕ ↕
paused_other_buy paused_ratio
↓ ↓
wait_other_sell (fourthWait → resume)
↓
buy_cycle
- wait_time1: Wait after token launch before checking others
- gate_others_zero: Don't buy until no other wallets hold the token
- buy_cycle: Sequentially buy with each wallet (balance - reserveSol), random delay between each
- paused_other_buy: Another wallet bought → sell
otherAmount × responsePercent, wait thirdWaitMs for them to sell - paused_ratio: othersHolding/total > limitThresholdRatio → pause; after fourthWaitMs, force-resume
- OtherSell event: Buy
otherSellAmount × responsePercent
See .env.example for all required variables.
Key variables:
LASERSTREAM_ENDPOINT— Helius LaserStream gRPC endpointLASERSTREAM_API_KEY— LaserStream/Geyser-enabled token used by the ingestorHELIUS_API_KEY— normal Helius RPC key, kept as a fallback for older configsSOLANA_RPC_URL— Solana RPC endpointWALLET_ENCRYPTION_KEY— 32-byte hex key for AES-256-GCM wallet encryptionLOGIN_EMAILS— comma-separated email allowlist for OTP request and verify (legacyLOGIN_EMAILstill supported)MONGODB_URI— MongoDB connection string (must be replica set for Change Streams)REDIS_URL— Redis connection string
cp .env.example .env
# Set production values (JWT_SECRET, WALLET_ENCRYPTION_KEY, CORS_ORIGINS, RPC keys, etc.)npm ci
npm run buildnpm run pm2:start
pm2 save
pm2 startupUseful PM2 commands:
npm run pm2:logs
npm run pm2:restart
npm run pm2:stopsudo mkdir -p /var/www/apumpun/web
sudo rsync -a --delete apps/web/dist/ /var/www/apumpun/web/
sudo cp infra/nginx/apumpun-trading.conf /etc/nginx/sites-available/apumpun-trading
sudo ln -sf /etc/nginx/sites-available/apumpun-trading /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginxgit pull
npm ci
npm run build
sudo rsync -a --delete apps/web/dist/ /var/www/apumpun/web/
npm run pm2:restartOr use the one-shot deploy script:
npm run deploy:prod
# optional: npm run deploy:prod -- --skip-pull