113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
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>("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);
|
|
});
|