Cooperative on-chain boss raid game built on OneChain ยท OneHack 3.0 submission
Players pick a role (Knight / Mage / Assassin), attack a global monster once per cooldown, and earn proportional token rewards when the boss dies. The player who lands the final blow gets a 1.5ร bonus. Every attack has a 15% chance to drop a weapon NFT.
raid-the-chain/
โโโ contract/ # Move smart contract
โ โโโ Move.toml
โ โโโ sources/
โ โโโ raid.move # Core game logic
โโโ frontend/ # Next.js app
โ โโโ src/
โ โ โโโ app/ # Next.js App Router
โ โ โโโ components/ # UI components
โ โ โโโ hooks/ # useGameState hook
โ โ โโโ lib/ # onechain.ts, config.ts
โ โโโ .env.example
โ โโโ package.json
โโโ deploy.sh # One-command deploy script
Install these before anything else:
| Tool | Version | Install |
|---|---|---|
| Node.js | โฅ 18 | https://nodejs.org |
one CLI |
latest | https://docs.onelabs.cc |
| Git | any | https://git-scm.com |
# The one CLI is OneChain's fork of the sui CLI
# Install from OneChain docs or via cargo:
cargo install --git https://github.com/one-chain-labs/onechain one --bin one
# Verify
one --version# If you cloned from GitHub:
git clone https://github.com/YOUR_USERNAME/raid-the-chain.git
cd raid-the-chain
# Or just navigate to the project folder:
cd raid-the-chain# Create a new wallet address
one client new-address ed25519
# Check your address
one client active-address
# Switch to testnet
one client switch --env testnet
# If testnet isn't configured yet, add it:
one client new-env --alias testnet --rpc https://rpc-testnet.onelabs.cc:443
# Get testnet tokens from faucet
one client faucet --url https://faucet-testnet.onelabs.cc/gas
# Check balance
one client balancecd contract
# Build (checks for errors)
one move build
# Optional: run tests
one move testExpected output:
BUILDING raid_the_chain
Build Successful
# From the project root:
cd ..
chmod +x deploy.sh
./deploy.shThe script will:
- Build the contract
- Publish to testnet
- Extract Package ID and GameState ID
- Spawn the first monster ("The Shadow Dragon", 10,000 HP)
- Write your
frontend/.env.localautomatically
cd contract
# Publish
one client publish \
--network testnet \
--gas-budget 100000000
# Note the output โ you'll see something like:
# ----- Transaction Effects ----
# Created Objects:
# ID: 0xABC... (Package โ Immutable)
# ID: 0xDEF... (GameState โ Shared)
# ID: 0x123... (AdminCap โ Owned by you)Then spawn a monster:
one client call \
--package <PACKAGE_ID> \
--module raid \
--function spawn_monster \
--args \
<ADMIN_CAP_ID> \
<GAME_STATE_ID> \
'"The Shadow Dragon"' \
10000 \
0 \
0x6 \
--gas-budget 50000000The output will contain a new Shared object โ that's your Monster ID.
Then create frontend/.env.local:
NEXT_PUBLIC_PACKAGE_ID=0xYOUR_PACKAGE_ID
NEXT_PUBLIC_GAME_STATE_ID=0xYOUR_GAME_STATE_ID
NEXT_PUBLIC_MONSTER_ID=0xYOUR_MONSTER_IDcd frontend
# Install dependencies
npm install
# Start dev server
npm run devOpen http://localhost:3000 ๐
- Connect your OneWallet
- Pick a role โ permanent choice:
- ๐ก๏ธ Knight โ 10 DMG, 2h cooldown (attacks ~12ร/day)
- ๐ฎ Mage โ 25 DMG, 6h cooldown (attacks ~4ร/day)
- ๐ก๏ธ Assassin โ 50 DMG, 12h cooldown (attacks ~2ร/day)
- Attack the boss when your cooldown expires
- Watch the HP bar drain as the community raids together
- Land the final blow for a 1.5ร reward bonus
- Collect rewards proportional to your damage contribution
- Loot chance: every attack has 15% chance to drop a weapon NFT
| Reward | Who gets it |
|---|---|
| 80% of pool | All contributors, proportional to damage |
| 20% of pool | Top 10 damage dealers, split equally |
| 1.5ร multiplier | Final blow player (on their proportional share) |
| Weapon NFT | Random 15% drop on any attack |
| Tier | Name | Bonus |
|---|---|---|
| Common | Iron Sword | +5 DMG |
| Rare | Silver Blade | +15 DMG |
| Epic | Dragon Fang | +30 DMG |
| Product | Usage | File |
|---|---|---|
| OneWallet | Login + transaction signing for all game actions | Providers.tsx |
| OneTransfer | transfer::public_transfer distributes OCT rewards proportionally to every raider on monster death |
raid.move โ distribute_rewards() |
| OnePlay | Real-time on-chain leaderboard โ queries AttackLanded events directly from chain, aggregates damage per address, shows live rankings |
integrations.ts โ fetchOnePlayLeaderboard() |
| OneID | Resolves wallet addresses to human display names in leaderboard rows and the player stats bar. Falls back to short address if no profile. | integrations.ts โ resolveOneID() |
| OneDEX | Each weapon NFT in your inventory has a "List on OneDEX โ" button that deep-links to OneDEX pre-filled with the weapon object. Collection view link also shown. | integrations.ts โ buildListWeaponOnDEXLink() |
Spawn a new monster after one is defeated:
one client call \
--package <PACKAGE_ID> \
--module raid \
--function spawn_monster \
--args <ADMIN_CAP_ID> <GAME_STATE_ID> '"Boss Name"' <HP> 0 0x6 \
--gas-budget 50000000Mint a weapon for a player (for testing):
one client call \
--package <PACKAGE_ID> \
--module raid \
--function craft_weapon \
--args <ADMIN_CAP_ID> <RECIPIENT_ADDRESS> 3 \
--gas-budget 20000000
# tier: 1=Common, 2=Rare, 3=Epic- Explorer: https://onescan.cc/testnet
- Faucet: https://faucet-testnet.onelabs.cc/gas
- RPC: https://rpc-testnet.onelabs.cc:443
cd frontend
npm run build
npm startone: command not found
โ Install the one CLI from OneChain docs.
E_ALREADY_REGISTERED error
โ Your wallet is already registered. Just play!
E_COOLDOWN_ACTIVE error
โ Your attack cooldown hasn't expired. Check the timer in the UI.
Blank frontend / "no monster"
โ Double-check your .env.local IDs. Run one client object <MONSTER_ID> to verify the object exists.
Transaction fails with "insufficient gas"
โ Get more testnet tokens: one client faucet --url https://faucet-testnet.onelabs.cc/gas
Built with โค๏ธ for OneHack 3.0 on OneChain