How to Create a Spin-the-Wheel Smart Contract on Sui Blockchain Using Move | by Ryan Adhitama Putra | January 2025
In this tutorial, we will learn how to create a “Spin the Wheel” gaming smart contract using the Move programming language on the Sui blockchain. Players spin a wheel with customizable segments and win multipliers. The outcome is determined randomly and an event records the outcome of the player’s turn.
This game allows players to:
- Set the number of segments on the wheel (4 to 20).
- Assign payout multipliers to each segment.
- Spin the wheel and receive a multiplier based on the segment you landed on.
You will implement the following:
- A Move smart contract for game logic.
- A rotation mechanism based on chance.
- Events to record spin results.
Before you start coding, make sure you have the following setup:
- About CLIs: Mandatory for contract deployment. Install your CLI.
- Code editor: A good editor like VS Code or IntelliJ with the Move plugin.
Run the following command to create a new Sui Move project:
sui move new spinwheel
This will create a directory named spinwheel
with the following structure:
spinwheel/
├── Move.lock
├── Move.toml
├── sources/
│ └── spinwheel.move
└── tests/
└── spinwheel_tests.move
Go to the project directory
cd spinwheel
Replace the contents of sources/spinwheel.move
with your module code (explained in the following steps).
module spinwheel::spinwheel;
THE spinwheel::spinwheel
The module defines a smart contract for a Spin The Wheel game built on the Sui blockchain using the Move programming language.
use sui::{
random::Random,
event,
};
random::Random
: Provides functionality for generating random numbers.event
: Used to emit events that record game results for transparency.
public struct SpinResult has copy, drop, store {
player: address,
spin_result: u64, // The segment number landed on
multiplier: u64, // Payout multiplier for the segment
}
player
: The address of the player who spun the wheel.spin_result
: The number of the segment where the wheel stopped.multiplier
: The payout multiplier for the landed segment.
const INVALID_SEGMENTS: u64 = 1;
const MIN_SEGMENTS: u8 = 4; // Minimum number of segments on the wheel
const MAX_SEGMENTS: u8 = 20; // Maximum number of segments on the wheel
INVALID_SEGMENTS
: Error code used when the number of segments is invalid.MIN_SEGMENTS
: Minimum authorized number of segments (4).MAX_SEGMENTS
: Maximum authorized number of segments (20).
entry fun spin(
num_segments: u8,
multipliers: vector<u64>,
random: &Random,
ctx: &mut TxContext
) {
// Validate the number of segments
assert!(num_segments >= MIN_SEGMENTS && num_segments <= MAX_SEGMENTS, INVALID_SEGMENTS);// Ensure multipliers length matches the number of segments
assert!(vector::length(&multipliers) == num_segments as u64, 1);
// Generate the spin result (random segment index)
let spin_result = generate_spin_result(num_segments, random, ctx);
// Determine the multiplier for the segment landed on
let multiplier = multipliers[spin_result as u64];
// Emit the result as an event
let player = ctx.sender();
event::emit(SpinResult {
player,
spin_result,
multiplier,
});
}
- Valid that
num_segments
is within the permitted range (4–20). - Check that the
multipliers
the vector has the correct length to match the number of segments. - Generates a random spin result and determines the corresponding multiplier.
- Issues a
SpinResult
event with game details.
fun generate_spin_result(num_segments: u8, random: &Random, ctx: &mut TxContext): u64 {
let mut gen = random.new_generator(ctx);
let random_number = gen.generate_u64();
let segment = random_number % (num_segments as u64); // Cast num_segments to u64segment
}
- Uses chance to generate a number between
0
Andnum_segments - 1
. - Ensures compatibility by casting
num_segments
of the same type as the random number (u64
).
module spinwheel::spinwheel;use sui::{
random::Random,
event,
};
/// Struct to store the result of a spin
public struct SpinResult has copy, drop, store {
player: address,
spin_result: u64, // The segment number landed on
multiplier: u64, // Payout multiplier for the segment
}
// === Constants ===
const INVALID_SEGMENTS: u64 = 1;
const MIN_SEGMENTS: u8 = 4; // Minimum number of segments on the wheel
const MAX_SEGMENTS: u8 = 20; // Maximum number of segments on the wheel
// === Public-Mutative Functions ===
/// Spin the wheel and calculate the result
entry fun spin(
num_segments: u8,
multipliers: vector<u64>,
random: &Random,
ctx: &mut TxContext
) {
// Validate the number of segments
assert!(num_segments >= MIN_SEGMENTS && num_segments <= MAX_SEGMENTS, INVALID_SEGMENTS);
// Ensure multipliers length matches the number of segments
assert!(vector::length(&multipliers) == num_segments as u64, 1);
// Generate the spin result (random segment index)
let spin_result = generate_spin_result(num_segments, random, ctx);
// Determine the multiplier for the segment landed on
let multiplier = multipliers[spin_result as u64];
// Emit the result as an event
let player = ctx.sender();
event::emit(SpinResult {
player,
spin_result,
multiplier,
});
}
// === Private Functions ===
/// Generate a random spin result (segment index between 0 and `num_segments - 1`)
fun generate_spin_result(num_segments: u8, random: &Random, ctx: &mut TxContext): u64 {
let mut gen = random.new_generator(ctx);
// Generate a random number and calculate the segment index
let random_number = gen.generate_u64();
let segment = random_number % (num_segments as u64); // Cast num_segments to u64
segment
}
Follow these steps to deploy your spinwheel
module:
Compile the contract
Navigate to the project directory and run:
sui move build
Publish the contract
Use the Sui CLI to publish the module:
sui client publish --gas-budget 100000000
Package deployed
Call him spin
work with the following command:
sui client call \
--package <PackageId> \
--module spinwheel \
--function spin \
--args <num_segments> '[<multiplier1>, <multiplier2>, ...]' <Random_ObjectId> \
--gas-budget 10000000
- Replace
<PackageId>
with the ID of your deployedspinwheel
module. - Replace
<num_segments>
with the number of segments (4–20). - Replace the multiplier table with values corresponding to the number of segments.
- Replace
<Random_ObjectId>
with the identifier ofRandom
object in your environment.
Example
sui client call \
--package '0x42f79866f445dcef3d65439b9f87442beebabf0f7032a74553daa1d74024b901' \
--module spinwheel \
--function spin \
--args 6 '[0,1,2,1,3,0]' '0x0000000000000000000000000000000000000000000000000000000000000008' \
--gas-budget 10000000
Before leaving: