68 lines
2.7 KiB
TypeScript
68 lines
2.7 KiB
TypeScript
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<TxReceipt>).value);
|
|
failedWithdrawalTransactions.push(...transactions.filter((tx) => tx.to === routerAddress.toLowerCase() && tx.status == 0));
|
|
}
|
|
|
|
return failedWithdrawalTransactions;
|
|
}
|
|
|
|
async function calculateLosses(failedTransactions: Array<TxReceipt>): Promise<RelayerLosses> {
|
|
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<bigint> {
|
|
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();
|