A Next.js 15 app that uploads photos to Irys using Solana mainnet. Built with World ID verification, MiniKit integration, and modern UI components.
- Node.js 18+
- Solana wallet with mainnet SOL
- World App (for authentication)
# Clone and install
git clone https://github.com/0xdevrel/irysXworld.git
cd irysXworld
npm install
# Set up environment
cp env.example .env.localCreate .env.local with:
# World ID Configuration (required for authentication)
WLD_APP_ID=app_your_app_id_here
NEXT_PUBLIC_WLD_ACTION_ID=your_action_id_here
NEXT_PUBLIC_WLD_SIGNAL=
NEXT_PUBLIC_WLD_VERIFICATION_LEVEL=Orb
# Solana Configuration (required for uploads)
SOLANA_PRIVATE_KEY=your_solana_private_key_here
NEXT_PUBLIC_IRYS_GATEWAY=https://gateway.irys.xyz
# Cloudflare KV Configuration (required for persistent photo storage)
CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id_here
CLOUDFLARE_KV_NAMESPACE_ID=your_kv_namespace_id_here
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token_here- Generate new wallet: Use Solana CLI or any wallet
- Export private key: Get base58 encoded private key
- Add to .env.local:
SOLANA_PRIVATE_KEY=your_key_here
Important: This app uses Solana mainnet, which requires real SOL tokens.
- Buy SOL from exchanges like Coinbase, Binance, Kraken
- Transfer SOL to your wallet address (shown in the app)
- Fund Irys account using the
/api/fund-accountendpoint
Important: Photos are now stored persistently using Cloudflare KV to maintain user galleries across sessions.
- Create Cloudflare Account: Sign up at cloudflare.com
- Create KV Namespace:
- Go to Workers & Pages β KV
- Create a new namespace (e.g., "photobooth-storage")
- Copy the namespace ID
- Get Account ID:
- Go to Workers & Pages β Overview
- Copy your Account ID
- Create API Token:
- Go to My Profile β API Tokens
- Create token with "Cloudflare KV:Edit" permissions
- Copy the token
- Add to .env.local: Set all three KV environment variables
npm run devVisit http://localhost:3000
- Sign in with World App - Authenticate using MiniKit
- Upload photos - Gallery or camera capture
- View photos - Click to open lightbox with share/download
- Check transactions - Click transaction ID for Solana explorer
| Endpoint | Method | Description | Parameters |
|---|---|---|---|
/api/upload |
POST | Upload photo to Irys | FormData with file |
/api/check-wallet |
GET | Check wallet balance | None |
/api/fund-account |
POST | Fund Irys account | { amount: number } |
/api/faucet |
POST | Disabled (mainnet) | None |
/api/nonce |
GET | Generate SIWE nonce | None |
/api/complete-siwe |
POST | Verify SIWE signature | { payload, nonce } |
/api/verify |
POST | Verify World ID proof | { payload, action, signal } |
/api/photos |
GET | Get user's photos from KV | x-user-address header |
/api/photos |
POST | Save photo to KV | { photo data } + x-user-address header |
/api/photos |
PUT | Update user profile | { username } + x-user-address header |
/api/photos/[id] |
DELETE | Delete photo from KV | x-user-address header |
src/
βββ app/
β βββ api/ # API routes
β β βββ upload/ # Photo upload endpoint
β β βββ check-wallet/ # Wallet balance check
β β βββ fund-account/ # Fund Irys account
β β βββ nonce/ # SIWE nonce generation
β β βββ complete-siwe/ # SIWE verification
β β βββ verify/ # World ID verification
β β βββ photos/ # Photo CRUD operations with KV
β βββ upload/ # Upload page
β βββ layout.tsx # Root layout with MiniKit provider
β βββ page.tsx # Landing page
βββ components/
β βββ PhotoUpload.tsx # Upload interface with camera/gallery
β βββ PhotoGallery.tsx # Photo grid with lightbox
β βββ WalletAuthButton.tsx # World App authentication
β βββ Navigation.tsx # Header navigation
βββ lib/
β βββ kv.ts # Cloudflare KV utility functions
βββ providers/
βββ minikit-provider.tsx # MiniKit initialization
- Next.js 15 - React framework with App Router
- Irys - Decentralized storage on Solana mainnet
- World ID MiniKit - Authentication and user management
- Cloudflare KV - Persistent photo storage and user profiles
- Tailwind CSS 4 - Modern styling
- TypeScript - Type safety
- User clicks "Sign in with Wallet"
- MiniKit generates SIWE message with nonce
- User signs message in World App
- Backend verifies signature via
/api/complete-siwe - User data stored in localStorage
- User selects image (gallery or camera)
- Image preview with file validation (10MB limit)
- Upload to
/api/uploadwith progress tracking - Irys uploader processes on Solana mainnet
- Transaction ID and gateway URL returned
- Photo metadata saved to Cloudflare KV
- Gallery refreshed with persistent storage
- File selection (gallery/camera)
- Image preview with validation
- Upload progress tracking
- Error handling with retry
- Grid layout with loading states
- Lightbox modal with share/download
- Image error handling and retry
- Transaction explorer integration
- MiniKit integration
- SIWE message generation
- Backend verification
- Username extraction
- Local state with React hooks
- localStorage for user session persistence
- Cloudflare KV for photo metadata persistence
- No external state management library
curl http://localhost:3000/api/check-wallet- Upload progress and errors
- Image loading status
- Transaction details
- MiniKit initialization
- Insufficient SOL: Check balance via
/api/check-wallet - Network errors: Verify Solana mainnet connection
- File size: Ensure images are under 10MB
- MiniKit not available: Check World App installation
- SIWE verification failed: Verify nonce and signature
- Username not found: Check MiniKit user object
- Black thumbnails: Check Irys gateway URL format
- Loading states: Images may take time to propagate
- CORS errors: Verify gateway configuration
- Turbopack: Enabled for faster builds
- ESLint: Code quality and consistency
- TypeScript: Type checking and IntelliSense
npm run build
# Deploy to Vercel with environment variables# Required
SOLANA_PRIVATE_KEY=your_solana_private_key_here
WLD_APP_ID=app_your_app_id_here
NEXT_PUBLIC_WLD_ACTION_ID=your_action_id_here
CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id_here
CLOUDFLARE_KV_NAMESPACE_ID=your_kv_namespace_id_here
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token_here
# Optional
NEXT_PUBLIC_WLD_SIGNAL=
NEXT_PUBLIC_WLD_VERIFICATION_LEVEL=Orb
NEXT_PUBLIC_IRYS_GATEWAY=https://gateway.irys.xyz- Next.js 15: App Router with Turbopack
- TypeScript: Strict mode enabled
- Tailwind CSS 4: PostCSS configuration
- ESLint: Next.js recommended rules
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature) - Make changes with proper TypeScript types
- Test thoroughly (upload, authentication, gallery)
- Submit PR with clear description
- Use TypeScript for all new code
- Follow existing component patterns
- Add proper error handling
- Test on both desktop and mobile
- Verify World App integration
- GitHub: https://github.com/0xdevrel/irysXworld
- Description: Irys upload proof of concept with World ID integration
- Language: TypeScript (95.5%), CSS (3.4%), JavaScript (1.1%)
MIT License - see LICENSE file for details