SolStep is a location-based AR fitness application built on Solana blockchain that gamifies physical movement through geolocation-based challenges and NFT collection. Users explore real-world locations, capture photos at checkpoints, and compete in staking challenges.
Diagram showing the challenge creation, invitation, staking and escrow settlement flow
- Location-Based Gameplay: Users walk to real locations (checkpoints) discovered via Google Maps API
- Photo Capture with Verification: Users take photos at checkpoints with geolocation verification (must be within 50m)
- NFT Minting: Verified photos are minted as compressed NFTs (cNFTs) on Solana using Metaplex Bubblegum
- Competitive Challenges: Users can create/join 10-spot challenges where the first person to capture all 10 locations wins the prize pool
- Staking System: Challenges use Solana program for escrow and automatic payouts
- Framework: Next.js 16.0.7 (App Router)
- UI: React 19.2.0, Tailwind CSS 4
- Maps: Google Maps API (
@react-google-maps/api) - Camera:
react-webcamfor photo capture - TypeScript: Full type safety
- Solana: Devnet network
- Anchor: 0.30.1 for Solana program interaction
- Metaplex: Compressed NFT minting (
@metaplex-foundation/mpl-bubblegum) - IPFS: NFT.Storage for image and metadata storage
- Wallets: Phantom, Solflare, Torus support via
@solana/wallet-adapter-react
- Firebase:
- Authentication (Google OAuth)
- Firestore for user data, avatars, challenge progress
- Google APIs:
- Places API for location discovery
- Google Fit API integration (for fitness tracking)
/ (Home)
- Landing page with stats
- Google OAuth login
- Navigation to map/profile/challenges
/map (Main Game Page)
- Tab 1: Interactive map with checkpoints
- Tab 2: Challenges list with progress tracking
- Real-time geolocation tracking
- Checkpoint discovery and filtering
- Challenge creation (10-spot selection)
/camera
- Photo capture interface
- Geolocation verification (50m radius)
- NFT minting after verification
- Challenge progress updates
/profile
- User stats and collected avatars
- Google Fit integration
- NFT gallery
/history
- Completed challenges
- Win/loss history
- Payout records
/challenges (Legacy page - functionality moved to /map)
- Challenge management UI
useAnchorProgram: Solana program initialization and wallet connectionuseChallenges: Challenge CRUD operations, escrow managementuseAvatarCollection: Avatar storage (Firestore + localStorage fallback)useGeolocation: Real-time GPS trackinguseCheckpoints: Google Places API integration for location discoveryuseAuth: Firebase authenticationuseUserProfile: User profile data with Google Fit statsuseNFTMinting: Compressed NFT minting with progress tracking
nftMinting.ts: Metaplex compressed NFT minting serviceipfsUpload.ts: NFT.Storage integration for IPFS uploadsplaces.ts: Google Places API wrapper with mock fallback
Program ID: 3aezMEt3EwNGU7uxBSNNwmXN5b54WXzmyosXpXSdma52
Instructions:
createChallenge: Create a new challenge with stake amount, duration, max participantsinitEscrow: Initialize escrow account for challenge fundsjoinChallenge: Join challenge and stake SOLfinalizeChallenge: Finalize challenge (organizer only)settleChallenge: Distribute winnings to winner and handle penalties
Account Structure:
Challenge: Stores challenge metadata, participants, stakes, timestampsOrganizerStats: Tracks organizer statisticsEscrow: PDA account holding challenge stakes
- User Authentication: Google OAuth via Firebase
- Location Discovery: Google Places API integration with 8 place type filters
- Real-time Geolocation: Continuous GPS tracking with high accuracy
- Photo Capture: Webcam-based photo capture
- Geolocation Verification: 50-meter radius verification before saving
- Compressed NFT Minting: Automatic cNFT creation on Solana after verification (~0.00001 SOL cost)
- Challenge System:
- Create 10-spot challenges with custom stake/duration
- Join challenges with SOL staking
- Real-time progress tracking (spots captured per participant)
- Leaderboard display
- Automatic winner detection (first to capture all 10 spots)
- Escrow-based prize pool management
- Challenge history and completion tracking
- Firestore Collections:
users: User profilesavatars: Collected photos with metadata and NFT mint addresseschallenges: Challenge metadata (10 spots, organizer, etc.)challengeProgress: Participant progress trackingchallengeInvites: Wallet address-based invites
- Solana On-Chain:
- Challenge accounts (stakes, participants, timestamps)
- Escrow accounts (prize pools)
- Compressed NFT ownership and metadata
- Mobile-first responsive design
- Dark theme (slate-950/900)
- Real-time status indicators
- Progress bars for challenge completion
- Error handling with user-friendly messages
- Loading states and animations
- Share challenge functionality (link, QR code, social media)
- Challenge details modal with participant list
- Active challenge highlighting
- Prevention of joining multiple active challenges
- Node.js 18+ and npm
- Google Cloud account (for Maps API and Places API)
- Firebase project
- Solana wallet (Phantom recommended)
- NFT.Storage account (optional, for IPFS uploads)
- Clone the repository:
git clone https://github.com/ankushchk/solstep-web.git
cd solstep-web- Install dependencies:
npm install- Set up environment variables:
Create a
.env.localfile:
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your_google_maps_api_key
NEXT_PUBLIC_NFT_STORAGE_API_KEY=your_nft_storage_api_key-
Configure Firebase: Update
src/lib/firebase.tswith your Firebase config. -
Run the development server:
npm run dev- Open http://localhost:3000 in your browser.
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: Google Maps/Places API keyNEXT_PUBLIC_NFT_STORAGE_API_KEY: NFT.Storage API key (optional, uses placeholder if not set)- Firebase config (in
src/lib/firebase.ts)
- User navigates to checkpoint on map
- Gets within 100m radius → "Collect" button enabled
- Opens camera page
- Captures photo
- System verifies location (must be within 50m)
- If verified → Uploads image to IPFS (NFT.Storage)
- Mints compressed NFT on Solana (Metaplex Bubblegum)
- Saves avatar to Firestore with NFT mint address
- Updates challenge progress if user is in active challenge
- Checks for winner (if all 10 spots captured)
- User selects 10 checkpoints on map (auto-selected with spacing)
- Creates challenge with stake amount, duration, max participants
- Solana program creates challenge account
- Escrow account initialized
- Other users join by staking SOL
- Participants capture spots → progress tracked in Firestore
- First to capture all 10 → marked as winner
- Organizer finalizes challenge
- Winner receives payout from escrow
src/
├── app/ # Next.js pages
│ ├── api/ # API routes (Google Fit, Places)
│ ├── camera/ # Photo capture page
│ ├── challenges/ # Legacy challenges page
│ ├── history/ # Challenge history page
│ ├── map/ # Main game page (map + challenges tabs)
│ │ ├── components/ # Map-specific components
│ │ ├── constants.ts # Map constants
│ │ ├── types.ts # Map types
│ │ └── utils.ts # Map utilities
│ ├── profile/ # User profile page
│ └── page.tsx # Home/landing page
├── components/ # React components
│ ├── ChallengeDetailsModal.tsx
│ ├── ErrorBoundary.tsx
│ ├── NFTCard.tsx
│ ├── ReactQueryProvider.tsx
│ ├── SolanaProviders.tsx
│ └── toast-tx.tsx
├── hooks/ # Custom React hooks
│ ├── useAnchorProgram.ts
│ ├── useAuth.ts
│ ├── useAvatarCollection.ts
│ ├── useChallenges.ts
│ ├── useCheckpoints.ts
│ ├── useGeolocation.ts
│ ├── useNFTMinting.ts
│ ├── useSolana.ts
│ └── useUserProfile.ts
├── idl/ # Solana program IDL
│ └── solstep.json
├── lib/ # Library configurations
│ ├── firebase.ts
│ ├── metaplex.ts
│ ├── solana.ts
│ └── utils.ts
├── services/ # Business logic services
│ ├── ipfsUpload.ts
│ ├── nftMinting.ts
│ └── places.ts
└── utils/ # Utility functions
├── instructions.ts
├── location.ts
├── nftMetadata.ts
├── pdas.ts
├── stats.ts
└── types.ts
- Blockchain:
@coral-xyz/anchor,@solana/web3.js,@metaplex-foundation/mpl-bubblegum - Maps:
@react-google-maps/api - Auth/DB:
firebase - UI:
tailwindcss,react,react-dom - Framework:
next - NFT Storage:
nft.storage - State Management:
@tanstack/react-query
- User authentication
- Location discovery and mapping
- Photo capture
- Geolocation verification
- Compressed NFT minting (Metaplex Bubblegum + IPFS)
- Challenge creation and joining
- Progress tracking
- Firestore data persistence
- Challenge history
- Escrow management
- Network: Currently configured for Solana Devnet
- Mainnet support can be added by updating RPC endpoint
- NFT Storage: Uses NFT.Storage for IPFS uploads
- Falls back to placeholder URLs if API key not configured
- Daily Challenge Limit: Users can create max 2 challenges per day
- Enforced via Firestore queries
