Sui.

Publication

Partagez vos connaissances.

article banner.
harry phan.
Apr 10, 2025
Article

Création d'une application de loterie NFT de nouvelle génération avec Sui Move et une interface utilisateur moderne

🧩 Création d'une application de loterie NFT de nouvelle génération avec Sui Move et une interface utilisateur moderne

Il s'agit de votre guide ultime pour créer une application de loterie gamifiée alimentée par NFT à l'aide deSui Move, avec un support multi-tours, des systèmes de parrainage, une gouvernance DAO et un système de conception que la génération Z adorera. De l'architecture des contrats au flux de l'interface utilisateur, allons-y.


📦 Répartition des phases

Phase 1 — Loterie de base

  • Gameplay à plusieurs tours
  • Billetterie NFT
  • Système de récompenses de parrainage
  • Vote DAO de base

Phase 2 — Marché et gamification

  • Intégration de la place de marché NFT
  • Boosters (augmente les chances de gagner)
  • Système Jackpot
  • Des parachutages cachés

Phase 3 — DAO et multichaînes

  • Compatibilité inter-chaînes
  • DAO avec propositions avancées
  • Tarification dynamique
  • Analyses en chaîne

🧠 Smart Contract : approfondissement de Sui Move

Structure du contrat

module nft_lottery_x::nft_lottery_x {
    use sui::object;
    use sui::balance::{Balance, zero};
    use sui::coin::{Self, Coin};
    use sui::clock::Clock;
    use sui::random::Random;
    use sui::event::emit;
    use sui::transfer;
    use sui::tx_context::TxContext;
    use std::option;
    use std::signer;

    const EGameNotStarted: u64 = 1000;
    const EGameAlreadyFinished: u64 = 1001;
    const EInvalidPayment: u64 = 1002;
    const ENoTickets: u64 = 1003;
    const EWinnerAlreadyChosen: u64 = 1004;
    const ENotWinner: u64 = 1005;

    public struct Game has key {
        id: UID,
        ticket_price: u64,
        start_time: u64,
        end_time: u64,
        total_tickets: u32,
        round: u32,
        winner: Option<u32>,
        balance: Balance<FAUCET_COIN>,
        referral_bonus: u64,
    }

    public struct Ticket has key {
        id: UID,
        game_id: ID,
        ticket_number: u32,
        buyer: address,
        referrer: Option<address>,
    }

    public struct GameCreated has copy, drop {
        game_id: ID,
        start_time: u64,
        end_time: u64,
        ticket_price: u64,
    }

    public struct TicketBought has copy, drop {
        game_id: ID,
        ticket_number: u32,
        buyer: address,
        referrer: Option<address>,
    }

    public struct WinnerAnnounced has copy, drop {
        game_id: ID,
        winner_ticket: u32,
        round: u32,
    }

    public struct RewardClaimed has copy, drop {
        game_id: ID,
        ticket_number: u32,
        amount: u64,
    }

    public fun create_game(
        start_time: u64,
        end_time: u64,
        ticket_price: u64,
        referral_bonus: u64,
        ctx: &mut TxContext
    ) {
        let game = Game {
            id: object::new(ctx),
            ticket_price,
            start_time,
            end_time,
            total_tickets: 0,
            round: 1,
            winner: option::none(),
            balance: zero(),
            referral_bonus,
        };

        emit<GameCreated>(GameCreated {
            game_id: object::id(&game),
            start_time,
            end_time,
            ticket_price,
        });

        transfer::share_object(game);
    }

    public fun buy_ticket(
        game: &mut Game,
        coin: Coin<FAUCET_COIN>,
        clock: &Clock,
        referrer: Option<address>,
        ctx: &mut TxContext
    ): Ticket {
        assert!(clock.timestamp_ms() >= game.start_time, EGameNotStarted);
        assert!(clock.timestamp_ms() < game.end_time, EGameAlreadyFinished);
        assert!(coin.value() == game.ticket_price, EInvalidPayment);

        game.total_tickets = game.total_tickets + 1;
        coin::put(&mut game.balance, coin);

        let ticket = Ticket {
            id: object::new(ctx),
            game_id: object::id(game),
            ticket_number: game.total_tickets,
            buyer: signer::address_of(ctx.sender()),
            referrer,
        };

        emit<TicketBought>(TicketBought {
            game_id: object::id(game),
            ticket_number: ticket.ticket_number,
            buyer: ticket.buyer,
            referrer: ticket.referrer,
        });

        ticket
    }

    public entry fun determine_winner(
        game: &mut Game,
        rand: &Random,
        clock: &Clock,
        ctx: &mut TxContext
    ) {
        assert!(clock.timestamp_ms() >= game.end_time, EGameNotStarted);
        assert!(game.winner.is_none(), EWinnerAlreadyChosen);
        assert!(game.total_tickets > 0, ENoTickets);

        let mut generator = rand.new_generator(ctx);
        let winning_ticket = generator.generate_u32_in_range(1, game.total_tickets);
        game.winner = option::some(winning_ticket);

        emit<WinnerAnnounced>(WinnerAnnounced {
            game_id: object::id(game),
            winner_ticket: winning_ticket,
            round: game.round,
        });
    }

    public fun claim_reward(
        ticket: Ticket,
        game: Game,
        ctx: &mut TxContext
    ): Coin<FAUCET_COIN> {
        assert!(object::id(&game) == ticket.game_id, EInvalidPayment);
        let ticket_num = ticket.ticket_number;
        assert!(game.winner.contains(&ticket_num), ENotWinner);

        let amount = game.balance.value();
        let reward = game.balance.into_coin(ctx);

        emit<RewardClaimed>(RewardClaimed {
            game_id: object::id(&game),
            ticket_number: ticket.ticket_number,
            amount,
        });

        object::delete(object::id(&game));

        reward
    }
}

Principaux points à retenir :

  • Balance<FAUCET_COIN>garantit la sécurité des caractères et une manipulation correcte des pièces
  • Option<u32>indique clairement si un gagnant a été choisi
  • ✅ Les événements offrent une traçabilité pour les frontends et les explorateurs

🛠 Commandes Sui CLI

sui client call   --package <PACKAGE_ID>   --module nft_lottery_x   --function create_game   --args <START_TIME> <END_TIME> <TICKET_PRICE> <REFERRAL_BONUS>   --gas-budget 10000000

Pour acheter un billet, déterminer le gagnant ou réclamer une récompense, suivez des flux CLI similaires.


🔮 Ajouts futurs

  • Logique de réinitialisation automatique pour le prochain round claim_reward
  • Émettez plus d'événements tels que ReferralRewardDistributed
  • Refactorisez les jackpots et les références dans des sous-modules

Faites-moi savoir si vous voulez une partie 2 pour créer une interface utilisateur et l'intégrer sur Sui testnet !

  • Sui
3
Partager
Commentaires
.
Nous utilisons des cookies pour vous assurer la meilleure expérience sur notre site Web.
Plus d'infos