@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
210 lines (209 loc) • 9.39 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenGatingSkill = void 0;
const ethers_1 = require("ethers");
const Web3SubscriptionSkill_1 = require("./Web3SubscriptionSkill");
const FundAgent_1 = require("./FundAgent");
class TokenGatingSkill {
constructor(config) {
// Set defaults for gating configuration
const defaultFeatures = {
chat: { requiredPlan: 'basic', requiredTokens: 0, requireSafeWallet: false },
help: { requiredPlan: 'basic', requiredTokens: 0, requireSafeWallet: false },
content: { requiredPlan: 'pro', requiredTokens: 100, requireSafeWallet: false },
social: { requiredPlan: 'pro', requiredTokens: 100, requireSafeWallet: false },
analytics: { requiredPlan: 'pro', requiredTokens: 100, requireSafeWallet: false }
};
this.config = {
...config,
gating: {
requireSafeWallet: false, // Default to false - Safe wallets are optional
autoCreateSafe: false, // Default to false - Don't auto-create Safe wallets
minTokenForAccess: 0, // Default to 0 - No minimum token required
gracePeriod: 7, // Default 7 days grace period
features: { ...defaultFeatures, ...config.gating.features }
}
};
// Create provider from RPC URL or use provided provider
this.provider = config.fundAgent.provider || new ethers_1.ethers.JsonRpcProvider(config.fundAgent.rpcUrl);
this.subscriptionSkill = new Web3SubscriptionSkill_1.Web3SubscriptionSkill(config.subscription);
this.fundAgent = new FundAgent_1.FundAgent(config.fundAgent);
}
async checkUserAccess(userAddress) {
try {
const tokenBalance = await this.getTokenBalance(userAddress);
const subscription = await this.subscriptionSkill.checkSubscription(userAddress);
const safeWallet = await this.getUserSafeWallet(userAddress);
const hasAccess = this.determineAccess(tokenBalance, subscription, safeWallet);
const features = await this.checkFeatureAccess(userAddress, tokenBalance, subscription, safeWallet);
return {
hasAccess,
subscription: subscription.hasActiveSubscription ? subscription : null,
safeWallet: safeWallet?.address || null,
adaoBalance: tokenBalance,
features,
nextBillingDate: subscription.nextBillingDate,
gracePeriodDays: this.calculateGracePeriod(subscription)
};
}
catch (error) {
console.error('Error checking user access:', error);
return {
hasAccess: false,
subscription: null,
safeWallet: null,
adaoBalance: 0,
features: {}
};
}
}
async onboardUser(userAddress, planId, billingPeriod, createSafeWallet = true) {
try {
const subscription = await this.subscriptionSkill.createSubscription(userAddress, planId, billingPeriod);
let safeWallet;
if (createSafeWallet && this.config.gating.requireSafeWallet) {
const depositAmount = this.config.fundAgent.minDeposit;
safeWallet = await this.fundAgent.createSafeWallet(userAddress, depositAmount);
await this.fundAgent.addOwner(safeWallet, userAddress);
}
return {
success: true,
subscription,
safeWallet
};
}
catch (error) {
console.error('Error onboarding user:', error);
return {
success: false,
error: error.message
};
}
}
async verifyPaymentAndCreateSafe(userAddress) {
try {
const paymentVerified = await this.fundAgent.verifyPayment(userAddress);
if (!paymentVerified) {
return {
success: false,
error: `Payment verification failed. Please ensure you have sufficient ${this.config.fundAgent.tokenSymbol} tokens.`
};
}
const depositAmount = this.config.fundAgent.minDeposit;
const safeAddress = await this.fundAgent.createSafeWallet(userAddress, depositAmount);
await this.fundAgent.addOwner(safeAddress, userAddress);
return {
success: true,
safeAddress
};
}
catch (error) {
console.error('Error verifying payment and creating Safe:', error);
return {
success: false,
error: error.message
};
}
}
async getTokenBalance(userAddress) {
return await this.fundAgent.getTokenBalance(userAddress);
}
// Keep for backward compatibility
async getADaoBalance(userAddress) {
return await this.getTokenBalance(userAddress);
}
async getAvailablePlansForUser(userAddress) {
const balance = await this.getTokenBalance(userAddress);
const allPlans = await this.subscriptionSkill.getAvailablePlans();
return allPlans.filter(plan => {
const minPrice = Math.min(plan.pricing.monthly.price, plan.pricing.quarterly.price, plan.pricing.annually.price);
return balance >= minPrice;
});
}
async getUserSafeWallet(userAddress) {
try {
// Query database for user's Safe wallet
if (!this.config.database || !this.config.database.endpoint) {
throw new Error('No database endpoint configured for Safe wallet lookup. Please configure a database endpoint to use this feature.');
}
const response = await fetch(`${this.config.database.endpoint}/safe-wallets`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {})
}
});
if (response.ok) {
const data = await response.json();
const userSafeWallet = data.safeWallets.find(wallet => wallet.owners && wallet.owners.includes(userAddress.toLowerCase()));
if (userSafeWallet) {
// Get real status from blockchain
const status = await this.fundAgent.getWalletStatus(userSafeWallet.address);
return {
address: status.address,
owners: status.owners,
threshold: status.threshold,
balance: status.balance,
isActive: status.isActive,
createdAt: new Date(userSafeWallet.createdAt || Date.now())
};
}
}
// If no Safe wallet found in database, return null
return null;
}
catch (error) {
console.error('Error getting user Safe wallet:', error);
return null;
}
}
determineAccess(tokenBalance, subscription, safeWallet) {
// Check minimum token requirement
if (tokenBalance < this.config.gating.minTokenForAccess) {
return false;
}
// Check subscription requirement
if (!subscription.hasActiveSubscription) {
return false;
}
// Safe wallet is optional by default - only required if explicitly configured
if (this.config.gating.requireSafeWallet && !safeWallet) {
return false;
}
return true;
}
async checkFeatureAccess(userAddress, tokenBalance, subscription, safeWallet) {
const features = {};
for (const [featureName, featureConfig] of Object.entries(this.config.gating.features)) {
let accessible = true;
let reason;
if (tokenBalance < featureConfig.requiredTokens) {
accessible = false;
reason = `Insufficient ${this.config.fundAgent.tokenSymbol}. Required: ${featureConfig.requiredTokens}, Available: ${tokenBalance}`;
}
if (featureConfig.requiredPlan && (!subscription.hasActiveSubscription || subscription.planId !== featureConfig.requiredPlan)) {
accessible = false;
reason = `Requires ${featureConfig.requiredPlan} subscription`;
}
if (featureConfig.requireSafeWallet && !safeWallet) {
accessible = false;
reason = 'Safe wallet required';
}
features[featureName] = { accessible, reason };
}
return features;
}
calculateGracePeriod(subscription) {
if (!subscription.hasActiveSubscription || subscription.daysLeft === undefined) {
return undefined;
}
if (subscription.daysLeft <= 0) {
return Math.max(0, this.config.gating.gracePeriod + subscription.daysLeft);
}
return undefined;
}
setSigner(signer) {
this.subscriptionSkill.setSigner(signer);
}
}
exports.TokenGatingSkill = TokenGatingSkill;