A decentralized horse racing betting game built on Solana where players can create races, join with referral codes, and compete for prizes using native GOR tokens.
GOR Race is a blockchain-based horse racing simulation where:
- Anyone can create races with configurable wait times
- Players join races using unique referral codes
- Races have a two-phase system: joining period + 60-second race simulation
- Winners are determined randomly and can claim their prizes
- Platform takes a 5% fee from the total pool
- Players can create profiles with usernames and track their statistics
- Comprehensive leaderboard system ranks players by various metrics
- Profile Creation: Players create profiles with usernames for leaderboard tracking
- Race Creation: Race creator sets wait time (30-180 seconds) and receives a referral code
- Joining: Players use referral codes to join races and select horses (1-10)
- Execution Phase 1: After wait time expires, race simulation begins (60 seconds)
- Execution Phase 2: Race completes, winners are determined
- Prize Claiming: Winners can claim their share of the prize pool
- Stats Update: Players update their statistics for leaderboard tracking
- Pending: Waiting for players to join
- Racing: 60-second race simulation in progress
- Completed: Race finished, prizes available
- Cancelled: Not enough players joined (minimum 1 player required)
- Node.js and npm installed
- Solana CLI configured
- Anchor framework installed
- Wallet with GOR tokens on the GOR network
git clone https://github.com/codewithmide/gor-race
cd gor-race
npm install
# Set your Solana cluster
export ANCHOR_PROVIDER_URL="https://rpc.gorbagana.wtf"
export ANCHOR_WALLET="~/.config/solana/id.json"
# Build the program
npm run build
# Deploy to GOR network
npm run deploy
# Initialize the platform (one-time setup)
npm run initialize
Create a player profile with a username for leaderboard tracking.
# Create profile with username
npm run create-profile HorseRacer123
npm run create-profile CryptoJockey
npm run create-profile SpeedDemon
Requirements:
- Username must be unique per wallet
- Max 32 characters
- Only letters, numbers, underscore (_), dash (-), and dot (.) allowed
- Cannot be empty
Output:
- Profile creation confirmation
- Profile details display
- Next steps guidance
View your own profile or another player's profile.
# View your own profile
npm run profile
# View another player's profile by wallet address
npm run profile <PLAYER_WALLET_ADDRESS>
Output:
- Username and basic info
- Race statistics (races, wins, podiums, earnings)
- Performance metrics (win rate, podium rate)
- Achievements and rankings
- Comparison with other players
View the leaderboard with various sorting options.
# Default leaderboard (sorted by score, top 10)
npm run leaderboard
# Sort by different metrics
npm run leaderboard wins # Sort by total wins
npm run leaderboard races # Sort by total races
npm run leaderboard earnings # Sort by total earnings
npm run leaderboard winrate # Sort by win percentage
npm run leaderboard podiums # Sort by podium finishes
# Specify number of players to show
npm run leaderboard score 20 # Top 20 by score
npm run leaderboard wins 5 # Top 5 by wins
Sorting Options:
score
(default): Weighted ranking considering wins, podiums, and consistencywins
: Total number of 1st place finishesraces
: Total number of races participatedearnings
: Total GOR earned from prizeswinrate
: Win percentage (wins/races)podiums
: Total podium finishes (1st, 2nd, 3rd)
Output:
- Ranked list of players with statistics
- Performance metrics for each player
- Total player counts and activity stats
Update your player statistics after completing a race.
# Update stats using referral code
npm run update-stats XYVSYS00
# Update stats using race ID
npm run update-stats 1751510633
Requirements:
- Must have participated in the race
- Race must be completed
- Player profile must exist
Output:
- Race results display
- Statistics update confirmation
- Updated player statistics
Create a new horse race with configurable wait time.
# Create race with default wait time (60 seconds)
npm run create-race
# Create race with custom wait time (30-180 seconds)
npm run create-race 90
npm run create-race 120
npm run create-race 180
Output:
- Race ID and PDAs
- Unique 8-character referral code (e.g.,
XYVSYS00
) - Race details (horses, timing, max players)
Parameters:
wait_time
(optional): 30-180 seconds, defaults to 60
Join an existing race using its referral code.
# Join race with referral code, select horse 1-10
npm run join-race XYVSYS00 3
npm run join-race R3ZSYS00 7
# Default to horse 1 if not specified
npm run join-race XYVSYS00
Requirements:
- Valid referral code (8 characters)
- Horse number 1-10
- 0.1 GOR entry fee
- Race must be in
Pending
status - Race must not be full (max 100 players)
Output:
- Confirmation of race joining
- Selected horse information
- Updated race statistics
Execute race transitions - from joining to racing, and from racing to completed.
# Execute using referral code
npm run execute-race XYVSYS00
# Execute using race ID
npm run execute-race 1751510633
Two-Phase Execution:
Phase 1: Start Race Simulation
- Triggered when wait time expires + minimum 1 player joined
- Changes status from
Pending
โRacing
- Begins 60-second race simulation
Phase 2: Complete Race
- Triggered after 60-second simulation completes
- Changes status from
Racing
โCompleted
- Determines winners and distributes prizes
Output:
- Race status updates
- Timing information
- Winner announcements (in Phase 2)
Claim winnings after race completion.
# Claim using referral code
npm run claim-prize XYVSYS00
# Claim using race ID
npm run claim-prize 1751510633
Requirements:
- Race must be completed
- Player must have participated in the race
- Player's horse must have won (1st, 2nd, or 3rd place)
- Prize not already claimed
Prize Distribution:
- ๐ฅ 1st Place: 50% of total pool
- ๐ฅ 2nd Place: 30% of total pool
- ๐ฅ 3rd Place: 15% of total pool
- Platform Fee: 5% of total pool
Output for Winners:
- Race results display
- Prize amount
- Transaction confirmation
- Updated GOR balance
Output for Non-Winners:
- Race results with all horses
- Encouraging message
- Tips for future races
# Player Management
npm run create-profile <USERNAME> # Create player profile
npm run profile [PLAYER_ADDRESS] # View profile
npm run leaderboard [SORT] [LIMIT] # View leaderboard
npm run update-stats <RACE_REF> # Update race statistics
# Race Management
npm run create-race [WAIT_TIME] # Create new race
npm run join-race <CODE> [HORSE] # Join race
npm run execute-race <RACE_REF> # Execute race
npm run claim-prize <RACE_REF> # Claim winnings
# Development
npm run build # Build program
npm run deploy # Deploy program
npm run initialize # Initialize platform (one-time)
npm run clean # Clean build artifacts
npm run test # Run tests
npm run lint # Lint code
gor-race/
โโโ programs/
โ โโโ gor-race/
โ โโโ src/
โ โ โโโ lib.rs
โ โ โโโ state/
โ โ โ โโโ mod.rs
โ โ โ โโโ race.rs
โ โ โ โโโ player_entry.rs
โ โ โ โโโ platform_vault.rs
โ โ โโโ instructions/
โ โ โ โโโ mod.rs
โ โ โ โโโ initialize.rs
โ โ โ โโโ create_race.rs
โ โ โ โโโ join_race.rs
โ โ โ โโโ execute_race.rs
โ โ โ โโโ claim_prize.rs
โ โ โโโ errors/
โ โ โ โโโ mod.rs
โ โ โโโ constants/
โ โ โ โโโ mod.rs
โ โ โโโ utils/
โ โ โโโ mod.rs
โ โ โโโ random.rs
โ โโโ Cargo.toml
โ โโโ Xargo.toml
โโโ tests/
โ โโโ gor-race.ts
โโโ migrations/
โ โโโ deploy.ts
โโโ Anchor.toml
โโโ Cargo.toml
โโโ package.json
โโโ tsconfig.json
โโโ README.md
- PlatformVault: Stores platform configuration and fee collection
- Race: Stores race state, participants, and results
- PlayerEntry: Individual player's race entry with stats tracking
- PlayerProfile: Player's username and statistics for leaderboard
- TokenVault: Holds race entry fees until distribution
The leaderboard uses a weighted scoring system that considers multiple factors:
Base Score Calculation:
- ๐ฅ Wins: 10 points each
- ๐ Podium finishes: 3 points each
- ๐ฏ Race participation: 1 point each
- ๐ฐ Earnings: 1 point per GOR earned
Consistency Bonus: Players with 10+ races get additional multipliers based on win rate:
- 30%+ win rate: 1.5x multiplier
- 20%+ win rate: 1.3x multiplier
- 10%+ win rate: 1.1x multiplier
This rewards both high performance and consistent participation.
[features]
seeds = false
skip-lint = false
[programs.localnet]
gor_race = "YOUR_PROGRAM_ID"
[programs.testnet]
gor_race = "YOUR_PROGRAM_ID"
[registry]
url = "https://api.apr.dev"
[provider]
cluster = "https://rpc.gorbagana.wtf"
wallet = "~/.config/solana/gor-race.json"
[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
# Set program keypair
anchor keys sync
# Deploy to Gorbagana testnet
anchor deploy --provider.cluster https://rpc.gorbagana.wtf
# Note the deployed program ID
# Run initialization script
anchor run initialize
await program.methods
.initialize(platformFeeBps)
.accounts({
platformVault: platformVaultPda,
authority: authority.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([authority])
.rpc();
await program.methods
.createRace()
.accounts({
race: racePda,
creator: creator.publicKey,
systemProgram: SystemProgram.programId,
clock: SYSVAR_CLOCK_PUBKEY,
})
.signers([creator])
.rpc();
await program.methods
.joinRace(horseNumber)
.accounts({
race: racePda,
playerEntry: playerEntryPda,
player: player.publicKey,
playerTokenAccount: playerTokenAccount,
raceTokenVault: raceTokenVault,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
})
.signers([player])
.rpc();
await program.methods
.executeRace()
.accounts({
race: racePda,
randomnessOracle: randomnessOracle,
clock: SYSVAR_CLOCK_PUBKEY,
})
.rpc();
await program.methods
.claimPrize()
.accounts({
race: racePda,
playerEntry: playerEntryPda,
player: player.publicKey,
playerTokenAccount: playerTokenAccount,
raceTokenVault: raceTokenVault,
platformVault: platformVaultPda,
platformTokenAccount: platformTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([player])
.rpc();
anchor test --provider.cluster https://rpc.gorbagana.wtf
anchor test --provider.cluster https://rpc.gorbagana.wtf -- --grep "should create race"
- Randomness: Uses on-chain randomness combining slot hashes and timestamps
- Reentrancy Protection: State transitions prevent double claims
- Authority Checks: Only authority can modify platform settings
- Overflow Protection: Uses checked math operations
- Time-based Execution: Races auto-execute after timeout
The program randomly selects 10 horses from this pool for each race:
- Bonk, Samo, Orca, Raydium, Marinade
- Serum, Mango, Drift, Jupiter, Phantom
- Solend, Saber, Mercurial, Tulip, Francium
- Port, Oxygen, Bonfida, Step, Grape
- Sunny, Quarry, Aldrin, Cyclos, Lifinity
- Hubble, Kamino, Marginfi, Cypher, Zeta
-
Insufficient GOR tokens
- Ensure you have enough GOR for transactions and rent
- Request from Gorbagana faucet
-
Program deployment fails
- Check wallet balance
- Verify RPC endpoint is correct
- Ensure program size is within limits
-
Transaction fails
- Check account ownership
- Verify PDA derivation
- Ensure proper token accounts exist
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature
) - Commit changes (
git commit -m 'Add amazing feature'
) - Push to branch (
git push origin feature/amazing-feature
) - Open Pull Request