UNPKG

flashloan-profit-calculator

Version:

A library for analyzing flashloan transactions and calculating profits

182 lines (181 loc) 7.27 kB
"use strict"; 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