SkateSpots/BOUNTY-SYSTEM-PLAN.md
SkateSpots 6407310213 feat(relay): cut over community relay to self-hosted Newlay
Point SKATE_RELAY, the default relay pools, the DM/CVM/zap relay arrays, the cvm-server + push-service defaults, and the archive default at wss://relay.skate-spots.org, keeping the legacy hosted relay as a fallback during the client-update window. Restored 115/115 archived events; the relay runs behind Caddy with TLS. Docs + AGENTS.md updated.
2026-10-12 12:38:13 +07:00

19 KiB

Bounty System Implementation Plan

🎯 Goal

Create a bounty system to incentivize Thai/Asian skaters to document spots, funded by your ZapFunder campaign, with spam prevention mechanisms.


🛡️ SPAM PREVENTION STRATEGY

Layer 1: NIP-05 Verification (Soft Requirement)

What: DNS-based identity verification How it works:

  • Users with NIP-05 (like username@skate-spots.com) are trusted
  • Non-verified users can still participate BUT:
    • Their bounty claims require manual review
    • Verified users get instant payouts
    • Verified users can earn 2x bounties

Implementation:

// Check if user has NIP-05
const hasNIP05 = user.metadata?.nip05 && isValidNIP05(user.metadata.nip05);

// Verified users = auto-approve
// Non-verified = pending review
const bountyStatus = hasNIP05 ? 'approved' : 'pending_review';

Pros:

  • ✅ Not too restrictive (anyone can still try)
  • ✅ Incentivizes getting NIP-05 (builds trust)
  • ✅ Manual review catches spam before payout
  • ✅ Thai skaters can get free NIP-05 from nostr.directory

Cons:

  • ⚠️ Requires manual review for non-verified
  • ⚠️ Slight friction for new users

Layer 2: NIP-32 Labeling System (Quality Control)

What: Community labeling and moderation

How it works:

  • Bounty system publishes kind 1985 labels on submitted spots
  • Labels: verified-spot, spam, low-quality, excellent
  • Community can also label (distributed moderation)
  • Only spots with verified-spot label get paid

Example label event:

{
  "kind": 1985,
  "tags": [
    ["L", "skatespots.bounty"],
    ["l", "verified-spot", "skatespots.bounty"],
    ["a", "30818:<user-pubkey>:<spot-identifier>"]
  ],
  "content": "Verified: Real skate spot in Bangkok with photos"
}

Pros:

  • ✅ Distributed moderation (community helps)
  • ✅ Transparent verification process
  • ✅ Can query spots by label
  • ✅ Reusable for other quality control

Layer 3: Geographic Validation (Smart Checking)

What: Verify spots are in target regions

How it works:

  • Bounty specifies region: "Bangkok", "Thailand", "Asia"
  • Spot must have geohash in that region
  • Reverse geocode to verify city/country
  • Auto-reject if outside target area

Implementation:

// Bounty: "Add 5 spots in Bangkok"
const bountyRegion = { lat: 13.7563, lng: 100.5018, radiusKm: 50 };

// Check if spot is within region
const spotCoords = decodeGeohash(spot.geohash);
const distance = calculateDistance(bountyRegion, spotCoords);

if (distance > bountyRegion.radiusKm) {
  // Not in Bangkok - reject claim
  return false;
}

