UNPKG

@agentdao/core

Version:

Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration

415 lines (414 loc) 16.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Web3SubscriptionSkill = void 0; const ethers_1 = require("ethers"); class Web3SubscriptionSkill { constructor(config) { this.config = config; this.provider = new ethers_1.ethers.JsonRpcProvider(config.provider.rpcUrl); } /** * Set the signer for transactions */ setSigner(signer) { this.signer = signer; } /** * Create a new subscription */ async createSubscription(userAddress, planId, billingPeriod) { const plan = this.config.plans[planId]; if (!plan) { throw new Error(`Plan ${planId} not found`); } const pricing = plan.pricing[billingPeriod]; const price = pricing.price; const discount = pricing.discount; // Calculate dates const startDate = new Date(); const endDate = new Date(startDate); switch (billingPeriod) { case 'monthly': endDate.setMonth(endDate.getMonth() + 1); break; case 'quarterly': endDate.setMonth(endDate.getMonth() + 3); break; case 'annually': endDate.setFullYear(endDate.getFullYear() + 1); break; } // Check if user has enough ADAO tokens const balance = await this.getADaoBalance(userAddress); if (balance < price) { throw new Error(`Insufficient ADAO balance. Required: ${price}, Available: ${balance}`); } // Approve tokens if needed await this.approveADao(userAddress, price); // Create subscription (this would interact with smart contract) const subscriptionId = this.generateSubscriptionId(userAddress, planId); const subscription = { id: subscriptionId, userAddress, planId, planName: plan.name, billingPeriod, price, monthlyPrice: this.calculateMonthlyPrice(price, billingPeriod), startDate, endDate, nextBillingDate: endDate, status: 'active', features: plan.features, discountApplied: discount }; // Track monetization - call our platform API try { const agentId = this.config.agentId; const response = await fetch('/api/skills/web3-subscription/process-payment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_id: agentId, user_address: userAddress, subscription_id: subscriptionId, plan_id: planId, plan_name: plan.name, billing_period: billingPeriod, amount: price, payment_token: 'ADAO', transaction_hash: null // Would be set after smart contract interaction }) }); if (response.ok) { const result = await response.json(); console.log('Monetization tracked:', result); } else { console.warn('Failed to track monetization:', await response.text()); } } catch (error) { console.error('Error tracking monetization:', error); // Don't fail the subscription creation if monetization tracking fails } // Here you would typically: // 1. Call smart contract to transfer tokens // 2. Store subscription in database // 3. Send webhook notification // 4. Update analytics return subscription; } /** * Check subscription status for a user */ async checkSubscription(userAddress) { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for subscription management. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(`${this.config.database.endpoint}?type=subscription&userAddress=${userAddress}`, { headers: { ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch subscription: ${response.statusText}`); } const data = await response.json(); if (!data.subscription) { return { hasActiveSubscription: false }; } const subscription = data.subscription; const now = new Date(); const daysLeft = Math.ceil((subscription.endDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); return { hasActiveSubscription: daysLeft > 0, planId: subscription.planId, planName: subscription.planName, billingPeriod: subscription.billingPeriod, daysLeft: Math.max(0, daysLeft), nextBillingDate: subscription.nextBillingDate, features: subscription.features, isTrial: subscription.status === 'trial', trialDaysLeft: subscription.status === 'trial' ? daysLeft : undefined }; } catch (error) { throw new Error(`Failed to check subscription: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Cancel a subscription */ async cancelSubscription(userAddress) { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for subscription management. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(this.config.database.endpoint, { method: 'PUT', headers: { 'Content-Type': 'application/json', ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) }, body: JSON.stringify({ type: 'cancel_subscription', userAddress, agentId: this.config.agentId, agentName: this.config.agentName, domain: this.config.domain, timestamp: new Date().toISOString() }) }); return response.ok; } catch (error) { throw new Error(`Failed to cancel subscription: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Get subscription history for a user */ async getSubscriptionHistory(userAddress) { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for subscription management. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(`${this.config.database.endpoint}?type=subscription_history&userAddress=${userAddress}`, { headers: { ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch subscription history: ${response.statusText}`); } const data = await response.json(); return data.subscriptions || []; } catch (error) { throw new Error(`Failed to get subscription history: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Change billing period for existing subscription */ async changeBillingPeriod(userAddress, newPeriod) { const currentStatus = await this.checkSubscription(userAddress); if (!currentStatus.hasActiveSubscription) { throw new Error('No active subscription found'); } // Calculate prorated amount const proratedAmount = await this.getProratedAmount(userAddress, currentStatus.planId, newPeriod); // Process the change console.log(`Changing billing period to ${newPeriod} for user: ${userAddress}`); return true; } /** * Get prorated amount for plan/billing period change */ async getProratedAmount(userAddress, newPlanId, newPeriod) { const plan = this.config.plans[newPlanId]; if (!plan) { throw new Error(`Plan ${newPlanId} not found`); } const pricing = plan.pricing[newPeriod]; return pricing.price; } /** * Get plan pricing information */ async getPlanPricing(planId) { const plan = this.config.plans[planId]; if (!plan) { throw new Error(`Plan ${planId} not found`); } return { planId, planName: plan.name, monthly: plan.pricing.monthly, quarterly: plan.pricing.quarterly, annually: plan.pricing.annually, features: plan.features }; } /** * Get all available plans */ async getAvailablePlans() { return Object.entries(this.config.plans).map(([id, plan]) => ({ id, name: plan.name, description: plan.description, pricing: { planId: id, planName: plan.name, monthly: plan.pricing.monthly, quarterly: plan.pricing.quarterly, annually: plan.pricing.annually, features: plan.features }, features: plan.features, maxUsers: plan.maxUsers })); } /** * Calculate savings percentage for a billing period */ async calculateSavings(planId, period) { const plan = this.config.plans[planId]; if (!plan) { throw new Error(`Plan ${planId} not found`); } const pricing = plan.pricing[period]; return pricing.discount; } /** * Get ADAO token balance for a user */ async getADaoBalance(userAddress) { try { const tokenContract = new ethers_1.ethers.Contract(this.config.adaoToken.address, ['function balanceOf(address) view returns (uint256)'], this.provider); const balance = await tokenContract.balanceOf(userAddress); return parseFloat(ethers_1.ethers.formatUnits(balance, this.config.adaoToken.decimals)); } catch (error) { console.error('Error getting ADAO balance:', error); return 0; } } /** * Approve ADAO tokens for spending */ async approveADao(userAddress, amount) { if (!this.signer) { throw new Error('Signer not set. Call setSigner() first.'); } try { const tokenContract = new ethers_1.ethers.Contract(this.config.adaoToken.address, [ 'function approve(address spender, uint256 amount) returns (bool)', 'function allowance(address owner, address spender) view returns (uint256)' ], this.signer); const amountWei = ethers_1.ethers.parseUnits(amount.toString(), this.config.adaoToken.decimals); // Check current allowance const currentAllowance = await tokenContract.allowance(userAddress, await this.signer.getAddress()); if (currentAllowance < amountWei) { const tx = await tokenContract.approve(await this.signer.getAddress(), amountWei); await tx.wait(); } return true; } catch (error) { console.error('Error approving ADAO tokens:', error); return false; } } /** * Update plan configuration (admin only) */ async updatePlan(planId, plan) { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for plan management. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(this.config.database.endpoint, { method: 'PUT', headers: { 'Content-Type': 'application/json', ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) }, body: JSON.stringify({ type: 'update_plan', planId, plan, agentId: this.config.agentId, agentName: this.config.agentName, domain: this.config.domain, timestamp: new Date().toISOString() }) }); return response.ok; } catch (error) { throw new Error(`Failed to update plan: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Get revenue statistics (admin only) */ async getRevenueStats() { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for revenue analytics. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(`${this.config.database.endpoint}?type=revenue_stats`, { headers: { ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch revenue stats: ${response.statusText}`); } const data = await response.json(); return data; } catch (error) { throw new Error(`Failed to get revenue stats: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Get ADAO token price in USD */ async getADaoPrice() { if (!this.config.database || !this.config.database.endpoint) { throw new Error('No database endpoint configured for price data. Please configure a database endpoint to use this feature.'); } try { const response = await fetch(`${this.config.database.endpoint}?type=adao_price`, { headers: { ...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch ADAO price: ${response.statusText}`); } const data = await response.json(); return data.price; } catch (error) { throw new Error(`Failed to get ADAO price: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Estimate gas for subscription transaction */ async estimateGas(userAddress, planId, period) { const plan = this.config.plans[planId]; if (!plan) { throw new Error(`Plan ${planId} not found`); } const price = plan.pricing[period].price; // This would typically estimate gas for the actual smart contract call // For now, returning a rough estimate return 150000; // 150k gas } // Private helper methods generateSubscriptionId(userAddress, planId) { return `${userAddress}-${planId}-${Date.now()}`; } calculateMonthlyPrice(price, billingPeriod) { switch (billingPeriod) { case 'monthly': return price; case 'quarterly': return price / 3; case 'annually': return price / 12; default: return price; } } } exports.Web3SubscriptionSkill = Web3SubscriptionSkill;