eatthepie
Version:
Command line app for interacting with Eat The Pie, the world lottery on World Chain.
235 lines (209 loc) ⢠6.22 kB
JavaScript
import inquirer from "inquirer";
import chalk from "chalk";
import { loadConfig } from "../utils/config.js";
import { createPublicClient } from "../utils/ethereum.js";
import { getDetailedGameInfo } from "../services/gameService.js";
import { formatDifficulty } from "../utils/display.js";
import { formatEther } from "viem";
/**
* Game status mapping
*/
const GAME_STATUS = {
0: "š® In Play",
1: "š² Drawing",
2: "ā
Completed",
};
/**
* Prize tier labels
*/
const PRIZE_TIERS = ["š Jackpot", "š„ 3 in-a-row", "š„ 2 in-a-row"];
/**
* Validation messages
*/
const VALIDATION = {
GAME_NUMBER: "ā ļø Please enter a valid game number",
};
/**
* Display defaults
*/
const DISPLAY = {
NOT_AVAILABLE: "ā",
};
/**
* Error messages that require special handling
*/
const ERROR_MESSAGES = {
GAME_NOT_STARTED: "Game ID exceeds current game",
};
/**
* Error response messages
*/
const ERROR_RESPONSES = {
GAME_NOT_STARTED:
"ā ļø Game number you entered exceeds the current active game.",
};
/**
* Handles displaying detailed information about a specific game
*/
async function gameInfoHandler() {
try {
console.log(chalk.cyan("\nš Loading game information..."));
const config = await loadConfig();
const publicClient = createPublicClient(config);
// Get game number from user
const gameNumber = await promptForGameNumber();
// Get and display game information
const gameInfo = await getDetailedGameInfo(
publicClient,
config.contractAddress,
gameNumber
);
displayGameInformation(gameNumber, gameInfo, config.network);
} catch (error) {
handleError(error);
}
}
/**
* Prompts the user for a game number
* @returns {Promise<number>} The selected game number
*/
async function promptForGameNumber() {
const { gameNumber } = await inquirer.prompt([
{
type: "number",
name: "gameNumber",
message: "š® Enter the past game number you want to view:",
validate: (input) => input > 0 || VALIDATION.GAME_NUMBER,
},
]);
return gameNumber;
}
/**
* Displays all game information
* @param {number} gameNumber - The game number
* @param {Object} gameInfo - The detailed game information
* @param {string} network - The network name
*/
function displayGameInformation(gameNumber, gameInfo, network) {
const status = GAME_STATUS[Number(gameInfo.status)];
const areNumbersSet = gameInfo.winningNumbers[0] !== 0n;
console.log(chalk.yellow(`\nš² Game ${gameNumber} Information:`));
// Display basic game info
displayBasicInfo(gameInfo, status, network);
// Display block information
displayBlockInfo(gameInfo, status);
// Display winning information
displayWinningInfo(gameInfo, status, areNumbersSet, network);
}
/**
* Displays basic game information
* @param {Object} gameInfo - The game information
* @param {string} status - The game status
* @param {string} network - The network name
*/
function displayBasicInfo(gameInfo, status, network) {
console.log(chalk.cyan("š Status:"), status);
console.log(
chalk.cyan("š° Prize Pool:"),
formatEther(gameInfo.prizePool),
network === "worldchain" ? "WLD" : "ETH"
);
console.log(
chalk.cyan("šÆ Difficulty:"),
formatDifficulty(gameInfo.difficulty)
);
}
/**
* Displays block-related information
* @param {Object} gameInfo - The game information
* @param {string} status - The game status
*/
function displayBlockInfo(gameInfo, status) {
const isInPlay = status === "š® In Play";
console.log(
chalk.cyan("š” Draw Initiated Block:"),
isInPlay ? DISPLAY.NOT_AVAILABLE : gameInfo.drawInitiatedBlock.toString()
);
console.log(
chalk.cyan("š² Witnet Randomness Value:"),
isInPlay || !gameInfo.randomValue
? DISPLAY.NOT_AVAILABLE
: gameInfo.randomValue.toString()
);
}
/**
* Displays winning-related information
* @param {Object} gameInfo - The game information
* @param {string} status - The game status
* @param {boolean} areNumbersSet - Whether the winning numbers have been set
* @param {string} network - The network name
*/
function displayWinningInfo(gameInfo, status, areNumbersSet, network) {
console.log(
chalk.cyan("šÆ Winning Numbers:"),
areNumbersSet ? gameInfo.winningNumbers.join(", ") : DISPLAY.NOT_AVAILABLE
);
console.log(
chalk.cyan("š„ Number of Winners:"),
areNumbersSet
? `${gameInfo.numberOfWinners.toString()} (š: ${
gameInfo.goldWinners
}, š„: ${gameInfo.silverWinners}, š„: ${gameInfo.bronzeWinners})`
: DISPLAY.NOT_AVAILABLE
);
displayPayouts(gameInfo, status, network);
}
/**
* Formats and displays payout information
* @param {Object} gameInfo - The game information
* @param {string} status - The game status
* @param {string} network - The network name
*/
function displayPayouts(gameInfo, status, network) {
console.log(
chalk.cyan("šø Payouts:"),
status === "ā
Completed"
? formatPayouts(gameInfo.payouts, network)
: DISPLAY.NOT_AVAILABLE
);
}
/**
* Formats payout information into a readable string
* @param {bigint[]} payouts - Array of payout amounts
* @param {string} network - The network name
* @returns {string} Formatted payout string
*/
function formatPayouts(payouts, network) {
return payouts
.map((payout, index) => {
return `${PRIZE_TIERS[index]}: ${formatEther(payout)} ${
network === "worldchain" ? "WLD" : "ETH"
}`;
})
.join(", ");
}
/**
* Handles errors that occur during the game info display
* @param {Error} error - The error to handle
*/
function handleError(error) {
if (error.message.includes(ERROR_MESSAGES.GAME_NOT_STARTED)) {
console.log(chalk.yellow(ERROR_RESPONSES.GAME_NOT_STARTED));
} else {
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);
}
}
export default {
command: "game-info",
describe: "š² Get game information",
handler: gameInfoHandler,
};