Pros:

  • ✅ Automated verification
  • ✅ Prevents gaming (can't claim Bangkok bounty with NYC spot)
  • ✅ Works for city/country/region bounties

Layer 4: NIP-13 Proof of Work (Optional - Heavy Hammer)

What: Require computational work for bounty claims

How it works:

  • Spots claiming bounties must have 16-20 difficulty PoW
  • Makes bulk spam economically infeasible
  • Normal users barely notice (30 seconds to mine)

Pros:

  • ✅ Extremely effective against bots/spam
  • ✅ No human review needed
  • ✅ Standard Nostr feature

Cons:

  • ⚠️ Battery drain on mobile
  • ⚠️ Friction for legitimate users
  • ⚠️ Only use if spam becomes serious problem

Recommendation: Keep as backup option, don't implement initially


Layer 5: Social Graph Filtering (Pyramid Integration)

What: Only Pyramid relay members can claim bounties

How it works:

  • Bounty claims only valid from relay.skate-spots.org members
  • Invite-only relay (using Pyramid)
  • Members vouch for quality
  • Spam = member gets kicked

Pros:

  • ✅ Self-regulating community
  • ✅ High trust environment
  • ✅ Uses your Pyramid relay

Cons:

  • ⚠️ Excludes new users initially
  • ⚠️ Requires Pyramid setup
  • ⚠️ Less open/permissionless

Recommendation: Good for "premium bounties" tier


For Launch (Simple & Effective):

  1. ✅ NIP-05 Verification - Instant approve if verified, manual review if not
  2. ✅ Geographic Validation - Auto-check region boundaries
  3. ✅ Manual Review Queue - You or moderators approve claims

For Scale (When Community Grows):

  1. ✅ NIP-32 Labeling - Community helps moderate
  2. ✅ Reputation System - Track user history (spam = ban)
  3. ✅ Pyramid Relay - Premium bounties for members only

Nuclear Option (If Spam Gets Bad):

  1. ✅ NIP-13 PoW - Make spam expensive

📋 BOUNTY SYSTEM ARCHITECTURE

A. Custom Event Kind for Bounties

Create new kind: 30824 (Bounty Listing)

{
  "kind": 30824,
  "tags": [
    ["d", "bangkok-5-spots-jan2025"],
    ["title", "Add 5 spots in Bangkok"],
    ["description", "Document 5 skateable spots in Bangkok with photos"],
    ["reward", "10000"], // sats
    ["region", "Bangkok"],
    ["region", "Thailand"], // can have multiple
    ["g", "w4rqq"], // geohash for Bangkok center
    ["requirements", "min_photos:3"],
    ["requirements", "spot_types:street,park,diy"],
    ["status", "active"], // active, claimed, completed, expired
    ["expires", "1738368000"], // unix timestamp
    ["funded_by", "zapfunder"],
    ["fund_event", "<zapfunder event id>"]
  ],
  "content": "We're funding documentation of Bangkok's skate scene! Add 5 quality spots with photos and description to earn 10,000 sats. Spots must be in Bangkok metro area."
}

B. Custom Event Kind for Bounty Claims

Create new kind: 30825 (Bounty Claim)

{
  "kind": 30825,
  "tags": [
    ["d", "claim-bangkok-5-spots-user123"],
    ["a", "30824:<bounty-creator-pubkey>:bangkok-5-spots-jan2025"],
    ["bounty", "bangkok-5-spots-jan2025"],
    ["status", "pending"], // pending, approved, rejected, paid
    
    // References to submitted spots (proof of work)
    ["a", "30818:<user-pubkey>:<spot1-id>"],
    ["a", "30818:<user-pubkey>:<spot2-id>"],
    ["a", "30818:<user-pubkey>:<spot3-id>"],
    ["a", "30818:<user-pubkey>:<spot4-id>"],
    ["a", "30818:<user-pubkey>:<spot5-id>"],
    
    // Verification data
    ["nip05", "<user-nip05-if-verified>"],
    ["L", "skatespots.verification"],
    ["l", "pending-review", "skatespots.verification"],
    
    // Payment info
    ["lud16", "<user-lightning-address>"],
    ["payment_request", "<bolt11-or-lnurl>"]
  ],
  "content": "I've added 5 spots in Bangkok as requested!"
}

C. Verification Events (NIP-32 Labels)

Moderator approves claim:

{
  "kind": 1985,
  "tags": [
    ["L", "skatespots.bounty"],
    ["l", "verified", "skatespots.bounty"],
    ["l", "approved", "skatespots.bounty"],
    ["a", "30825:<user-pubkey>:<claim-id>"],
    ["p", "<user-pubkey>"] // notify user
  ],
  "content": "Claim verified! All 5 spots are legit Bangkok locations with good photos."
}

Community flags spam:

{
  "kind": 1985,
  "tags": [
    ["L", "skatespots.bounty"],
    ["l", "spam", "skatespots.bounty"],
    ["a", "30818:<spammer-pubkey>:<fake-spot-id>"],
    ["p", "<spammer-pubkey>"]
  ],
  "content": "This is not a real skate spot - it's a restaurant"
}

🔧 TECHNICAL IMPLEMENTATION PLAN

Phase 1: Core Infrastructure (Week 1-2)

1.1 Create Bounty Management System

  • Define custom kinds (30824, 30825) in NIP.md
  • Create src/lib/bounty-types.ts with TypeScript types
  • Create src/hooks/useBounties.ts (query active bounties)
  • Create src/hooks/useBountyClaims.ts (query user's claims)
  • Create src/hooks/useCreateBounty.ts (admin only)
  • Create src/hooks/useClaimBounty.ts (submit claim)

1.2 Geographic Validation Utilities

  • Create src/lib/geo-validation.ts
    • Function: isSpotInRegion(geohash, regionBounds)
    • Function: getRegionBounds(cityName) (Bangkok, Chiang Mai, etc.)
    • Function: validateBountyClaim(bounty, spots)

1.3 NIP-05 Verification Helper

  • Create src/lib/nip05-verification.ts
    • Function: isUserVerified(user)
    • Function: getVerificationStatus(user)
    • Cache verification results (24hr expiry)

Phase 2: UI Components (Week 2-3)

2.1 Bounty Cards

  • src/components/BountyCard.tsx
    • Display bounty details (title, reward, region, expires)
    • Progress indicator (e.g., "Add 5 spots: 2/5 complete")
    • "Claim Bounty" button
    • Requirements checklist

2.2 Bounty Claim Flow

  • src/components/BountyClaimDialog.tsx
    • Select spots to submit (from user's spots)
    • Show auto-validation results (region check, photo check)
    • Submit claim button
    • Lightning address field (for payment)

2.3 Admin Bounty Creation

  • src/components/CreateBountyDialog.tsx (admin only)
    • Bounty details form
    • Region selector (city/country)
    • Requirements (min photos, spot types)
    • Reward amount
    • Expiration date
    • Fund source (ZapFunder link)

2.4 Claim Review Dashboard

  • src/pages/BountyReviewPage.tsx (admin/moderator only)
    • List pending claims
    • View submitted spots on map
    • Approve/reject buttons
    • Bulk actions
    • Payment tracking

Phase 3: Rewards Page Integration (Week 3-4)

3.1 Update RewardsPage

  • Add "Active Bounties" section at top
  • Show user's claimed bounties
  • Display total earnings from bounties
  • Leaderboard: "Top Bounty Hunters"

3.2 Notifications

  • New bounty posted → Notify all users
  • Claim approved → Notify user + send zap
  • Claim rejected → Notify user with reason

Phase 4: Payment System (Week 4)

4.1 Auto-Zap Integration

  • When claim approved → Auto-zap user from your wallet
  • Use NWC (Nostr Wallet Connect) for automated payments
  • Track payments in database or Nostr events
  • Handle failed payments (retry logic)

4.2 ZapFunder Integration

  • Link bounty to ZapFunder event ID
  • Display funding progress
  • "This bounty is funded by community via ZapFunder"
  • Track total spent vs. total funded

🎨 UI/UX FLOW

User Journey: Claiming a Bounty

  1. Discover - User sees "Active Bounties" on Rewards page
  2. View Details - Click bounty card to see requirements
  3. Check Eligibility - See if they qualify (NIP-05, region, etc.)
  4. Add Spots - Go to map and add required spots
  5. Submit Claim - Select their spots, submit claim
  6. Wait for Review - Track status (pending → approved/rejected)
  7. Get Paid - Receive zap automatically when approved

Admin Journey: Creating a Bounty

  1. Admin Panel - Settings → Bounties (or /admin/bounties)
  2. Create Bounty - Fill form (title, reward, region, requirements)
  3. Fund Bounty - Link ZapFunder campaign
  4. Publish - Bounty goes live immediately
  5. Monitor Claims - Review submissions as they come
  6. Approve/Reject - One-click approval sends zap
  7. Close Bounty - Mark complete when quota reached

🔐 ACCESS CONTROL & ROLES

Public (Everyone)

  • ✅ View active bounties
  • ✅ Submit claims (with verification)
  • ✅ See leaderboards

Verified Users (NIP-05)

  • ✅ Instant claim approval (for simple bounties)
  • ✅ 2x reward multiplier
  • ✅ Priority review

Moderators (Designated pubkeys)

  • ✅ Review claims
  • ✅ Approve/reject submissions
  • ✅ Add labels to spots (NIP-32)
  • ✅ Flag spam

Admin (You)

  • ✅ Create bounties
  • ✅ Edit bounties
  • ✅ Assign moderators
  • ✅ View analytics
  • ✅ Manage funds

💾 DATA STORAGE

Option A: Pure Nostr (Fully Decentralized)

Pros: No backend, censorship-resistant, transparent Cons: Harder to query, no guaranteed delivery

Option B: Hybrid (Nostr + Your Relay)

Pros: Fast queries, reliable, still on Nostr Cons: Depends on your relay staying online Recommendation: ⭐ Use this

Architecture:

  • Bounties published to Nostr (kind 30824)
  • Claims published to Nostr (kind 30825)
  • Your relay indexes them for fast lookup
  • Verification labels (kind 1985) published to Nostr

🎮 GAMIFICATION FEATURES

1. Bounty Hunter Badges (NIP-58)

  • 🥉 "Rookie Hunter" - Claimed 1st bounty
  • 🥈 "Bounty Collector" - Claimed 5 bounties
  • 🥇 "Master Hunter" - Claimed 20 bounties
  • 💎 "Bangkok Legend" - Claimed all Bangkok bounties

2. Leaderboards

  • Top bounty earners (all-time)
  • Top this month
  • Top per region (Bangkok, Chiang Mai, etc.)
  • Fastest claim (first to complete new bounty)

3. Streaks

  • "7-Day Streak" - Claimed bounty every week for 7 weeks
  • Streak bonuses (+10% per week)

4. Combo Multipliers

  • Claim 3 bounties in one day = 1.5x reward
  • Complete bounty within 24hr of posting = 2x reward

📊 EXAMPLE BOUNTIES (Thailand Focus)

Starter Bounties (Easy Entry)

🇹🇭 Bangkok Basics
- Add 3 spots in Bangkok
- Reward: 5,000 sats
- Requirements: 2+ photos each, description
- NIP-05: Not required (manual review)

Regional Expansion

🌏 Chiang Mai Explorer
- First 5 spots in Chiang Mai
- Reward: 15,000 sats
- Requirements: 3+ photos, detailed features
- NIP-05: Required for instant payout

Quality Focus

📸 Bangkok Photo Mission
- Add high-quality photos to 10 existing Bangkok spots
- Reward: 8,000 sats
- Requirements: 1080p+ photos, multiple angles
- NIP-05: Recommended

Pioneer Bounties

🚀 First in Laos
- Be the first to add ANY spot in Laos
- Reward: 50,000 sats BONUS
- Requirements: Verified location, proof photo
- NIP-05: Required

Community Building

🏪 Shop Network
- Add 5 verified skate shops in Thailand
- Reward: 20,000 sats
- Requirements: Shop owner verification, contact info
- NIP-05: Required + shop NIP-05

🚨 SPAM SCENARIOS & SOLUTIONS

Scenario 1: Bulk Fake Spots

Attack: User adds 100 fake "spots" (restaurants, random locations) Prevention:

  • ✅ Geographic validation (must be in target region)
  • ✅ Manual review for non-NIP-05 users
  • ✅ Community can label as spam (NIP-32)
  • ✅ Reputation system (1 rejection = ban from future bounties)

Scenario 2: Low-Quality Content

Attack: User adds 5 spots with no photos, generic descriptions Prevention:

  • ✅ Auto-validation checks (min 2 photos required)
  • ✅ Quality multiplier (low quality = reduced payout)
  • ✅ Manual review rejects poor submissions

Scenario 3: Duplicate Submissions

Attack: Multiple users claim same spot for bounty Prevention:

  • ✅ Check if spot already exists (by geohash proximity)
  • ✅ First valid submission wins
  • ✅ Later duplicates auto-rejected

Scenario 4: Sybil Attack

Attack: One person creates multiple accounts to claim same bounty multiple times Prevention:

  • ✅ NIP-05 required (hard to get multiple verifications)
  • ✅ Lightning address reuse detection
  • ✅ IP/device fingerprinting (optional, privacy trade-off)
  • ✅ Manual review for suspicious patterns

💰 PAYMENT FLOW

Automated Payment (NIP-47 NWC)

1. Claim approved (kind 1985 label)
2. System reads user's lud16/lnurl from profile
3. System generates invoice request
4. System sends zap via your NWC connection
5. Zap receipt (kind 9735) published to Nostr
6. Update bounty claim status to "paid"
7. Notify user

Manual Payment (Backup)

1. Claim approved
2. User added to "pending payment" queue
3. Admin manually zaps user
4. Mark as paid in system

Recommendation: Start with manual, add automation later


📈 ANALYTICS TO TRACK

  • Total bounties created
  • Total claims submitted
  • Approval rate (% approved vs rejected)
  • Average time to approval
  • Total sats paid out
  • Regional breakdown (Bangkok: 45%, Chiang Mai: 20%, etc.)
  • Top earners
  • Spam detection rate

🛠️ TECH STACK

Frontend (SkateSpots App)

  • React components for bounty UI
  • Custom hooks for querying bounties/claims
  • NIP-32 labeling integration
  • NIP-05 verification checking

Backend/Logic

  • Bounty validation functions (pure TypeScript)
  • Geographic boundary checking (ngeohash)
  • Auto-approval logic for verified users
  • Payment queue management

Nostr Events

  • Kind 30824: Bounty listings
  • Kind 30825: Bounty claims
  • Kind 1985: Verification labels (NIP-32)
  • Kind 8: Badge awards (NIP-58) for achievements

Payment

  • NIP-47: Nostr Wallet Connect (for auto-zaps)
  • Manual zap via your wallet (backup)
  • Track via kind 9735 zap receipts

📅 IMPLEMENTATION TIMELINE

Week 1: Foundation

  • Define custom kinds in NIP.md
  • Create bounty data types
  • Build query hooks
  • Geographic validation utilities

Week 2: UI

  • BountyCard component
  • BountyClaimDialog
  • Update RewardsPage
  • Admin creation form

Week 3: Verification

  • NIP-05 checking
  • Manual review dashboard
  • Approval/rejection flow
  • NIP-32 labeling

Week 4: Payment

  • Manual payment tracking
  • Zap integration
  • Notification system
  • Analytics dashboard

Week 5: Launch

  • Create first 5 bounties (Bangkok, Chiang Mai, Phuket, etc.)
  • Promote on social media
  • Monitor for spam
  • Iterate based on feedback

🎯 SUCCESS METRICS

Month 1 Goals

  • 50+ bounty claims submitted
  • 30+ approved claims
  • 10+ verified skaters with NIP-05
  • <5% spam rate

Month 3 Goals

  • 200+ spots added via bounties
  • 100+ active bounty hunters
  • Organic bounty requests from community
  • Self-sustaining with community funding

⚖️ ANTI-SPAM RECOMMENDATION

Start Simple, Add Layers as Needed:

  1. Launch with:

    • ✅ NIP-05 incentives (2x for verified)
    • ✅ Geographic validation (auto-check)
    • ✅ Manual review queue
  2. Add if spam appears:

    • ✅ NIP-32 community labeling
    • ✅ Reputation/ban system
  3. Nuclear option:

    • ✅ NIP-13 Proof of Work
    • ✅ Pyramid relay requirement

This progressive approach:

  • Keeps friction low initially
  • Can scale up protection as needed
  • Doesn't scare away legitimate users
  • Community helps moderate at scale

🚀 LAUNCH STRATEGY (Thailand)

Week 0: Pre-Launch

  1. Create 10 diverse bounties (Bangkok, Chiang Mai, Phuket, etc.)
  2. Recruit 3 Thai moderators (trusted skaters)
  3. Test with small group (10 beta testers)

Week 1: Soft Launch

  1. Announce on Thai skate Facebook groups
  2. Offer "Early Bird Bonus" (first 50 claims = +50%)
  3. Monitor closely for spam
  4. Quick approvals (same-day)

Week 2-4: Scale Up

  1. Add regional bounties (Vietnam, Philippines, Malaysia)
  2. Introduce quality multipliers
  3. Announce weekly winners on social
  4. Cross-promote with Thai skate shops

💡 FINAL RECOMMENDATION

Most Important Decision: Verification Method

Option A: NIP-05 Optional (Friendly)

  • Anyone can claim
  • Non-verified = manual review
  • Verified = instant approval
  • Best for: Growing user base quickly

Option B: NIP-05 Required (Quality)

  • Only verified users can claim
  • All claims auto-approved (with geo check)
  • Best for: High-quality, spam-free

Option C: Pyramid Members Only (Exclusive)

  • Only relay members can claim
  • Invite-based (you control who joins)
  • Best for: Tight-knit community

My vote: Start with Option A (friendly), move to Option B if spam becomes a problem. Keep Option C for "premium bounties" (50k+ sats).


Does this plan make sense for your use case? Any questions about implementation specifics? 🛹⚡