flashloan-profit-calculator
Version:
A library for analyzing flashloan transactions and calculating profits
175 lines (174 loc) • 7.7 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);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.flashloanContracts = exports.globalContractAddress = exports.globalSenderAddress = exports.globalGasCostWei = exports.globalGasCostETH = exports.globalBlockNumber = exports.FlashloanAnalysisClient = void 0;
exports.calculateProfitFromTxHash = calculateProfitFromTxHash;
exports.calculateProfit = calculateProfit;
exports.displayProfitResults = displayProfitResults;
const constants_1 = require("./constants");
const transferProcessor_1 = require("./transferProcessor");
const profitCalculator_1 = require("./profitCalculator");
__exportStar(require("./types"), exports);
__exportStar(require("./constants"), exports);
__exportStar(require("./utils"), exports);
__exportStar(require("./transferProcessor"), exports);
__exportStar(require("./profitCalculator"), exports);
__exportStar(require("./api/types"), exports);
var client_1 = require("./api/client");
Object.defineProperty(exports, "FlashloanAnalysisClient", { enumerable: true, get: function () { return __importDefault(client_1).default; } });
exports.flashloanContracts = [];
/**
* Calculate profit from a transaction hash
*/
async function calculateProfitFromTxHash(txHash) {
try {
// Get transaction details
let transactionDetails;
try {
transactionDetails = await (0, transferProcessor_1.getTransactionDetails)(txHash);
}
catch (error) {
console.error(`Failed - Could not get transaction details: ${error}`);
throw error;
}
const { blockNumber, senderAddress, contractAddress, trace, logs, gasCostETH, gasCostWei, } = transactionDetails;
exports.globalBlockNumber = transactionDetails.blockNumber;
exports.globalGasCostETH = gasCostETH;
exports.globalGasCostWei = gasCostWei;
exports.globalSenderAddress = senderAddress;
exports.globalContractAddress = contractAddress;
// 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}`);
// Reset state for clean calculation
(0, transferProcessor_1.resetState)();
(0, profitCalculator_1.resetProfitTakers)();
console.log("State reset complete");
// Setup the processor
try {
await (0, transferProcessor_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, transferProcessor_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" && constants_1.WETH_LIKE_TOKENS.has(log.raw.address)) ||
(log.name === "Deposit" && constants_1.WETH_LIKE_TOKENS.has(log.raw.address)));
try {
for (const log of filteredLogs) {
console.log(`Processing log: ${log.name}`);
try {
(0, transferProcessor_1.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, transferProcessor_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 = await (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:");
let totalProfit = 0;
for (const result of profitResults) {
try {
// Try to get token metadata for better display
const metadata = await (0, transferProcessor_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;
const usd = result.usd * profit;
totalProfit += usd;
console.log(`Token: ${result.token} (${symbol}), Profit: ${profit.toFixed(decimals)} ${symbol}, USD: $${usd.toFixed(2)}`);
}
catch (error) {
// If metadata can't be retrieved, display raw data
const usd = (result.usd * Number(result.profit)) / 1e18;
totalProfit += usd;
console.log(`Token: ${result.token}, Profit: ${Number(result.profit) / 1e18} (raw), USD: $${usd.toFixed(2)}`);
}
}
console.log(`Total Profit: $${totalProfit.toFixed(2)}`);
}