import { ethers } from "hardhat"; import { WhitelistOracle } from "../typechain-types"; import hre from "hardhat"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { fetchPriceFromUniswap } from "./fetchPriceFromUniswap"; import { sleep } from "./utils"; async function getAllOracles() { const [deployer] = await ethers.getSigners(); const whitelistContract = await ethers.getContract("WhitelistOracle", deployer.address); const oracleAddresses = []; let index = 0; try { while (true) { const oracle = await whitelistContract.oracles(index); oracleAddresses.push(oracle); index++; } } catch { // When we hit an out-of-bounds error, we've found all oracles console.log(`Found ${oracleAddresses.length} oracles`); } return oracleAddresses; } function getRandomPrice(basePrice: bigint): bigint { const percentageShifts = [1, 2, 5, 7, 10, 15, 20]; const randomIndex = Math.floor(Math.random() * percentageShifts.length); const percentage = BigInt(percentageShifts[randomIndex]); const direction = Math.random() < 0.5 ? -1n : 1n; const offset = (basePrice * percentage * direction) / 100n; return basePrice + offset; } const runCycle = async (hre: HardhatRuntimeEnvironment, basePrice: bigint) => { try { const accounts = await hre.viem.getWalletClients(); const simpleOracleFactory = await ethers.getContractFactory("SimpleOracle"); const publicClient = await hre.viem.getPublicClient(); const blockNumber = await publicClient.getBlockNumber(); console.log(`\n[Block ${blockNumber}] Starting new whitelist oracle cycle...`); const oracleAddresses = await getAllOracles(); if (oracleAddresses.length === 0) { console.log("No oracles found"); return; } for (const oracleAddress of oracleAddresses) { if (Math.random() < 0.4) { console.log(`Skipping oracle at ${oracleAddress}`); continue; } const randomPrice = getRandomPrice(basePrice); console.log(`Setting price for oracle at ${oracleAddress} to ${randomPrice}`); await accounts[0].writeContract({ address: oracleAddress as `0x${string}`, abi: simpleOracleFactory.interface.fragments, functionName: "setPrice", args: [randomPrice], }); } } catch (error) { console.error("Error in oracle cycle:", error); throw error; } }; async function run() { console.log("Starting whitelist oracle bots..."); const basePrice = await fetchPriceFromUniswap(); while (true) { await runCycle(hre, basePrice); await sleep(4000); } } run().catch(error => { console.error(error); process.exitCode = 1; }); // Handle process termination signals process.on("SIGINT", async () => { console.log("\nReceived SIGINT (Ctrl+C). Cleaning up..."); process.exit(0); }); process.on("SIGTERM", async () => { console.log("\nReceived SIGTERM. Cleaning up..."); process.exit(0); }); // Handle uncaught exceptions process.on("uncaughtException", async error => { console.error("Uncaught Exception:", error); process.exit(1); }); // Handle unhandled promise rejections process.on("unhandledRejection", async (reason, promise) => { console.error("Unhandled Rejection at:", promise, "reason:", reason); process.exit(1); });