UNPKG

@gotake/gotake-sdk

Version:

SDK for interacting with GoTake blockchain contracts

250 lines (249 loc) 8.97 kB
import { BigNumber } from 'ethers'; /** * Utility functions for content management */ export class ContentUtils { /** * Validate content ID * @param contentId Content ID to validate * @returns True if content ID is valid */ static isValidContentId(contentId) { return Number.isInteger(contentId) && contentId > 0; } /** * Format price for display * @param price Price in wei/smallest unit * @param decimals Token decimals (default 18 for ETH) * @param maxDecimals Maximum decimal places to show * @returns Formatted price string */ static formatPrice(price, decimals = 18, maxDecimals = 6) { const ethers = require('ethers'); const formatted = ethers.utils.formatUnits(price, decimals); const num = parseFloat(formatted); if (num === 0) return '0'; if (num < 0.000001) return '< 0.000001'; // Round to maxDecimals return num.toFixed(Math.min(maxDecimals, decimals)).replace(/\.?0+$/, ''); } /** * Parse price from string * @param priceString Price string * @param decimals Token decimals (default 18 for ETH) * @returns Price in BigNumber */ static parsePrice(priceString, decimals = 18) { const ethers = require('ethers'); return ethers.utils.parseUnits(priceString.toString(), decimals); } /** * Calculate remaining time in seconds * @param validUntil Valid until timestamp * @returns Remaining seconds (0 if expired) */ static getRemainingTime(validUntil) { const now = Math.floor(Date.now() / 1000); const remaining = validUntil.toNumber() - now; return Math.max(0, remaining); } /** * Format time duration for display * @param seconds Duration in seconds * @returns Formatted duration string */ static formatDuration(seconds) { if (seconds <= 0) return 'Expired'; const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const remainingSeconds = seconds % 60; if (days > 0) { return `${days}d ${hours}h ${minutes}m`; } else if (hours > 0) { return `${hours}h ${minutes}m`; } else if (minutes > 0) { return `${minutes}m ${remainingSeconds}s`; } else { return `${remainingSeconds}s`; } } /** * Check if permission is still valid * @param permission View permission object * @returns True if permission is valid and not expired */ static isPermissionValid(permission) { if (!permission.isValid) return false; if (permission.remainingViews.lte(0)) return false; // Since validUntil is no longer available, we rely on the isValid flag return permission.isValid; } /** * Get permission status description * @param permission View permission object * @returns Status description string */ static getPermissionStatus(permission) { if (!permission.isValid) return 'Invalid'; if (permission.remainingViews.lte(0)) return 'No views remaining'; // Since validUntil is no longer available, we consider all valid permissions as not time-expired const remainingTime = 86400; // Default to 24 hours for display purposes if (remainingTime <= 0) return 'Expired'; const views = permission.remainingViews.toNumber(); const timeStr = this.formatDuration(remainingTime); return `${views} view${views !== 1 ? 's' : ''} remaining, ${timeStr} left`; } /** * Calculate expiry timestamp * @param durationSeconds Duration in seconds * @returns Expiry timestamp */ static calculateExpiry(durationSeconds) { const now = Math.floor(Date.now() / 1000); return BigNumber.from(now + durationSeconds); } /** * Validate content configuration * @param config Content configuration * @returns Validation result with errors if any */ static validateContentConfig(config) { const errors = []; if (!this.isValidContentId(config.contentId)) { errors.push('Content ID must be a positive integer'); } if (config.nativePrice.lt(0)) { errors.push('Native price cannot be negative'); } if (config.defaultViewCount <= 0) { errors.push('Default view count must be positive'); } if (config.viewDuration <= 0) { errors.push('View duration must be positive'); } return { isValid: errors.length === 0, errors }; } /** * Compare two content configurations * @param config1 First configuration * @param config2 Second configuration * @returns Object showing differences */ static compareConfigs(config1, config2) { const changes = {}; if (!config1.nativePrice.eq(config2.nativePrice)) { changes.nativePrice = { old: config1.nativePrice.toString(), new: config2.nativePrice.toString() }; } if (config1.defaultViewCount !== config2.defaultViewCount) { changes.defaultViewCount = { old: config1.defaultViewCount, new: config2.defaultViewCount }; } if (config1.viewDuration !== config2.viewDuration) { changes.viewDuration = { old: config1.viewDuration, new: config2.viewDuration }; } if (config1.isActive !== config2.isActive) { changes.isActive = { old: config1.isActive, new: config2.isActive }; } return { hasChanges: Object.keys(changes).length > 0, changes }; } /** * Generate content summary for display * @param config Content configuration * @returns Human-readable summary */ static generateContentSummary(config) { const price = this.formatPrice(config.nativePrice); const duration = this.formatDuration(config.viewDuration); const status = config.isActive ? 'Active' : 'Inactive'; return `Content ${config.contentId}: ${price} ETH, ${config.defaultViewCount} views, ${duration} validity - ${status}`; } /** * Sort content configurations by various criteria * @param configs Array of content configurations * @param sortBy Sort criteria * @param ascending Sort order * @returns Sorted configurations */ static sortConfigs(configs, sortBy, ascending = true) { const sorted = [...configs].sort((a, b) => { let comparison = 0; switch (sortBy) { case 'contentId': comparison = a.contentId - b.contentId; break; case 'nativePrice': comparison = a.nativePrice.gt(b.nativePrice) ? 1 : a.nativePrice.lt(b.nativePrice) ? -1 : 0; break; case 'defaultViewCount': comparison = a.defaultViewCount - b.defaultViewCount; break; case 'viewDuration': comparison = a.viewDuration - b.viewDuration; break; case 'isActive': comparison = Number(b.isActive) - Number(a.isActive); // Active first by default break; } return ascending ? comparison : -comparison; }); return sorted; } /** * Filter content configurations by criteria * @param configs Array of content configurations * @param filters Filter criteria * @returns Filtered configurations */ static filterConfigs(configs, filters) { return configs.filter(config => { if (filters.isActive !== undefined && config.isActive !== filters.isActive) { return false; } if (filters.minPrice && config.nativePrice.lt(filters.minPrice)) { return false; } if (filters.maxPrice && config.nativePrice.gt(filters.maxPrice)) { return false; } if (filters.minViewCount && config.defaultViewCount < filters.minViewCount) { return false; } if (filters.maxViewCount && config.defaultViewCount > filters.maxViewCount) { return false; } if (filters.contentIds && !filters.contentIds.includes(config.contentId)) { return false; } return true; }); } }