const { ethers } = require('ethers');
const dotenv = require('dotenv');
dotenv.config();
// Contract ABI (simplified for key functions)
const ENTROPY_DEMO_ABI = ['function playDiceGame(uint256 targetNumber) external payable returns (uint64)', 'function getGameDetails(uint64 sequenceNumber) external view returns (tuple(address player, uint256 betAmount, uint256 targetNumber, bool fulfilled, bool won, uint256 diceRoll, uint256 timestamp))', 'function isRequestFulfilled(uint64 sequenceNumber) external view returns (bool)', 'function getPlayerBalance(address player) external view returns (uint256)', 'function withdraw() external', 'function getEntropyFee() external view returns (uint128)', 'function gameCounter() external view returns (uint256)', 'event GameRequested(uint64 indexed sequenceNumber, address indexed player, uint256 betAmount, uint256 targetNumber)', 'event GameResolved(uint64 indexed sequenceNumber, address indexed player, bool won, uint256 diceRoll)', 'event RandomnessRequested(uint64 indexed sequenceNumber)', 'event RandomnessFulfilled(uint64 indexed sequenceNumber, bytes32 randomNumber)'];
/**
* Play a dice game using Pyth Entropy randomness
* @param {string} contractAddress Deployed Entropy demo contract address
* @param {string} privateKey Player's private key
* @param {number} targetNumber Target dice number (1-6)
* @param {string} betAmount Bet amount in SEI
* @param {string} rpcUrl RPC endpoint URL
*/
async function playEntropyDiceGame(contractAddress, privateKey, targetNumber, betAmount, rpcUrl = 'https://evm-rpc.sei-apis.com') {
try {
console.log('🎲 Starting Pyth Entropy Dice Game...');
// Setup provider and wallet
const provider = new ethers.JsonRpcProvider(rpcUrl);
const wallet = new ethers.Wallet(privateKey, provider);
// Create contract instance
const contract = new ethers.Contract(contractAddress, ENTROPY_DEMO_ABI, wallet);
const balance = await provider.getBalance(wallet.address);
console.log(`💼 Player Wallet: ${wallet.address} | Balance: ${ethers.formatEther(balance)} SEI`);
console.log(`🎯 Player: ${wallet.address}`);
console.log(`💰 Bet Amount: ${betAmount} SEI`);
console.log(`🎲 Target Number: ${targetNumber}`);
// Get current entropy fee
const entropyFee = await contract.getEntropyFee();
console.log(`⚡ Entropy Fee: ${ethers.formatEther(entropyFee)} SEI`);
// Check current balance
const currentBalance = await contract.getPlayerBalance(wallet.address);
console.log(`💳 Current Contract Balance: ${ethers.formatEther(currentBalance)} SEI`);
// Calculate total payment (bet + entropy fee)
const betInWei = ethers.parseEther(betAmount);
const totalPayment = betInWei + entropyFee;
console.log('\n🔄 Submitting game transaction...');
const tx = await contract.playDiceGame(targetNumber, {
value: totalPayment,
gasLimit: 300000
});
console.log(`📝 Transaction Hash: ${tx.hash}`);
// Wait for confirmation and get receipt
const receipt = await tx.wait();
console.log(`✅ Transaction confirmed in block: ${receipt.blockNumber}`);
// Extract sequence number from events
const gameRequestedEvent = receipt.logs.find((log) => {
try {
const decoded = contract.interface.parseLog({
topics: log.topics,
data: log.data
});
return decoded.name === 'GameRequested';
} catch {
return false;
}
});
if (!gameRequestedEvent) {
throw new Error('GameRequested event not found');
}
const decodedEvent = contract.interface.parseLog({
topics: gameRequestedEvent.topics,
data: gameRequestedEvent.data
});
const sequenceNumber = decodedEvent.args[0];
console.log(`🎟️ Sequence Number: ${sequenceNumber.toString()}`);
// Wait for Entropy fulfillment
console.log('\n⏳ Waiting for Entropy fulfillment...');
await waitForEntropyFulfillment(contract, sequenceNumber);
// Get final game results
const gameDetails = await contract.getGameDetails(sequenceNumber);
console.log('\n🎯 GAME RESULTS:');
console.log(`🎲 Dice Roll: ${gameDetails.diceRoll}`);
console.log(`🎯 Target: ${gameDetails.targetNumber}`);
console.log(`${gameDetails.won ? '🎉 WINNER!' : '💔 Better luck next time!'}`);
console.log(`💰 Bet Amount: ${ethers.formatEther(gameDetails.betAmount)} SEI`);
if (gameDetails.won) {
const winAmount = gameDetails.betAmount * BigInt(5);
console.log(`💸 Winnings: ${ethers.formatEther(winAmount)} SEI`);
}
// Check updated balance
const newBalance = await contract.getPlayerBalance(wallet.address);
console.log(`💳 New Balance: ${ethers.formatEther(newBalance)} SEI`);
return {
sequenceNumber: sequenceNumber.toString(),
diceRoll: Number(gameDetails.diceRoll),
targetNumber: Number(gameDetails.targetNumber),
won: gameDetails.won,
txHash: receipt.transactionHash,
blockNumber: receipt.blockNumber
};
} catch (error) {
console.error('❌ Error playing Entropy dice game:', error.message);
throw error;
}
}
/**
* Wait for Entropy fulfillment with timeout
* @param {Contract} contract Contract instance
* @param {BigInt} sequenceNumber Entropy sequence number
* @param {number} timeoutMs Timeout in milliseconds
*/
async function waitForEntropyFulfillment(contract, sequenceNumber, timeoutMs = 120000) {
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
try {
const fulfilled = await contract.isRequestFulfilled(sequenceNumber);
if (fulfilled) {
console.log('✅ Entropy request fulfilled!');
return;
}
process.stdout.write('.');
await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait 3 seconds
} catch (error) {
console.error('Error checking fulfillment:', error.message);
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
throw new Error('Entropy fulfillment timed out');
}
/**
* Monitor Entropy events in real-time
* @param {string} contractAddress Contract address
* @param {string} rpcUrl RPC URL
*/
async function monitorEntropyEvents(contractAddress, rpcUrl = 'https://evm-rpc.sei-apis.com') {
try {
console.log('👂 Starting Entropy event monitoring...');
const provider = new ethers.JsonRpcProvider(rpcUrl);
const contract = new ethers.Contract(contractAddress, ENTROPY_DEMO_ABI, provider);
// Listen for game events
contract.on('GameRequested', (sequenceNumber, player, betAmount, targetNumber) => {
console.log(`🎮 Game Requested - Sequence: ${sequenceNumber}, Player: ${player}, Target: ${targetNumber}, Bet: ${ethers.formatEther(betAmount)} SEI`);
});
contract.on('RandomnessRequested', (sequenceNumber) => {
console.log(`🔄 Entropy Randomness Requested - Sequence: ${sequenceNumber}`);
});
contract.on('RandomnessFulfilled', (sequenceNumber, randomNumber) => {
console.log(`✅ Entropy Randomness Fulfilled - Sequence: ${sequenceNumber}, Random: ${randomNumber}`);
});
contract.on('GameResolved', (sequenceNumber, player, won, diceRoll) => {
console.log(`🎯 Game Resolved - Sequence: ${sequenceNumber}, Player: ${player}, Won: ${won}, Roll: ${diceRoll}`);
});
console.log('✅ Event monitoring active. Press Ctrl+C to stop.');
} catch (error) {
console.error('Error monitoring events:', error.message);
throw error;
}
}
/**
* Simple Pyth Entropy demonstration
*/
async function demonstratePythEntropyIntegration() {
const contractAddress = process.env.CONTRACT_ADDRESS;
const privateKey = process.env.PRIVATE_KEY;
const rpcUrl = 'https://evm-rpc.sei-apis.com';
console.log('🚀 Starting Sei Pyth Entropy Integration Demo...');
console.log(`📍 Contract Address: ${contractAddress}`);
console.log(`🌐 RPC URL: ${rpcUrl}\n`);
try {
// Play a single dice game
const result = await playEntropyDiceGame(contractAddress, privateKey, 3, '0.1', rpcUrl);
console.log('\n🎉 Pyth Entropy Demo completed successfully!');
console.log(`📋 Game Summary:`);
console.log(` - Sequence: ${result.sequenceNumber}`);
console.log(` - Target: ${result.targetNumber}, Roll: ${result.diceRoll}`);
console.log(` - Result: ${result.won ? 'WON' : 'LOST'}`);
console.log(` - Transaction: ${result.txHash}`);
console.log(` - Block: ${result.blockNumber}`);
} catch (error) {
console.error('❌ Demo failed:', error.message);
}
}
// Export functions for use in other modules
module.exports = {
playEntropyDiceGame,
waitForEntropyFulfillment,
monitorEntropyEvents,
demonstratePythEntropyIntegration
};
// Run demo if this file is executed directly
// Usage: node SeiPythEntropyIntegration.js
if (require.main === module) {
demonstratePythEntropyIntegration();
}