Spaces:
Sleeping
Sleeping
| // scripts/deploy-all-testnets.js | |
| // Deploy QuantumRandomnessOracle to all testnets | |
| const { ethers } = require("hardhat"); | |
| const fs = require("fs"); | |
| const path = require("path"); | |
| // Deployment configuration | |
| const DEPLOYMENT_CONFIG = { | |
| fee: ethers.utils.parseEther("0.01"), // 0.01 native token per request | |
| oracleNodeAddress: null, // Will be set to deployer address | |
| }; | |
| // Testnet configurations | |
| const TESTNETS = [ | |
| { | |
| name: "sepolia", | |
| displayName: "Ethereum Sepolia", | |
| chainId: 11155111, | |
| explorer: "https://sepolia.etherscan.io", | |
| explorerApi: "https://api-sepolia.etherscan.io/api" | |
| }, | |
| { | |
| name: "polygonAmoy", | |
| displayName: "Polygon Amoy", | |
| chainId: 80002, | |
| explorer: "https://amoy.polygonscan.com", | |
| explorerApi: "https://api-amoy.polygonscan.com/api" | |
| }, | |
| { | |
| name: "bscTestnet", | |
| displayName: "BSC Testnet", | |
| chainId: 97, | |
| explorer: "https://testnet.bscscan.com", | |
| explorerApi: "https://api-testnet.bscscan.com/api" | |
| }, | |
| { | |
| name: "avalancheFuji", | |
| displayName: "Avalanche Fuji", | |
| chainId: 43113, | |
| explorer: "https://testnet.snowtrace.io", | |
| explorerApi: "https://api-testnet.snowtrace.io/api" | |
| }, | |
| { | |
| name: "fantomTestnet", | |
| displayName: "Fantom Testnet", | |
| chainId: 4002, | |
| explorer: "https://testnet.ftmscan.com", | |
| explorerApi: "https://api-testnet.ftmscan.com/api" | |
| } | |
| ]; | |
| async function deployToNetwork(networkName) { | |
| const networkConfig = TESTNETS.find(n => n.name === networkName); | |
| if (!networkConfig) { | |
| throw new Error(`Unknown network: ${networkName}`); | |
| } | |
| console.log(`\n========================================`); | |
| console.log(`Deploying to ${networkConfig.displayName}...`); | |
| console.log(`========================================`); | |
| // Get deployer | |
| const [deployer] = await ethers.getSigners(); | |
| console.log("Deploying contracts with the account:", deployer.address); | |
| const balance = await deployer.getBalance(); | |
| console.log("Account balance:", ethers.utils.formatEther(balance), "ETH"); | |
| // Set oracle node address to deployer | |
| DEPLOYMENT_CONFIG.oracleNodeAddress = deployer.address; | |
| // Deploy contract | |
| console.log("\nDeploying QuantumRandomnessOracle..."); | |
| console.log("Fee:", ethers.utils.formatEther(DEPLOYMENT_CONFIG.fee), "ETH"); | |
| console.log("Oracle Node:", DEPLOYMENT_CONFIG.oracleNodeAddress); | |
| const QuantumRandomnessOracle = await ethers.getContractFactory("QuantumRandomnessOracle"); | |
| const oracleContract = await QuantumRandomnessOracle.deploy( | |
| DEPLOYMENT_CONFIG.fee, | |
| DEPLOYMENT_CONFIG.oracleNodeAddress | |
| ); | |
| console.log("Waiting for deployment..."); | |
| await oracleContract.deployed(); | |
| console.log("✓ QuantumRandomnessOracle deployed to:", oracleContract.address); | |
| console.log("Explorer URL:", `${networkConfig.explorer}/tx/${oracleContract.deployTransaction.hash}`); | |
| // Wait for additional confirmations | |
| console.log("Waiting for 5 confirmations..."); | |
| await oracleContract.deployTransaction.wait(5); | |
| console.log("✓ Deployment confirmed"); | |
| return { | |
| network: networkName, | |
| displayName: networkConfig.displayName, | |
| chainId: networkConfig.chainId, | |
| contractAddress: oracleContract.address, | |
| deployerAddress: deployer.address, | |
| fee: DEPLOYMENT_CONFIG.fee.toString(), | |
| deploymentTxHash: oracleContract.deployTransaction.hash, | |
| explorerUrl: `${networkConfig.explorer}/address/${oracleContract.address}`, | |
| deploymentTimestamp: new Date().toISOString() | |
| }; | |
| } | |
| async function verifyContract(networkName, contractAddress) { | |
| console.log(`\nVerifying contract on ${networkName}...`); | |
| try { | |
| await hre.run("verify:verify", { | |
| address: contractAddress, | |
| constructorArguments: [ | |
| DEPLOYMENT_CONFIG.fee, | |
| DEPLOYMENT_CONFIG.oracleNodeAddress | |
| ] | |
| }); | |
| console.log("✓ Contract verified successfully"); | |
| return true; | |
| } catch (error) { | |
| console.log("✗ Contract verification failed:", error.message); | |
| return false; | |
| } | |
| } | |
| async function saveDeploymentResults(results) { | |
| const deploymentsDir = path.join(__dirname, "../deployments"); | |
| // Create deployments directory if it doesn't exist | |
| if (!fs.existsSync(deploymentsDir)) { | |
| fs.mkdirSync(deploymentsDir, { recursive: true }); | |
| } | |
| // Save individual network deployments | |
| results.forEach(result => { | |
| const filename = `deployment-${result.network}.json`; | |
| const filepath = path.join(deploymentsDir, filename); | |
| fs.writeFileSync(filepath, JSON.stringify(result, null, 2)); | |
| console.log(`✓ Saved deployment info: ${filename}`); | |
| }); | |
| // Save combined deployment summary | |
| const summary = { | |
| deploymentDate: new Date().toISOString(), | |
| totalNetworks: results.length, | |
| deployments: results, | |
| summary: results.map(r => ({ | |
| network: r.network, | |
| displayName: r.displayName, | |
| contractAddress: r.contractAddress, | |
| explorerUrl: r.explorerUrl | |
| })) | |
| }; | |
| const summaryPath = path.join(deploymentsDir, "deployment-summary.json"); | |
| fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2)); | |
| console.log(`✓ Saved deployment summary: deployment-summary.json`); | |
| // Save as Markdown report | |
| const mdReport = generateMarkdownReport(summary); | |
| const mdPath = path.join(deploymentsDir, "DEPLOYMENT_REPORT.md"); | |
| fs.writeFileSync(mdPath, mdReport); | |
| console.log(`✓ Saved deployment report: DEPLOYMENT_REPORT.md`); | |
| } | |
| function generateMarkdownReport(summary) { | |
| let md = `# QuantumRandomnessOracle Deployment Report\n\n`; | |
| md += `**Deployment Date:** ${summary.deploymentDate}\n\n`; | |
| md += `**Total Networks:** ${summary.totalNetworks}\n\n`; | |
| md += `---\n\n`; | |
| md += `## Contract Addresses\n\n`; | |
| md += `| Network | Contract Address | Explorer |\n`; | |
| md += `|---------|-----------------|----------|\n`; | |
| summary.deployments.forEach(dep => { | |
| md += `| ${dep.displayName} | \`${dep.contractAddress}\` | [View](${dep.explorerUrl}) |\n`; | |
| }); | |
| md += `\n---\n\n`; | |
| md += `## Deployment Details\n\n`; | |
| summary.deployments.forEach(dep => { | |
| md += `### ${dep.displayName}\n\n`; | |
| md += `- **Contract Address:** \`${dep.contractAddress}\`\n`; | |
| md += `- **Chain ID:** ${dep.chainId}\n`; | |
| md += `- **Deployer:** \`${dep.deployerAddress}\`\n`; | |
| md += `- **Fee:** ${ethers.utils.formatEther(dep.fee)} ETH\n`; | |
| md += `- **Deployment TX:** [${dep.deploymentTxHash.slice(0, 10)}...${dep.deploymentTxHash.slice(-8)}](${dep.explorerUrl})\n`; | |
| md += `- **Timestamp:** ${dep.deploymentTimestamp}\n\n`; | |
| }); | |
| md += `---\n\n`; | |
| md += `## Usage\n\n`; | |
| md += `### Add to Configuration\n\n`; | |
| md += `\`\`\`bash\n`; | |
| md += `# Add these to your .env file or app/config.py\n`; | |
| summary.deployments.forEach(dep => { | |
| const envName = dep.network.toUpperCase().replace('TESTNET', '').replace('FUJI', 'AVALANCHE'); | |
| md += `${envName}_ORACLE_CONTRACT="${dep.contractAddress}"\n`; | |
| }); | |
| md += `\`\`\`\n\n`; | |
| md += `### API Configuration\n\n`; | |
| md += `\`\`\`python\n`; | |
| md += `# app/config.py or environment variables\n`; | |
| summary.deployments.forEach(dep => { | |
| const envName = dep.network.toUpperCase().replace('TESTNET', '').replace('FUJI', 'AVALANCHE'); | |
| md += `ORACLE_CONTRACT_${envName} = "${dep.contractAddress}"\n`; | |
| }); | |
| md += `\`\`\`\n\n`; | |
| return md; | |
| } | |
| async function main() { | |
| console.log("=============================================="); | |
| console.log("QuantumRandomnessOracle Multi-Network Deploy"); | |
| console.log("==============================================\n"); | |
| const results = []; | |
| const failed = []; | |
| // Get deployment targets from command line or deploy to all testnets | |
| const targetNetworks = process.argv.length > 2 | |
| ? process.argv.slice(2) | |
| : TESTNETS.map(n => n.name); | |
| console.log("Target networks:", targetNetworks.join(", ")); | |
| // Deploy to each network | |
| for (const networkName of targetNetworks) { | |
| try { | |
| // Switch network | |
| await hre.network.change(networkName); | |
| const result = await deployToNetwork(networkName); | |
| results.push(result); | |
| // Verify contract (optional, requires API key) | |
| if (process.env.SKIP_VERIFICATION !== "true") { | |
| await verifyContract(networkName, result.contractAddress); | |
| } | |
| } catch (error) { | |
| console.error(`\n✗ Deployment to ${networkName} failed:`, error.message); | |
| failed.push({ network: networkName, error: error.message }); | |
| } | |
| } | |
| // Save results | |
| if (results.length > 0) { | |
| await saveDeploymentResults(results); | |
| } | |
| // Summary | |
| console.log("\n=============================================="); | |
| console.log("Deployment Summary"); | |
| console.log("=============================================="); | |
| console.log(`Successful: ${results.length}/${targetNetworks.length}`); | |
| console.log(`Failed: ${failed.length}/${targetNetworks.length}`); | |
| if (failed.length > 0) { | |
| console.log("\nFailed deployments:"); | |
| failed.forEach(f => { | |
| console.log(` - ${f.network}: ${f.error}`); | |
| }); | |
| } | |
| if (results.length > 0) { | |
| console.log("\n✓ Deployments complete!"); | |
| console.log("Check deployments/ folder for contract addresses and details."); | |
| } | |
| } | |
| main() | |
| .then(() => process.exit(0)) | |
| .catch((error) => { | |
| console.error("Fatal error:", error); | |
| process.exit(1); | |
| }); | |