Sui.

Post

Share your knowledge.

article banner.
0xduckmove.
Mar 07, 2025
Article

Developing a Dice Game Contract in Sui Move

In this tutorial, I’ll guide you through the process of creating a dice game smart contract using Sui Move.

This contract enables players to bet on the outcome of a dice roll, with an admin managing the prize pool. By the end, you'll have a fully functional contract and a solid understanding of several key Sui Move concepts.

Introduction

The dice game contract we'll build allows for the following functionalities:

  • Initialization: The contract creator sets up the game.
  • Admin Management: An admin can deposit tokens into the prize pool and withdraw them as needed.
  • Player Interaction: Players participate by guessing the dice roll outcome and placing bets.

This tutorial assumes you have a basic understanding of Sui Move and focuses on introducing new concepts through practical implementation. Before dive into the code, let’s explore the key concepts you’ll encounter:

1.1 Adding Dependencies:

To use tokens from another contract (e.g., a faucet token contract), you need to add it as a dependency in your project. This is done by updating the Move.toml file of your contract:

[dependencies]
coin_duck = { local = "../coin_duck"”}

Here, coin_duck is the faucet token contract located at the specified path. The depended contract must also specify its published-at field in its own Move.toml with the package ID obtained upon publication, like so: rust

published-at = "packageId_from_publication"

1.2 Using Assertions

Assertions ensure that certain conditions are met during contract execution. The assert! macro checks a condition and, if it fails, throws an error and halts execution. This is useful for preventing invalid states, such as betting more than a player’s balance.

1.3 Generating Random Numbers

Fairness in the dice game relies on random number generation. Sui Move provides the random module for this purpose. You’ll create a RandomGenerator object and use it to generate a random number between 1 and 6, simulating a dice roll.

1.4 Working with Coin and Balance

In Sui Move, tokens are managed using the coin and balance modules:

  • Coin: A wrapper around Balance, used for transferring tokens.

  • Balance: Represents the actual token amount, allowing operations like splitting and merging.

Key methods include:

  • coin::value(in_coin): Returns the total value of a Coin object.
  • coin::take(&mut balance, amount, ctx): Extracts a specified amount from a Balance to create a Coin.
  • in_coin.balance_mut().split(amount): Splits a specified amount from a Coin’s Balance.
  • balance.join(balance): Merges one Balance into another.

These operations will be used to manage the game’s prize pool and player bets.

The Dice Game Contract

Here’s the complete code for the dice game contract, followed by detailed explanations:

/// Game: Dice rolling. Players bet and guess the number. If correct, they win an amount equal to their bet; if incorrect, the bet goes to the game pool.

module game_duck:game_duck;

use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin};
use sui::random::{Random, new_generator, generate_u8_in_range};
use coin_duck::duckfaucet::DUCKFAUCET;

const ErrorUserInsufficient: u64 = 0x101;
const ErrorGameInsufficient: u64 = 0x102;

public struct Game has key {
    id: UID,
    pool_amount: Balance<DUCKFAUCET>,
}

public struct Admin has key {
    id: UID,
}

fun init(ctx: &mut TxContext) {
    let game = Game {
        id: object::new(ctx),
        pool_amount: balance::zero()
    };
    transfer::share_object(game);

    let admin = Admin { id: object::new(ctx) };
    transfer::transfer(admin, ctx.sender());
}

public entry fun addCoinToGamePool(game: &mut Game, in_coin: &mut Coin<DUCKFAUCET>, amount: u64, _: &mut TxContext) {
    let value = coin::value(in_coin);
    assert!(amount <= value, ErrorUserInsufficient);
    let coin_balance = in_coin.balance_mut().split(amount);
    game.pool_amount.join(coin_balance);
}

public entry fun removeCoinFromGamePool(_: &Admin, game: &mut Game, amount: u64, ctx: &mut TxContext) {
    assert!(game.pool_amount.value() >= amount, ErrorGameInsufficient);
    let coin = coin::take(&mut game.pool_amount, amount, ctx);
    transfer::public_transfer(coin, ctx.sender());
}

entry fun play(game: &mut Game, random: &Random, guess_num: u8, in_coin: &mut Coin<DUCKFAUCET>, amount: u64, ctx: &mut TxContext) {
    assert!(game.pool_amount.value() >= (amount * 3), ErrorGameInsufficient);
    assert!(in_coin.balance().value() >= amount, ErrorUserInsufficient);

    let mut g = new_generator(random, ctx);
    let win_num = generate_u8_in_range(&mut g, 1, 6);

    if (win_num == guess_num) {
        let reward_coin = coin::take(&mut game.pool_amount, amount, ctx);
        in_coin.join(reward_coin);
    } else {
        addCoinToGamePool(game, in_coin, amount, ctx);
    }
}

Code Breakdown structure

  • Game: A shared object with a unique id and a pool_amount (Balance) to store the prize pool.
  • Admin: A key object owned by the admin for Initialization (init)managing the pool.

Initialization (init):

  • Creates a Game object with an empty prize pool and shares it publicly.
  • Creates an Admin object and transfers it to the contract creator.

Adding to the Pool (addCoinToGamePool)

  • Takes a specified amount from the admin’s in_coin.
  • Uses assert! to ensure the coin has sufficient value.
  • Splits the amount from in_coin’s Balance and merges it into the game’s pool_amount.

Outcome:

  • Win: If the guess matches the roll, a reward equal to the bet is taken from the pool and merged into the player’s in_coin.
  • Lose: If incorrect, the bet is deducted from in_coin and added to the pool via addCoinToGamePool.
  • Sui
  • Move
3
Share
Comments
.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

268Posts383Answers
Sui.X.Peera.

Earn Your Share of 1000 Sui

Gain Reputation Points & Get Rewards for Helping the Sui Community Grow.

Reward CampaignMay
We use cookies to ensure you get the best experience on our website.
More info