npm install # Install dependencies
npm run db:migrate # Initialize database
npm start # Start server
npm run dev # Start with auto-reloadnode src/scripts/test-webhook.js # Simulate webhooks
node src/scripts/check-balance.js <addr> # Check wallet balancesqlite3 data/gitwork.db # Open database
sqlite3 data/gitwork.db "SELECT * FROM bounties;"
sqlite3 data/gitwork.db "SELECT * FROM activity_log ORDER BY created_at DESC LIMIT 10;"ngrok http 3000 # Expose local server
pm2 start src/index.js # Production process manager
pm2 logs # View logs
pm2 restart all # RestartOctavian:CURRENCY:AMOUNT
Examples:
Octavian:USDC:50Octavian:USDC:100.5Octavian:SOL:2
| Endpoint | Method | Purpose |
|---|---|---|
/ |
GET | API info |
/api/webhooks/github |
POST | GitHub webhooks |
/api/webhooks/health |
GET | Health check |
| Event | Action |
|---|---|
installation.created |
Record installation |
installation.deleted |
Mark as uninstalled |
issues.labeled |
Create bounty if label matches |
issues.unlabeled |
Cancel if pending_deposit |
pull_request.closed |
Process claim if merged |
pending_deposit → deposit_confirmed → ready_to_claim → claimed
↓
cancelled
| Status | Meaning |
|---|---|
pending_deposit |
Waiting for repo owner to deposit |
deposit_confirmed |
Funds in escrow, bounty active |
ready_to_claim |
PR merged, ready for contributor |
claimed |
Funds transferred to contributor |
cancelled |
Bounty cancelled before deposit |
GITHUB_APP_ID=123456
GITHUB_WEBHOOK_SECRET=your_secret
GITHUB_PRIVATE_KEY_PATH=./private-key.pem# Devnet (testing)
SOLANA_RPC_URL=https://api.devnet.solana.com
USDC_MINT_ADDRESS=4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
# Mainnet (production)
SOLANA_RPC_URL=https://your-rpc-provider.com/key
USDC_MINT_ADDRESS=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1vid, github_issue_id, github_repo_owner, github_repo_name,
github_issue_number, bounty_amount, currency,
escrow_wallet_address, escrow_wallet_private_key, status,
created_at, updated_at, deposit_confirmed_at, claimed_at,
claim_wallet_address, contributor_github_username,
pull_request_number, transaction_signatureid, github_installation_id, github_account_login,
github_account_type, installed_at, uninstalled_atid, bounty_id, event_type, event_data, created_atSELECT github_repo_owner, github_repo_name, github_issue_number,
bounty_amount, currency, status
FROM bounties
ORDER BY created_at DESC;SELECT * FROM bounties WHERE status = 'pending_deposit';SELECT * FROM bounties WHERE status = 'deposit_confirmed';SELECT b.github_issue_number, a.event_type, a.created_at
FROM activity_log a
JOIN bounties b ON a.bounty_id = b.id
ORDER BY a.created_at DESC
LIMIT 20;SELECT SUM(bounty_amount) as total, currency
FROM bounties
WHERE status IN ('deposit_confirmed', 'ready_to_claim')
GROUP BY currency;src/
├── index.js # Main entry point
├── routes/
│ └── webhooks.js # Webhook handlers
├── services/
│ ├── bounty.js # Core bounty logic
│ ├── github.js # GitHub API
│ ├── solana.js # Blockchain
│ ├── privy.js # Wallet auth
│ └── deposit-monitor.js # Background service
├── db/
│ ├── database.js # DB connection
│ └── migrate.js # Migrations
├── utils/
│ └── parser.js # Label parsing
└── scripts/
├── test-webhook.js # Test tool
└── check-balance.js # Balance checker
createBounty()- Create new bountygetBountyByIssue()- Find by issueupdateBountyStatus()- Change statusprocessBountyLabel()- Handle label eventcheckBountyDeposit()- Verify deposit
postIssueComment()- Post commentgetIssue()- Get issue detailsgenerateDepositRequestComment()- Format messagegenerateDepositConfirmedComment()- Format message
createEscrowWallet()- Generate keypaircheckUSDCBalance()- Get USDC balancecheckSOLBalance()- Get SOL balancegetUSDCTokenAccount()- Get token account
start()- Start monitoringstop()- Stop monitoring- Runs every 30 seconds
- Checks all pending deposits
- Check ngrok is running
- Verify webhook URL in GitHub App settings
- Check webhook secret matches
- View deliveries in GitHub App → Advanced tab
- Verify correct wallet address
- Check correct token (USDC not SOL)
- Verify amount matches
- Check monitor is running:
pm2 list - Manual check:
node src/scripts/check-balance.js <addr>
# Check for other processes
ps aux | grep node
# If needed, restart
pm2 restart gitworkEnsure these permissions:
- Issues: Read & Write ✅
- Pull requests: Read & Write ✅
- Metadata: Read-only ✅
curl http://localhost:3000/api/webhooks/healthpm2 logs gitwork # View logs
pm2 logs gitwork --lines 100 # Last 100 linespm2 status # All processes
pm2 show gitwork # Detailed infocp data/gitwork.db backups/gitwork_$(date +%Y%m%d).db0 2 * * * cp /path/to/data/gitwork.db /path/to/backups/gitwork_$(date +\%Y\%m\%d).db-
.envnot in git -
private-key.pemnot in git - Webhook secret is strong
- Database file has restricted permissions
- HTTPS enabled in production
- Rate limiting enabled
- Regular backups configured
- GitHub Apps: https://github.com/settings/apps
- Solana Explorer (Devnet): https://explorer.solana.com/?cluster=devnet
- Solana Explorer (Mainnet): https://explorer.solana.com/
- QUICKSTART.md - 5-minute setup
- SETUP_GUIDE.md - Detailed setup
- ARCHITECTURE.md - System design
- DEPLOYMENT.md - Production deployment
- REPO_OWNER_FLOW.md - Flow walkthrough
- VISUAL_FLOW.md - Diagrams
- Update database schema in
src/db/migrate.js - Add service methods in
src/services/ - Add webhook handler in
src/routes/webhooks.js - Update documentation
// Enable verbose logging
console.log('Bounty data:', bounty);
console.log('Webhook payload:', JSON.stringify(payload, null, 2));Already optimized with indexes on:
statusgithub_repo_owner, github_repo_nameescrow_wallet_address
-- Slow queries (if any)
PRAGMA compile_options;
EXPLAIN QUERY PLAN SELECT * FROM bounties WHERE status = 'pending_deposit';- Deposit check interval: 30 seconds
- USDC decimals: 6
- SOL decimals: 9
- Default port: 3000
- Database: SQLite (WAL mode)
Keep this card handy for quick reference! 📋