Anthony Olajide
Jan 2, 2026 at 2:56 PM
Sign in to join the conversation
import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js'
const connection = new Connection('https://api.devnet.solana.com')
export const recordGameResult = async (
winner: PublicKey,
loser: PublicKey,
amount: number
) => {
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: loser,
toPubkey: winner,
lamports: amount
})
)
// In a real app, you'd sign and send this transaction properly
return transaction
}
export const getGameHistory = async (player: PublicKey) => {
// Implement fetching game history from your on-chain program
return []
}
yarn build
yarn add -D firebase-tools
firebase login
firebase init
# Select Hosting and follow prompts
firebase deploy
npx create-react-app solana-tic-tac-toe --template typescript
cd solana-tic-tac-toe
yarn add @solana/web3.js @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets @solana/wallet-adapter-base firebase @chakra-ui/react @emotion/react @emotion/styled framer-motion
yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}@tailwind base;
@tailwind components;
@tailwind utilities;
import { initializeApp } from 'firebase/app'
import { getDatabase } from 'firebase/database'
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
databaseURL: "YOUR_DATABASE_URL",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_SENDER_ID",
appId: "YOUR_APP_ID"
};
const app = initializeApp(firebaseConfig)
const database = getDatabase(app)
export { database }
import React, { useMemo } from 'react'
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'
import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets'
import { clusterApiUrl } from '@solana/web3.js'
require('@solana/wallet-adapter-react-ui/styles.css')
export const WalletContextProvider = ({ children }: { children: React.ReactNode }) => {
const network = WalletAdapterNetwork.Devnet
const endpoint = useMemo(() => clusterApiUrl(network), [network])
const wallets = useMemo(() => [new PhantomWalletAdapter()], [])
return (
{children}
)
}
import React from 'react'
type BoardProps = {
board: string[]
onCellClick: (index: number) => void
disabled: boolean
}
export const GameBoard = ({ board, onCellClick, disabled }: BoardProps) => {
return (
{board.map((cell, index) => (
onCellClick(index)}
disabled={disabled || !!cell}
className="flex items-center justify-center text-4xl font-bold bg-gray-200 hover:bg-gray-300 rounded-lg h-20 w-20"
>
{cell}
))}
)
}
import { useState, useEffect } from 'react'
import { ref, onValue, set, push, update } from 'firebase/database'
import { database } from '../firebase'
import { useWallet } from '@solana/wallet-adapter-react'
type GameState = {
board: string[]
currentPlayer: 'X' | 'O'
winner: string | null
playerX: string | null
playerO: string | null
}
export const useGame = (gameId?: string) => {
const { publicKey } = useWallet()
const [gameState, setGameState] = useState({
board: Array(9).fill(''),
currentPlayer: 'X',
winner: null,
playerX: null,
playerO: null
})
const [isLoading, setIsLoading] = useState(true)
const [isPlayer, setIsPlayer] = useState(false)
const [playerSymbol, setPlayerSymbol] = useState(null)
// Game logic implementation here
// Including Firebase realtime updates, move validation, etc.
return {
gameState,
isLoading,
isPlayer,
playerSymbol,
makeMove: (cellIndex: number) => {
// Implement move logic
},
createGame: async () => {
// Implement game creation
},
joinGame: async (gameId: string) => {
// Implement game joining
}
}
}
import React from 'react'
import { WalletContextProvider } from './components/WalletContextProvider'
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'
import { useGame } from './hooks/useGame'
import { GameBoard } from './components/GameBoard'
function App() {
const {
gameState,
isLoading,
isPlayer,
playerSymbol,
makeMove,
createGame,
joinGame
} = useGame()
if (isLoading) return Loading...
return (
Solana Tic-Tac-Toe
{!gameState.playerX || !gameState.playerO ? (
Create New Game
joinGame('game-id-from-input')}
className="py-2 px-4 bg-green-500 text-white rounded-r hover:bg-green-600"
>
Join
) : (
{gameState.winner ? (
{gameState.winner === 'draw'
? "It's a draw!"
: `${gameState.winner} wins!`}
) : (
Current turn: {gameState.currentPlayer}
{isPlayer && ` (You're ${playerSymbol})`}
)}
)}
)
}
export default function WrappedApp() {
return (
)
}