UNPKG

eatthepie

Version:

Command line app for interacting with Eat The Pie, the world lottery on World Chain.

255 lines (227 loc) • 7.22 kB
import chalk from "chalk"; import inquirer from "inquirer"; import { formatEther } from "viem"; import { buyTickets, getTicketPrice, getCurrentGameInfo, } from "../services/gameService.js"; import { loadConfig } from "../utils/config.js"; import { createPublicClient, createWalletClient } from "../utils/ethereum.js"; import { generateRandomTicket, getDifficultyLimits } from "../utils/helpers.js"; import { formatDifficulty } from "../utils/display.js"; /** * Handles the ticket buying process for the lottery game. * This includes fetching game info, getting user input for tickets, * and executing the purchase transaction. */ async function buyHandler() { try { // Initialize clients and load configuration const config = await loadConfig(); const publicClient = createPublicClient(config); const walletClient = createWalletClient(config); // Fetch current game state const ticketPrice = await getTicketPrice( publicClient, config.contractAddress ); const gameInfo = await getCurrentGameInfo( publicClient, config.contractAddress ); const limits = getDifficultyLimits(gameInfo.difficulty); // Display current game information displayGameInfo(ticketPrice, gameInfo.difficulty, limits); // Get ticket count from user const ticketCount = await getTicketCount(); // Get ticket numbers (manual or auto-generated) const tickets = await getTicketNumbers(ticketCount, limits); // Calculate and display purchase summary const totalPrice = ticketPrice * BigInt(ticketCount); displayPurchaseSummary(tickets, totalPrice); // Confirm and process purchase await confirmAndProcessPurchase( config.network, walletClient, publicClient, config.contractAddress, tickets, totalPrice ); } catch (error) { console.error( chalk.red("\nāŒ Error:"), error.shortMessage || error.message ); console.error( chalk.red( "\nāš ļø Make sure your settings are correct.\nšŸ”§ Run 'config' to view them and 'setup' to reset them." ) ); process.exit(1); } } /** * Displays current game information including ticket price and difficulty */ function displayGameInfo(ticketPrice, difficulty, limits) { console.log( chalk.cyan(`šŸ’° Current ticket price: ${formatEther(ticketPrice)} WLD`) ); console.log( chalk.cyan(`šŸŽÆ Current difficulty: ${formatDifficulty(difficulty)}`) ); console.log( chalk.cyan( `šŸ”¢ Valid number range: 1-${limits.max}, 🌟 Etherball: 1-${limits.etherballMax}` ) ); } /** * Prompts user for the number of tickets they want to buy * @returns {Promise<number>} Number of tickets to purchase */ async function getTicketCount() { const { ticketCount } = await inquirer.prompt([ { type: "number", name: "ticketCount", message: "šŸŽŸļø How many tickets do you want to buy? (1-100)", validate: (input) => input >= 1 && input <= 100, }, ]); return ticketCount; } /** * Gets ticket numbers either through manual input or auto-generation * @param {number} ticketCount - Number of tickets to generate/input * @param {Object} limits - Number range limits based on difficulty * @returns {Promise<number[][]>} Array of ticket numbers */ async function getTicketNumbers(ticketCount, limits) { const { choiceMethod } = await inquirer.prompt([ { type: "list", name: "choiceMethod", message: "✨ Do you want to provide your own numbers or auto-generate?", choices: ["šŸŽÆ Provide own", "šŸŽ² Auto-generate"], }, ]); if (choiceMethod === "šŸŽÆ Provide own") { return await getManualTickets(ticketCount, limits); } const uniqueTickets = new Set(); const tickets = []; while (tickets.length < ticketCount) { const newTicket = generateRandomTicket(limits); const ticketKey = newTicket.join(","); if (!uniqueTickets.has(ticketKey)) { uniqueTickets.add(ticketKey); tickets.push(newTicket); } } return tickets; } /** * Prompts user for manual input of ticket numbers * @param {number} ticketCount - Number of tickets to input * @param {Object} limits - Number range limits * @returns {Promise<number[][]>} Array of ticket numbers */ async function getManualTickets(ticketCount, limits) { const tickets = []; for (let i = 0; i < ticketCount; i++) { const { numbers } = await inquirer.prompt([ { type: "input", name: "numbers", message: `šŸŽÆ Enter 4 numbers for ticket ${ i + 1 } (comma-separated, last is Etherball):`, validate: (input) => validateTicketNumbers(input, limits), }, ]); tickets.push(numbers.split(",").map(Number)); } return tickets; } /** * Validates user-input ticket numbers * @param {string} input - Comma-separated numbers * @param {Object} limits - Number range limits * @returns {boolean} Whether the input is valid */ function validateTicketNumbers(input, limits) { const nums = input.split(",").map(Number); return ( nums.length === 4 && nums.slice(0, 3).every((n) => n >= 1 && n <= limits.max) && nums[3] >= 1 && nums[3] <= limits.etherballMax ); } /** * Displays purchase summary including all tickets and total cost */ function displayPurchaseSummary(tickets, totalPrice) { console.log(chalk.yellow("šŸŽ« Tickets to purchase:")); tickets.forEach((ticket, index) => { console.log(chalk.cyan(`šŸŽŸļø Ticket ${index + 1}:`), ticket.join(", ")); }); console.log(chalk.cyan(`šŸ’° Total cost: ${formatEther(totalPrice)} WLD`)); } /** * Confirms purchase with user and processes the transaction */ async function confirmAndProcessPurchase( network, walletClient, publicClient, contractAddress, tickets, totalPrice ) { const { confirm } = await inquirer.prompt([ { type: "confirm", name: "confirm", message: "šŸ’« Do you want to proceed with the purchase?", }, ]); if (confirm) { const txHash = await buyTickets( network, walletClient, publicClient, contractAddress, tickets, totalPrice ); console.log(chalk.yellow("\nšŸ“ Transaction Hash:"), txHash); console.log(chalk.green("šŸš€ Purchase submitted!")); // Wait for transaction confirmation await waitForTransactionConfirmation(publicClient, txHash); } else { console.log(chalk.yellow("āŒ Purchase cancelled.")); } } /** * Waits for a transaction to be confirmed and displays the confirmation * @param {PublicClient} publicClient - The public client instance * @param {string} txHash - The transaction hash to wait for */ async function waitForTransactionConfirmation(publicClient, txHash) { console.log(chalk.yellow("\nā³ Waiting for transaction to be confirmed...")); const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, confirmations: 1, }); console.log(chalk.cyan("šŸ“¦ Block Number:"), receipt.blockNumber); console.log(chalk.green("\nāœ… Transaction confirmed successfully!")); } export default { command: "buy", describe: "šŸŽŸļø Buy tickets", handler: buyHandler, };