Publicación
Comparte tu conocimiento.
Creación de una dApp de lotería NFT de próxima generación con Sui Move y una interfaz de usuario moderna
🧩 Creación de una dApp de lotería NFT de próxima generación con Sui Move y una interfaz de usuario moderna
Esta es tu guía definitiva para crear una dApp de lotería gamificada e impulsada por NFT utilizandoSui Move, con soporte para múltiples rondas, sistemas de recomendación, gobernanza de DAO y un sistema de diseño que encantará a la generación Z. Desde la arquitectura de contratos hasta el flujo de la interfaz de usuario, hagamos todo lo posible.
📦 Desglose de fases
Fase 1: Lotería básica
- Juego de varias rondas
- Venta de entradas en NFT
- Sistema de recompensas por recomendación
- Votación DAO básica
Fase 2: Mercado y gamificación
- Integración con el mercado de NFT
- Potenciadores (aumentan las posibilidades de ganar)
- Sistema de premios
- Lanzamientos aéreos ocultos
Fase 3: DAO y multicadena
- Compatibilidad entre cadenas
- DAO con propuestas avanzadas
- Precios dinámicos
- Análisis en cadena
🧠 Smart Contract profundiza en Sui Move
Estructura del contrato
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
}
}
Conclusiones clave:
- ✅
Balance<FAUCET_COIN>
garantiza la seguridad tipográfica y el manejo adecuado de las monedas - ✅
Option<u32>
indica claramente si se ha elegido un ganador - ✅ Los eventos ofrecen trazabilidad para usuarios finales y exploradores
🛠 Comandos de CLI Sui
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
Para comprar un boleto, determinar el ganador o reclamar una recompensa, siga flujos de CLI similares.
🔮 Futuras incorporaciones
- Restablecimiento automático de la lógica para la próxima ronda
claim_reward
- Emite más eventos como
ReferralRewardDistributed
- Refactoriza los premios mayores y las referencias en submódulos
¡Avísame si quieres una parte 2 para crear una interfaz de usuario e integrarla en la red de pruebas de Sui!
- Sui
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.