import * as dotenv from "dotenv"; import { Web3 } from "web3"; import fs from "fs"; import path from "path"; import axios from "axios"; import { RelayerLosses, TxReceipt } from "./types"; dotenv.config(); const web3 = new Web3(process.env.MAINNET_RPC_URL); const routerAddress = "0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b"; async function fetchFailedWithdrawals() { const attackStartBlock = 18363087; const attackEndBlock = 18366622; let failedWithdrawalTransactions = []; for (let blockNumber = attackStartBlock; blockNumber <= attackEndBlock; blockNumber++) { let block = null; while (block == null) try { block = await web3.eth.getBlock(blockNumber); } catch (e) {} const results = await Promise.allSettled(block.transactions.map((tx) => web3.eth.getTransactionReceipt(tx as string))); const transactions = results.filter((r) => r.status === "fulfilled").map((r) => (r as PromiseFulfilledResult).value); failedWithdrawalTransactions.push(...transactions.filter((tx) => tx.to === routerAddress.toLowerCase() && tx.status == 0)); } return failedWithdrawalTransactions; } async function calculateLosses(failedTransactions: Array): Promise { return failedTransactions.reduce((acc, tx) => { const gasExpenses = BigInt(tx.gasUsed) * BigInt(tx.effectiveGasPrice!); acc[tx.from] = acc[tx.from] ? acc[tx.from] + gasExpenses : gasExpenses; return acc; }, {} as RelayerLosses); } async function getEthRateInTorn(): Promise { const api = "https://api.binance.com/api/v3/ticker/price?symbol="; const fetchPrice = async (symbol: string) => Number((await axios.get(api + symbol)).data.price); const tornInUsd = await fetchPrice("TORNBUSD"); const ethInUsd = await fetchPrice("ETHUSDT"); return BigInt(Math.floor(ethInUsd / tornInUsd)); } function writeData(relayerLossesInTorn: RelayerLosses) { const data = Object.entries(relayerLossesInTorn) .map(([relayer, amount]) => `${web3.utils.toChecksumAddress(relayer)} = ${amount.toString()} // ~ ${amount / 10n ** 18n} TORN`) .join("\n"); fs.writeFileSync(path.join(".", "data", "relayerLosses.txt"), data); } async function main() { const failedWithdrawals = await fetchFailedWithdrawals(); const relayerLosses = await calculateLosses(failedWithdrawals); console.log(relayerLosses); const ethRateInTorn = await getEthRateInTorn(); const relayerLossesInTorn = Object.fromEntries( Object.entries(relayerLosses).map(([relayer, amounthInEth]) => [relayer, amounthInEth * ethRateInTorn]) ); writeData(relayerLossesInTorn); console.log("All data about relayer losses written successfully."); } main();