Add script to calculate relayer losses during the hack
This commit is contained in:
parent
739c28414c
commit
8c97665093
4
data/relayerLosses.txt
Normal file
4
data/relayerLosses.txt
Normal file
@ -0,0 +1,4 @@
|
||||
0x864DF9CD806D58341f13602103Bf853066ff962a = 625894225496155734516 // ~ 625 TORN
|
||||
0x5555555731006f71f121144534Ca7C8799F66AA3 = 43970301082908267318 // ~ 43 TORN
|
||||
0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C = 189640345451160934437 // ~ 189 TORN
|
||||
0x03392600086874456E08D2bAc104380BCdEBCfC0 = 129757783603193410350 // ~ 129 TORN
|
14
package.json
14
package.json
@ -1,22 +1,26 @@
|
||||
{
|
||||
"name": "forge-proposal-template",
|
||||
"name": "proposal-33-compensate-relayer-losses",
|
||||
"version": "1.0.0",
|
||||
"repository": "https://git.tornado.ws/Theo/forge-proposal-template",
|
||||
"repository": "https://git.tornado.ws/Theo/proposal-33-compensate-relayer-losses",
|
||||
"author": "Theo",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"init": "cd lib && git clone --recurse-submodules https://github.com/foundry-rs/forge-std",
|
||||
"test:windows": ".\\.env.bat && forge test",
|
||||
"test:linux": ". .env && forge test",
|
||||
"test:gas:windows": ".\\.env.bat && forge test --gas-report",
|
||||
"test:gas:linux": ". .env && forge test --gas-report"
|
||||
"test:gas:linux": ". .env && forge test --gas-report",
|
||||
"calculate": "npx ts-node scripts/calculateLosses.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ensdomains/ens-contracts": "^0.0.21",
|
||||
"@openzeppelin/contracts": "^4.9.0",
|
||||
"@openzeppelin/upgrades-core": "^1.26.2"
|
||||
"@openzeppelin/upgrades-core": "^1.26.2",
|
||||
"axios": "^1.5.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"web3": "^4.2.0",
|
||||
"web3-utils": "^4.0.7"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@gnosis.pm/ido-contracts": "^0.5.0",
|
||||
|
67
scripts/calculateLosses.ts
Normal file
67
scripts/calculateLosses.ts
Normal file
@ -0,0 +1,67 @@
|
||||
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();
|
4
scripts/types.ts
Normal file
4
scripts/types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { Web3Eth } from "web3";
|
||||
|
||||
export type TxReceipt = Awaited<ReturnType<Web3Eth["getTransactionReceipt"]>>;
|
||||
export type RelayerLosses = Record<string, bigint>;
|
@ -1,34 +1,31 @@
|
||||
type NodeVarObject = { [key: string]: string | number };
|
||||
type NodeVarObject = { [key: string]: string };
|
||||
type NodeVarArray = [string, string];
|
||||
|
||||
const solidityCodePadding = " ".repeat(8);
|
||||
const pad = (decl: string, padding: string = solidityCodePadding) => padding + decl + "\n";
|
||||
|
||||
class DeclCalculator {
|
||||
declType!: string | number;
|
||||
padding!: string;
|
||||
transformator!: Function;
|
||||
|
||||
public constructor(
|
||||
declType: string | number,
|
||||
padding: string = solidityCodePadding,
|
||||
transformator: Function = (
|
||||
private declType: string,
|
||||
private padding: string = solidityCodePadding,
|
||||
private transformator: Function = (
|
||||
() => (x: any) =>
|
||||
x
|
||||
)(),
|
||||
private variableNameChanger: Function = (
|
||||
() => (x: any) =>
|
||||
x
|
||||
)()
|
||||
) {
|
||||
this.declType = declType;
|
||||
this.padding = padding || solidityCodePadding;
|
||||
this.transformator = transformator;
|
||||
}
|
||||
) {}
|
||||
|
||||
private displayVariableName(varObj: NodeVarObject) {
|
||||
return Object.keys(varObj)[0];
|
||||
}
|
||||
|
||||
public calculateDecl = (varObj: NodeVarObject, type: string = "bytes32") => {
|
||||
const solidityVariableName = this.displayVariableName(varObj);
|
||||
const solidityVariableValue = this.transformator(Object.values(varObj)[0]);
|
||||
const solidityDeclaration = `${this.declType || type} ${solidityVariableName} = ${solidityVariableValue.toString()};`;
|
||||
public calculateDecl = (varInfo: NodeVarObject | NodeVarArray, type: string = "bytes32") => {
|
||||
const solidityVariableName = this.variableNameChanger(Array.isArray(varInfo) ? varInfo[0] : this.displayVariableName(varInfo));
|
||||
const solidityVariableValue = this.transformator(Array.isArray(varInfo) ? varInfo[1] : Object.values(varInfo)[0]);
|
||||
const solidityDeclaration = `${this.declType || type} ${solidityVariableName} = ${solidityVariableValue};`;
|
||||
|
||||
return pad(solidityDeclaration, this.padding);
|
||||
};
|
||||
|
@ -27,7 +27,7 @@
|
||||
/* Modules */
|
||||
"module": "NodeNext" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
"moduleResolution": "NodeNext" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
|
Loading…
Reference in New Issue
Block a user