flashloan-profit-calculator
Version:
A library for analyzing flashloan transactions and calculating profits
182 lines (181 loc) • 7.27 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateProfitFromTxHash = calculateProfitFromTxHash;
exports.calculateProfit = calculateProfit;
exports.displayProfitResults = displayProfitResults;
const processors_1 = require("./processors");
const services_1 = require("./services");
const profitCalculator_1 = require("./profitCalculator");
/**
* Calculate profit from a transaction hash
*/
async function calculateProfitFromTxHash(txHash) {
try {
// Get transaction details
let transactionDetails;
try {
transactionDetails = await (0, services_1.getTransactionDetails)(txHash);
}
catch (error) {
console.error(`Failed - Could not get transaction details: ${error}`);
throw error;
}
const { blockNumber, senderAddress, contractAddress, trace, logs } = transactionDetails;
// Calculate profit using the extracted data
console.log(`Calculating profit for tx ${txHash}...`);
let profit;
try {
profit = await calculateProfit(logs, trace, blockNumber, contractAddress, senderAddress);
// Log profit summary
console.log("Profit Summary:");
for (const item of profit) {
console.log(` Token: ${item.token}, Profit: ${item.profit.toString()}`);
}
}
catch (error) {
console.error(`Failed - Could not calculate profit: ${error}`);
throw error;
}
console.log(`========== COMPLETED ANALYSIS FOR TX: ${txHash} ==========`);
return profit;
}
catch (error) {
console.error(`ANALYSIS FAILED FOR TX ${txHash}: ${error}`);
console.error(`Stack trace: ${error.stack}`);
throw error;
}
}
/**
* Main function to calculate profit from a transaction
*/
async function calculateProfit(logs, trace, blockNumber, contract, sender) {
try {
console.log(`Starting profit calculation: Block ${blockNumber}, Contract ${contract}, Sender ${sender}`);
console.log(`Processing ${logs.length} logs and ${trace.length} trace calls`);
// Reset state for clean calculation
(0, processors_1.resetState)();
console.log("State reset complete");
// Setup the processor
try {
await (0, processors_1.updateBuilderAddress)(blockNumber);
console.log(`Builder address updated: ${blockNumber}`);
}
catch (error) {
console.error(`Failed to update builder address: ${error}`);
// Continue with processing even if this fails
}
(0, processors_1.setupProcessor)(contract, sender);
console.log(`Processor setup complete: Contract ${contract}, Sender ${sender}`);
// Process transfer logs and trace data
// const filteredLogs = logs.filter(
// (log) =>
// log.name === "Transfer" ||
// (log.name === "Withdrawal" && WETH_LIKE_TOKENS.has(log.raw.address)) ||
// (log.name === "Deposit" && WETH_LIKE_TOKENS.has(log.raw.address))
// );
// try {
// for (const log of filteredLogs) {
// try {
// processTransferLog(log);
// } catch (error) {
// console.error(`Error processing log: ${error}`);
// // Continue with next log
// }
// }
// } catch (error) {
// console.error(`Failed to process logs: ${error}`);
// // Continue with trace processing
// }
try {
console.log(`Processing ${trace.length} trace calls`);
await (0, processors_1.processTraceCall)(trace);
console.log("Trace processing complete");
}
catch (error) {
console.error(`Failed to process trace calls: ${error}`);
// Continue with profit calculation
}
// Calculate profit
try {
console.log("Calculating profit...");
const profit = (0, profitCalculator_1.calculateProfitByToken)();
console.log(`Profit calculation complete. Found ${profit.length} tokens`);
return profit;
}
catch (error) {
console.error(`Failed to calculate profit: ${error}`);
throw error;
}
}
catch (error) {
console.error(`Fatal error in calculateProfit: ${error}`);
console.error(`Stack trace: ${error.stack}`);
throw error;
}
}
/**
* Format and display profit results
*/
async function displayProfitResults(profitResults) {
console.log("Profit Summary:");
for (const result of profitResults) {
try {
// Try to get token metadata for better display
const metadata = await (0, processors_1.getTokenMetadata)(result.token);
const decimals = metadata.decimals || 18;
const symbol = metadata.symbol || "ETH";
// Calculate human-readable profit
const profit = Number(result.profit) / 10 ** decimals;
console.log(`Token: ${result.token} (${symbol}), Profit: ${profit.toFixed(decimals)} ${symbol}`);
}
catch (error) {
// If metadata can't be retrieved, display raw data
console.log(`Token: ${result.token}, Profit: ${Number(result.profit) / 1e18} (raw)`);
}
}
}
// Example usage
if (require.main === module) {
const runExample = async () => {
try {
// Example using transaction hash
const txHash = "0x4eaa9a30fabe363c883a557765f1512747011304db589dcc686156b42b613d5e";
const results = await calculateProfitFromTxHash(txHash);
await displayProfitResults(results);
}
catch (error) {
console.error("Error calculating profit:", error);
}
};
runExample().catch(console.error);
}
// Export types
__exportStar(require("./types"), exports);
// Export constants
__exportStar(require("./constants/addresses"), exports);
// Export processors
__exportStar(require("./processors"), exports);
// Export utilities
__exportStar(require("./utils/parsing"), exports);
__exportStar(require("./utils/decoding"), exports);
__exportStar(require("./utils/weth"), exports);
// Export services
__exportStar(require("./services/alchemy"), exports);
// Export detectors
__exportStar(require("./detectors/flashloan"), exports);
// Export main analysis function
// export { analyseTransferLogs } from "./token_transfers"; // TODO: Implement this