Decentralized Finance Yield Farming Tool

DeFi Yield Farming Calculator

$${totalEndingBalance.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}

Blended APY

${overallAPY.toFixed(2)}%

Detailed Breakdown

${results.details.map(detail => ` `).join('')}
Farming Pool Daily Earnings Total Profit Final Value
${detail.poolName} (${detail.poolApy}%) $${detail.dailyEarnings.toFixed(2)} $${detail.totalProfit.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} $${detail.finalValue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}
`; }; const renderSetupTab = () => { return `
$

Select Farming Pools

${farmingPools.map(pool => `

APY: ${pool.apy}% - Risk: ${pool.risk}

`).join('')}
`; }; const renderConfigTab = () => { let poolForms = farmingPools.map(pool => `

Edit Pool

`).join(''); return `
${poolForms}
`; }; // --- CHART & PDF --- const renderChart = () => { if (myChart) { myChart.destroy(); } const ctx = document.getElementById('yieldChart'); if (!ctx || !results) return; const labels = results.details.map(d => d.poolName); const profitData = results.details.map(d => d.totalProfit); myChart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: 'Total Profit ($)', data: profitData, backgroundColor: 'rgba(79, 70, 229, 0.8)', borderColor: 'rgba(79, 70, 229, 1)', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return '$' + value.toLocaleString(); } } } }, plugins: { legend: { display: false }, title: { display: true, text: `Projected Profit over ${results.periodDays} Days`, font: { size: 16 } } } } }); }; window.downloadPDF = () => { if (!results) { console.error("No results to download."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); const today = new Date().toLocaleDateString('en-US'); // Title doc.setFontSize(20); doc.text("DeFi Yield Farming Report", doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); doc.setFontSize(12); doc.text(`Report Generated: ${today}`, doc.internal.pageSize.getWidth() / 2, 28, { align: 'center' }); // Summary Text const summaryText = ` Initial Investment: $${results.totalInitialInvestment.toLocaleString()} Investment Period: ${results.periodDays} days Total Ending Balance: $${results.totalEndingBalance.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} Total Profit: $${(results.totalEndingBalance - results.totalInitialInvestment).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} `; doc.setFontSize(11); doc.text(summaryText, 14, 40); // Add Chart Image let finalY = 70; if (myChart) { const chartImage = myChart.toBase64Image(); const imgProps = doc.getImageProperties(chartImage); const pdfWidth = doc.internal.pageSize.getWidth() - 28; const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; doc.addImage(chartImage, 'PNG', 14, finalY, pdfWidth, pdfHeight); finalY += pdfHeight + 10; } // Detailed Table const head = [['Farming Pool', 'APY (%)', 'Daily Earnings ($)', 'Total Profit ($)', 'Final Value ($)']]; const body = results.details.map(d => [d.poolName, d.poolApy, d.dailyEarnings.toFixed(2), d.totalProfit.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}), d.finalValue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})]); doc.autoTable({ startY: finalY, head: head, body: body, theme: 'striped', headStyles: { fillColor: [79, 70, 229] } }); doc.save('DeFi-Yield-Farming-Report.pdf'); }; // --- EVENT HANDLERS & DATA UPDATERS --- window.updateInvestment = (key, value) => { investment[key] = parseFloat(value) || 0; }; window.togglePoolSelection = (poolId) => { const index = investment.selectedPoolIds.indexOf(poolId); if (index > -1) { investment.selectedPoolIds.splice(index, 1); } else { investment.selectedPoolIds.push(poolId); } }; const handleCalculation = () => { if (investment.selectedPoolIds.length === 0) { // We can't use alert, so we'll show a subtle message const calcButton = document.getElementById('calculate-btn'); if(calcButton) { calcButton.innerText = 'Please select at least one pool!'; setTimeout(() => { calcButton.innerText = 'Calculate Returns'; }, 2000); } return; } const details = []; let totalEndingBalance = 0; const investmentPerPool = investment.amount / investment.selectedPoolIds.length; investment.selectedPoolIds.forEach(poolId => { const pool = farmingPools.find(p => p.id === poolId); if (pool) { const dailyRate = (pool.apy / 100) / 365; const dailyEarnings = investmentPerPool * dailyRate; const totalProfit = dailyEarnings * investment.periodDays; const finalValue = investmentPerPool + totalProfit; details.push({ poolName: pool.name, poolApy: pool.apy, dailyEarnings, totalProfit, finalValue }); totalEndingBalance += finalValue; } }); results = { totalInitialInvestment: investment.amount, periodDays: investment.periodDays, totalEndingBalance, details }; switchTab(0); // Go to dashboard }; window.updatePool = (poolId, key, value) => { const pool = farmingPools.find(p => p.id === poolId); if (pool) { pool[key] = (key === 'apy') ? parseFloat(value) || 0 : value; } }; const handleAddPool = () => { farmingPools.push({ id: Date.now(), name: 'New Custom Pool', apy: 10.0, risk: 'Medium' }); renderCurrentTab(); }; window.handleDeletePool = (poolId) => { farmingPools = farmingPools.filter(p => p.id !== poolId); // Also remove it from selection if it was selected investment.selectedPoolIds = investment.selectedPoolIds.filter(id => id !== poolId); renderCurrentTab(); }; // --- INITIALIZATION --- nextBtn.addEventListener('click', () => switchTab(currentTab + 1)); prevBtn.addEventListener('click', () => switchTab(currentTab - 1)); tabButtons.forEach((button, index) => { button.addEventListener('click', () => switchTab(index)); }); renderCurrentTab(); updateNavButtons(); });
Scroll to Top