Testing on Localhost

Quick Testing Setup

You can test your game running on localhost directly in the Upside.win test environment without deploying.

How it works:

  1. Run your game backend on http://localhost:3000 (or any port)
  2. Base64 encode your localhost URL
  3. Navigate to the test URL on upside.win

Step-by-Step

Step 1: Start your game backend

bash
npm run dev# Game running at http://localhost:3000

Step 2: Base64 encode your URL

Using Node.js:

javascript
const url = "http://localhost:3000";const encoded = Buffer.from(url).toString("base64");console.log(encoded); // aHR0cDovL2xvY2FsaG9zdDozMDAw

Using command line:

bash
echo -n "http://localhost:3000" | base64# aHR0cDovL2xvY2FsaG9zdDozMDAw

Online: Use any base64 encoder at https://www.base64encode.org/

Step 3: Test in Upside.win

Visit the test URL:

text
https://upside.win/test/games/aHR0cDovL2xvY2FsaG9zdDozMDAw

Replace aHR0cDovL2xvY2FsaG9zdDozMDAw with your encoded URL.

Examples

Different localhost URLs:

URLBase64Test Link
http://localhost:3000aHR0cDovL2xvY2FsaG9zdDozMDAwhttps://upside.win/test/games/aHR0cDovL2xvY2FsaG9zdDozMDAw
http://localhost:5000aHR0cDovL2xvY2FsaG9zdDo1MDOwhttps://upside.win/test/games/aHR0cDovL2xvY2FsaG9zdDo1MDOw
http://127.0.0.1:3000aHR0cDovLzEyNy4wLjAuMTozMDAwhttps://upside.win/test/games/aHR0cDovLzEyNy4wLjAuMTozMDAw

Development Workflow

  1. Create game code - Write your React frontend and Cloudflare Hono backend
  2. Start locally - Run npm run dev on localhost
  3. Generate test URL - Base64 encode your localhost address
  4. Test on Upside - Visit https://upside.win/test/games/<BASE64>
  5. Get JWT & test - Game loads with real JWT for testing
  6. Iterate - Make changes locally and refresh the test URL
  7. Deploy - When ready, deploy backend and update game URL

Tips for Local Testing

  • Use same machine: Keep localhost running while testing
  • Check CORS: Ensure your backend allows requests from upside.win domains

Troubleshooting Local Testing

Problem: "Game not found" or 404

  • Solution: Verify localhost URL is correct and encoding is accurate

Problem: CORS errors

  • Solution: Your backend needs to accept requests from upside.win domain

Problem: JWT errors during testing

  • Solution: Make sure you're using staging API key, not production

Problem: Network requests failing

  • Solution: Check that localhost is running and firewall allows requests

Complete Example: Coin Flip Game

Frontend (React)

javascript
import { ParentProvider, useParentContext } from "@b3dotfun/upside-sdk";export default function CoinFlipGame() { return ( <ParentProvider> <CoinFlipContent /> </ParentProvider> );}function CoinFlipContent() { const { token, balance, playerId } = useParentContext(); const [gameState, setGameState] = useState("ready"); // ready, playing, won, lost const [prediction, setPrediction] = useState(null); const [result, setResult] = useState(null); const [earnings, setEarnings] = useState(0); const playGame = async playerPrediction => { setPrediction(playerPrediction); setGameState("playing"); try { // Call your backend const response = await fetch("/api/game/coin-flip", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ playerId, prediction: playerPrediction, betAmount: "100000000000000000", // 1 token in wei }), }); const data = await response.json(); if (data.outcome === "win") { setGameState("won"); setEarnings(data.payout); } else { setGameState("lost"); setEarnings(0); } setResult(data.result); } catch (error) { console.error("Game error:", error); setGameState("error"); } }; return ( <div style={{ textAlign: "center", padding: "40px" }}> <h1>Coin Flip</h1> <p>Balance: {(balance / 1e18).toFixed(2)} WIN</p> {gameState === "ready" && ( <div> <button onClick={() => playGame("heads")}>Predict Heads</button> <button onClick={() => playGame("tails")}>Predict Tails</button> </div> )} {gameState === "playing" && <p>Flipping...</p>} {gameState === "won" && ( <div> <p>🎉 You won! Coin landed on {result}</p> <p>+{(earnings / 1e18).toFixed(2)} WIN</p> </div> )} {gameState === "lost" && ( <div> <p>❌ You lost! Coin landed on {result}</p> <p>Better luck next time</p> </div> )} {gameState !== "ready" && <button onClick={() => setGameState("ready")}>Play Again</button>} </div> );}

Backend (Hono + Cloudflare Workers)

javascript
import { Hono } from "hono";import { createB3Client } from "@b3dotfun/upside-sdk/server";const app = new Hono();app.post("/api/game/coin-flip", async c => { const { prediction, betAmount } = await c.req.json(); try { // Create B3Client from Hono context // Automatically extracts auth token from Authorization header const b3Client = createB3Client(c); // Step 1: Place the bet (amount in wei) const betResult = await b3Client.placeBet("coin-flip", betAmount); if (!betResult.sessionId) { return c.json({ error: "Failed to place bet" }, 400); } // Step 2: Game logic - flip coin const coin = Math.random() < 0.5 ? "heads" : "tails"; const isWin = coin === prediction; // Calculate payout: 50% profit on win (betAmount * 1.5, in wei) const payout = isWin ? (BigInt(betAmount) * BigInt(150)) / BigInt(100) : "0"; // Step 3: Store game in your database (D1, etc.) // await db.execute( // "INSERT INTO games (sessionId, prediction, result, betAmount, payout) VALUES (?, ?, ?, ?, ?)", // [betResult.sessionId, prediction, coin, betAmount, payout.toString()] // ); // Step 4: Process payout const payoutResult = await b3Client.processPayout("coin-flip", betResult.sessionId, payout.toString(), { playerChoice: prediction, result: coin, outcome: isWin ? "win" : "loss", }); // Step 5: Return result to frontend return c.json({ sessionId: betResult.sessionId, prediction, result: coin, outcome: isWin ? "win" : "loss", payout: isWin ? payout.toString() : "0", newBalance: payoutResult.newBalance, }); } catch (error) { console.error("Game error:", error); return c.json({ error: error.message }, 500); }});export default app;

Troubleshooting

Common Issues

Problem: placeBet fails with "Insufficient balance"

  • Solution: Check player balance before placing bet, or increase bet amount display in UI

Problem: processPayout returns "session not found"

  • Solution: Verify sessionId matches bet response, check for typos

Problem: Duplicate game sessions or bets

  • Solution: Use same sessionId for retries, implement idempotency on your end

Problem: JWT expires during gameplay

  • Solution: Refresh token before game starts, handle token expiration gracefully

Problem: Game logic runs on client, leading to cheating

  • Solution: Move ALL game logic to backend, client only displays results
Ask a question... ⌘I