import { ethers } from 'ethers'; import { GoTakeSDK, NetworkId, getNetworkById, getNetworkByName } from '../src'; import * as dotenv from 'dotenv'; // Load environment variables dotenv.config(); interface PermissionSummary { contentId: number; hasPermission: boolean; purchaseTime?: Date; remainingViews: number; } class PermissionChecker { private sdk: GoTakeSDK; constructor(network: NetworkId | string, private signer: ethers.Signer) { this.sdk = new GoTakeSDK({ network: network, signer: signer }); } async checkUserPermissions(userAddress: string, contentIds: number[]): Promise { console.log(`\nšŸ” Checking permissions for user: ${userAddress}`); console.log('='.repeat(80)); const summaries: PermissionSummary[] = []; // Check permissions for each content for (const contentId of contentIds) { try { const hasPermission = await this.sdk.videoPayment.userHasViewPermission(userAddress, contentId); let purchaseTime: Date | undefined; let remainingViews = 0; if (hasPermission) { const permissions = await this.sdk.videoPayment.getUserPermissions(userAddress, contentId); purchaseTime = new Date(permissions.purchaseTime.toNumber() * 1000); remainingViews = permissions.remainingViews.toNumber(); } const summary: PermissionSummary = { contentId, hasPermission, purchaseTime, remainingViews }; summaries.push(summary); await this.displayPermissionDetails(summary); } catch (error) { console.error(`āŒ Failed to process permissions for content ${contentId}:`, error.message); summaries.push({ contentId, hasPermission: false, remainingViews: 0 }); } } this.displaySummaryTable(summaries); await this.displayRecommendations(summaries); } private async displayPermissionDetails(summary: PermissionSummary): Promise { console.log(`\nšŸ“ŗ Content ID: ${summary.contentId}`); try { // Get content purchase information to show available options const contentInfo = await this.sdk.videoPayment.getContentInfo(summary.contentId); console.log(` Content Active: ${contentInfo.isActive ? 'Yes āœ…' : 'No āŒ'}`); console.log(` View Count: ${contentInfo.viewCount} views`); if (summary.hasPermission) { console.log(` Permission: āœ… Granted`); console.log(` Purchase Time: ${summary.purchaseTime?.toLocaleString()}`); console.log(` Remaining Views: ${summary.remainingViews}`); } else { console.log(` Permission: āŒ Not granted`); if (contentInfo.isActive) { console.log(` šŸ’° Purchase Options:`); Object.entries(contentInfo.tokenPrices).forEach(([token, price]) => { if (token === ethers.constants.AddressZero) { console.log(` šŸ’Ž ETH: ${ethers.utils.formatEther(price)} ETH`); } else { console.log(` šŸŖ™ Token: ${ethers.utils.formatUnits(price, 18)} (${token.slice(0, 10)}...)`); } }); } else { console.log(` Action Required: Content not available for purchase`); } } } catch (error) { console.log(` āŒ Failed to get content details: ${error.message}`); if (summary.hasPermission) { console.log(` Permission: āœ… Granted`); console.log(` Remaining Views: ${summary.remainingViews}`); } else { console.log(` Permission: āŒ Not granted`); } } } private displaySummaryTable(summaries: PermissionSummary[]): void { console.log('\nšŸ“Š Permission Summary Table:'); console.log('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'); console.log('│ Content ID │ Permission │ Views Left │'); console.log('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'); summaries.forEach(summary => { const contentId = summary.contentId.toString().padStart(10); const permission = summary.hasPermission ? 'āœ… Yes'.padStart(12) : 'āŒ No'.padStart(11); const views = summary.remainingViews.toString().padStart(12); console.log(`│ ${contentId} │ ${permission} │ ${views} │`); }); console.log('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜'); } private async displayRecommendations(summaries: PermissionSummary[]): Promise { console.log('\nšŸ’” Recommendations:'); const needToPurchase = summaries.filter(s => !s.hasPermission); const exhaustedPermissions = summaries.filter(s => s.hasPermission && s.remainingViews <= 0); const activePermissions = summaries.filter(s => s.hasPermission && s.remainingViews > 0); if (needToPurchase.length > 0) { console.log('\nšŸ›’ Content Available for Purchase:'); for (const summary of needToPurchase) { try { const contentInfo = await this.sdk.videoPayment.getContentInfo(summary.contentId); if (contentInfo.isActive) { const ethPrice = contentInfo.tokenPrices[ethers.constants.AddressZero]; if (ethPrice) { console.log(` • Content ${summary.contentId}: ${ethers.utils.formatEther(ethPrice)} ETH`); } else { console.log(` • Content ${summary.contentId}: ERC20 tokens only`); } } else { console.log(` • Content ${summary.contentId}: Currently unavailable`); } } catch (error) { console.log(` • Content ${summary.contentId}: Error getting price info`); } } // Batch purchase suggestion if (needToPurchase.length > 1) { console.log(`\n šŸ’” Tip: Use batch purchase to buy multiple content at once`); console.log(` Command: npm run purchase-content batch ${needToPurchase.map(s => s.contentId).join(' ')}`); } } if (exhaustedPermissions.length > 0) { console.log('\nšŸ”„ Views Exhausted (Repurchase to Continue):'); exhaustedPermissions.forEach(s => { console.log(` • Content ${s.contentId}: No views remaining`); }); } if (activePermissions.length > 0) { console.log('\nāœ… Active Permissions:'); activePermissions.forEach(s => { console.log(` • Content ${s.contentId}: ${s.remainingViews} views remaining`); }); } // Performance suggestions if (activePermissions.length > 0) { const lowViewCounts = activePermissions.filter(s => s.remainingViews <= 1); if (lowViewCounts.length > 0) { console.log('\n⚔ Usage Alert:'); lowViewCounts.forEach(s => { console.log(` • Content ${s.contentId}: Only ${s.remainingViews} view(s) remaining`); }); } } } async checkMyPermissions(contentIds: number[]): Promise { const userAddress = await this.signer.getAddress(); await this.checkUserPermissions(userAddress, contentIds); } async bulkPermissionCheck(userAddresses: string[], contentIds: number[]): Promise { console.log('\nšŸ‘„ Bulk Permission Check'); console.log('='.repeat(50)); for (const userAddress of userAddresses) { await this.checkUserPermissions(userAddress, contentIds); console.log('\n' + '-'.repeat(80)); } } async analyzeUserEngagement(userAddress: string, contentIds: number[]): Promise { console.log(`\nšŸ“ˆ User Engagement Analysis for: ${userAddress}`); console.log('='.repeat(80)); let totalPurchases = 0; let activePurchases = 0; let exhaustedPurchases = 0; let totalViewsRemaining = 0; for (const contentId of contentIds) { try { const hasPermission = await this.sdk.videoPayment.userHasViewPermission(userAddress, contentId); if (hasPermission) { totalPurchases++; const permissions = await this.sdk.videoPayment.getUserPermissions(userAddress, contentId); totalViewsRemaining += permissions.remainingViews.toNumber(); if (permissions.remainingViews.toNumber() > 0) { activePurchases++; } else { exhaustedPurchases++; } } } catch (error) { console.warn(`Failed to analyze content ${contentId}:`, error.message); } } console.log('\nšŸ“Š Engagement Statistics:'); console.log(` Total Purchases: ${totalPurchases}`); console.log(` Active Purchases: ${activePurchases}`); console.log(` Exhausted Purchases: ${exhaustedPurchases}`); console.log(` Views Remaining: ${totalViewsRemaining}`); if (totalPurchases > 0) { console.log(` Active Purchase Rate: ${((activePurchases / totalPurchases) * 100).toFixed(1)}%`); } if (totalViewsRemaining > 0 && activePurchases > 0) { console.log(` Average Views per Active Purchase: ${(totalViewsRemaining / activePurchases).toFixed(1)}`); } } async performanceTest(userAddress: string, contentIds: number[]): Promise { console.log('\n⚔ Performance Test: Individual Operations'); console.log('='.repeat(60)); // Test individual operations console.time('Individual Operations'); try { for (const contentId of contentIds) { await this.sdk.videoPayment.userHasViewPermission(userAddress, contentId); } console.timeEnd('Individual Operations'); console.log('āœ… Individual operations completed successfully'); } catch (error) { console.timeEnd('Individual Operations'); console.log('āŒ Individual operations failed:', error.message); } } } async function main() { console.log('šŸ‘ļø GoTake Permission Checker'); console.log('============================\n'); // Environment configuration - support network selection const NETWORK = process.env.NETWORK || 'Base Sepolia'; const PRIVATE_KEY = process.env.PRIVATE_KEY; if (!PRIVATE_KEY) { console.error('āŒ Please set PRIVATE_KEY environment variable'); process.exit(1); } try { // Resolve network configuration let networkConfig; if (typeof NETWORK === 'string' && !isNaN(Number(NETWORK))) { // Network ID provided const networkId = Number(NETWORK) as NetworkId; networkConfig = getNetworkById(networkId); } else { // Network name provided networkConfig = getNetworkByName(NETWORK); } if (!networkConfig) { console.error(`āŒ Unsupported network: ${NETWORK}`); console.log('Supported networks: Base Mainnet, Base Sepolia, Base Goerli, Ethereum Mainnet, Ethereum Sepolia'); process.exit(1); } console.log(`🌐 Network: ${networkConfig.name} (ID: ${networkConfig.id})`); console.log(`šŸ”— RPC: ${networkConfig.rpcUrl}`); // Create provider and signer const provider = new ethers.providers.JsonRpcProvider(networkConfig.rpcUrl); const signer = new ethers.Wallet(PRIVATE_KEY, provider); const checker = new PermissionChecker(networkConfig.id, signer); // Get command line arguments const command = process.argv[2]; const targetAddress = process.argv[3]; // Default test content IDs const contentIds = [1, 2, 3, 4]; switch (command) { case 'check': if (targetAddress) { await checker.checkUserPermissions(targetAddress, contentIds); } else { await checker.checkMyPermissions(contentIds); } break; case 'my-permissions': await checker.checkMyPermissions(contentIds); break; case 'analyze': const analyzeAddress = targetAddress || await signer.getAddress(); await checker.analyzeUserEngagement(analyzeAddress, contentIds); break; case 'bulk': // Example bulk check with multiple addresses const addresses = process.argv.slice(3); if (addresses.length === 0) { console.error('Usage: npm run check-permissions bulk [address2] ...'); process.exit(1); } await checker.bulkPermissionCheck(addresses, contentIds); break; case 'single': // Check single content for current user const singleContentId = parseInt(process.argv[3]); if (!singleContentId) { console.error('Usage: npm run check-permissions single '); process.exit(1); } await checker.checkMyPermissions([singleContentId]); break; case 'performance': // Performance test const testAddress = targetAddress || await signer.getAddress(); await checker.performanceTest(testAddress, contentIds); break; default: console.log('Available commands:'); console.log(' check [address] - Check permissions (current user if no address)'); console.log(' my-permissions - Check current user permissions'); console.log(' analyze [address] - Analyze user engagement'); console.log(' bulk [addr2]... - Bulk check multiple users'); console.log(' single - Check single content for current user'); console.log(' performance [address] - Test individual operations'); console.log('\nExamples:'); console.log(' npm run check-permissions check'); console.log(' npm run check-permissions check 0x742d35Cc6638C0532925a3b8A39c309b64D0b76b'); console.log(' npm run check-permissions analyze'); console.log(' npm run check-permissions single 1'); console.log(' npm run check-permissions performance'); break; } } catch (error) { console.error('āŒ Permission check failed:', error); process.exit(1); } } // Run the script if (require.main === module) { main().catch(console.error); }