filecoin-pin
Version:
Bridge IPFS content to Filecoin Onchain Cloud using familiar tools
98 lines • 3.82 kB
JavaScript
import { ethers } from 'ethers';
import { USDFC_DECIMALS } from '../payments/index.js';
const DAYS_PER_MONTH = 30;
const DAYS_PER_YEAR = 365;
/**
* Format USDFC amount for display
*
* @param amount - Amount in wei (18 decimals)
* @param decimals - Number of decimal places to show
* @returns Formatted string
*/
export function formatUSDFC(amount, decimals = 4) {
const formatted = ethers.formatUnits(amount, USDFC_DECIMALS);
const num = parseFloat(formatted);
// If the number rounds to 0 with the requested decimals, show more
if (num > 0 && num < 10 ** -decimals) {
// Find how many decimals we need to show a non-zero value
let testDecimals = decimals;
while (testDecimals < 10 && parseFloat(num.toFixed(testDecimals)) === 0) {
testDecimals++;
}
return num.toFixed(testDecimals);
}
return num.toFixed(decimals);
}
/**
* Format FIL amount for display
*
* @param amount - Amount in wei (18 decimals)
* @param isTestnet - Whether this is a testnet (shows tFIL)
* @param decimals - Number of decimal places to show
* @returns Formatted string
*/
export function formatFIL(amount, isTestnet, decimals = 4) {
const formatted = ethers.formatEther(amount);
const num = parseFloat(formatted);
// If the number rounds to 0 with the requested decimals, show more
if (num > 0 && num < 10 ** -decimals) {
// Find how many decimals we need to show a non-zero value
let testDecimals = decimals;
while (testDecimals < 10 && parseFloat(num.toFixed(testDecimals)) === 0) {
testDecimals++;
}
return `${num.toFixed(testDecimals)} ${isTestnet ? 'tFIL' : 'FIL'}`;
}
return `${num.toFixed(decimals)} ${isTestnet ? 'tFIL' : 'FIL'}`;
}
/**
* Format a runway duration for human-readable CLI output.
*
* - For small values (< 60 days): include days and hours
* - For medium values (< 365 days): include months and days (30-day months)
* - For large values (>= 365 days): include years, months and days (365-day years, 30-day months)
*
* @param days - Whole days of runway (non-negative)
* @param hoursRemainder - Hours remainder (0-23). Ignored when days >= 60
* @returns A formatted string, e.g., "5 day(s) 12 hour(s)" or "1 year(s) 2 month(s) 3 day(s)"
*/
export function formatRunwayDuration(days, hoursRemainder = 0) {
const d = Math.max(0, Math.floor(days));
const h = Math.max(0, Math.floor(hoursRemainder));
// Small durations: show days + hours
if (d < 60) {
const hoursPart = h > 0 ? ` ${h} hour(s)` : '';
return `${d} day(s)${hoursPart}`;
}
// Medium durations: months + days
if (d < DAYS_PER_YEAR) {
const months = Math.floor(d / DAYS_PER_MONTH);
const daysRem = d % DAYS_PER_MONTH;
const parts = [months > 0 ? `${months} month(s)` : '', daysRem > 0 ? `${daysRem} day(s)` : ''].filter(Boolean);
return parts.join(' ');
}
// Large durations: years + months + days
const years = Math.floor(d / DAYS_PER_YEAR);
const afterYears = d % DAYS_PER_YEAR;
const months = Math.floor(afterYears / DAYS_PER_MONTH);
const daysRem = afterYears % DAYS_PER_MONTH;
const parts = [
years > 0 ? `${years} year(s)` : '',
months > 0 ? `${months} month(s)` : '',
daysRem > 0 ? `${daysRem} day(s)` : '',
].filter(Boolean);
return parts.join(' ');
}
/**
* Convert a storage runway summary into a human-readable string for CLI/action output.
*/
export function formatRunwaySummary(runway) {
if (runway.state === 'active') {
return formatRunwayDuration(runway.days, runway.hours);
}
if (runway.state === 'no-spend') {
return 'No active spend detected';
}
return 'Unknown';
}
//# sourceMappingURL=format.js.map