Publication
Partagez vos connaissances.
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
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
204Publications300Réponses
Publications tendance
- How to access and manage nested structs and dynamic fields in Move?56
- Comment convertir une clé privée en un nouveau format via la CLI43
- 👀 SEAL- Je pense que la confidentialité des données Web3 est sur le point de changer4
- Sui memes DEX options and chart44
- How to update coin logo on Sui smart contract?32