Crypto ICO Token Vesting Schedule Calculator

Vesting Parameters

Check Vesting Status at Specific Date

This calculator provides an illustrative vesting schedule based on your inputs. "Linear Daily" vesting is approximated and shown with monthly snapshots. Ensure total vesting period includes any cliff duration. This tool does not provide financial or legal advice.

${this.summaryData.cliffEndDate}

Full Vesting End Date

${this.summaryData.fullVestingEndDate}

Total Tokens Vested

${Number(totalTokens).toLocaleString()}

`; // Display Schedule Table this.elements.scheduleTableBody.innerHTML = ''; this.scheduleData.forEach(item => { const row = document.createElement('tr'); row.innerHTML = ` ${item.date} ${Number(item.unlocked).toLocaleString(undefined, {minimumFractionDigits:0, maximumFractionDigits:2})} ${Number(item.cumulative).toLocaleString(undefined, {minimumFractionDigits:0, maximumFractionDigits:2})} ${item.percentVested.toFixed(2)}% `; this.elements.scheduleTableBody.appendChild(row); }); // Calculate and Display Vested at Specific Date this.elements.vestedAtDateDisplay.innerHTML = ''; if (checkDateStr) { const checkDate = new Date(checkDateStr + "T00:00:00Z"); let vestedByCheckDate = 0; if (checkDate < tgeDate) { vestedByCheckDate = 0; } else if (checkDate < cliffEndDate) { vestedByCheckDate = 0; // No vesting during cliff } else { // After cliff // Find the last schedule entry on or before checkDate let lastApplicableEntryAmount = 0; for(let i = this.scheduleData.length - 1; i >= 0; i--) { if (new Date(this.scheduleData[i].date) <= checkDate) { lastApplicableEntryAmount = this.scheduleData[i].cumulative; break; } } vestedByCheckDate = lastApplicableEntryAmount; // For linear daily, need more precise calculation if checkDate is between table rows if (releaseFrequency === 'linear_daily' && checkDate <= fullVestingEndDate) { const daysToVestAfterCliff = vestingPeriodAfterCliffMonths * (365.25 / 12); const tokensPerDay = (daysToVestAfterCliff > 0) ? totalTokens / daysToVestAfterCliff : 0; let daysPastCliffForCheckDate = (checkDate.getTime() - cliffEndDate.getTime()) / (1000 * 60 * 60 * 24); daysPastCliffForCheckDate = Math.max(0, daysPastCliffForCheckDate); // Cannot be negative vestedByCheckDate = Math.min(tokensPerDay * daysPastCliffForCheckDate, totalTokens); } } vestedByCheckDate = Math.max(0, Math.min(vestedByCheckDate, totalTokens)); // Clamp between 0 and totalTokens this.elements.vestedAtDateDisplay.innerHTML = ` At ${this.formatDate(checkDate)}: ${Number(vestedByCheckDate).toLocaleString(undefined, {minimumFractionDigits:0, maximumFractionDigits:2})} tokens vested (${totalTokens > 0 ? ((vestedByCheckDate / totalTokens) * 100).toFixed(2) : 0}%) `; this.summaryData.checkDate = this.formatDate(checkDate); this.summaryData.vestedAtCheckDate = vestedByCheckDate; this.summaryData.percentAtCheckDate = totalTokens > 0 ? (vestedByCheckDate / totalTokens) * 100 : 0; } this.elements.resultsSection.style.display = 'block'; }, generatePDF: async function() { if (!window.jspdf || !window.html2canvas || this.scheduleData.length === 0) { alert('Please generate the vesting schedule first.'); return; } await new Promise(resolve => setTimeout(resolve, 50)); const pdfExportContainer = document.createElement('div'); pdfExportContainer.classList.add('tvc-pdf-export-content'); pdfExportContainer.style.width = '800px'; let pdfHtml = `

Token Vesting Schedule Report

`; pdfHtml += `

Summary

`; pdfHtml += `

TGE Date: ${this.summaryData.tgeDate}

`; pdfHtml += `

Cliff End Date: ${this.summaryData.cliffEndDate}

`; pdfHtml += `

Full Vesting End Date: ${this.summaryData.fullVestingEndDate}

`; pdfHtml += `

Total Tokens in Schedule: ${Number(this.summaryData.totalTokens).toLocaleString()}

`; if (this.summaryData.checkDate) { pdfHtml += `
`; pdfHtml += `

Tokens Vested by ${this.summaryData.checkDate}: ${Number(this.summaryData.vestedAtCheckDate).toLocaleString(undefined, {maximumFractionDigits:2})} (${this.summaryData.percentAtCheckDate.toFixed(2)}%)

`; } pdfHtml += `
`; pdfHtml += `

Detailed Vesting Schedule

`; const tableClone = this.elements.scheduleTableBody.parentNode.cloneNode(true); tableClone.style.fontSize = '8pt'; tableClone.querySelectorAll('th, td').forEach(cell => cell.style.padding = '4px'); pdfHtml += tableClone.outerHTML; pdfHtml += `
This schedule is illustrative, based on the provided inputs. "Linear Daily" vesting is approximated for table display.
`; pdfExportContainer.innerHTML = pdfHtml; document.body.appendChild(pdfExportContainer); try { const canvas = await html2canvas(pdfExportContainer, { scale: 1.5, useCORS: true, logging: false, windowWidth: pdfExportContainer.scrollWidth }); document.body.removeChild(pdfExportContainer); const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgProps = pdf.getImageProperties(imgData); let imgFinalWidth = pdfWidth - 40; let imgFinalHeight = (imgProps.height * imgFinalWidth) / imgProps.width; if (imgFinalHeight > pdfHeight - 40) { imgFinalHeight = pdfHeight - 40; imgFinalWidth = (imgProps.width * imgFinalHeight) / imgProps.height; } let currentY = 20; let heightProcessed = 0; const pageMargin = 20; const pageHeightAvailable = pdfHeight - 2 * pageMargin; while(heightProcessed < canvas.height) { let pageSegmentHeightOnCanvas = Math.min(canvas.height - heightProcessed, (pageHeightAvailable / imgFinalHeight) * canvas.height ); const segmentCanvas = document.createElement('canvas'); segmentCanvas.width = canvas.width; segmentCanvas.height = pageSegmentHeightOnCanvas; const sctx = segmentCanvas.getContext('2d'); sctx.drawImage(canvas, 0, heightProcessed, canvas.width, pageSegmentHeightOnCanvas, 0, 0, canvas.width, pageSegmentHeightOnCanvas); const segmentImgData = segmentCanvas.toDataURL('image/png'); const segmentImgProps = pdf.getImageProperties(segmentImgData); let segmentRenderWidth = pdfWidth - 2 * pageMargin; let segmentRenderHeight = (segmentImgProps.height * segmentRenderWidth) / segmentImgProps.width; if(segmentRenderHeight > pageHeightAvailable) { segmentRenderHeight = pageHeightAvailable; segmentRenderWidth = (segmentImgProps.width * segmentRenderHeight) / segmentImgProps.height; } if(heightProcessed > 0) pdf.addPage(); pdf.addImage(segmentImgData, 'PNG', pageMargin, pageMargin, segmentRenderWidth, segmentRenderHeight); heightProcessed += pageSegmentHeightOnCanvas; } pdf.save('Token_Vesting_Schedule.pdf'); } catch (error) { console.error("Error generating PDF:", error); alert("An error occurred while generating PDF."); if (document.body.contains(pdfExportContainer)) document.body.removeChild(pdfExportContainer); } } }; document.addEventListener('DOMContentLoaded', function() { tvcApp.init(); });
Scroll to Top