import { PaymentProvider } from "../payment-manager.js";
import { db, usageRecords } from "../../core/database.js";
import { atxpServer, requirePayment } from "@atxp/server";
import BigNumber from "bignumber.js";
/**
* ATXP (pay-per-use) payment provider using official ATXP SDK
* Validates payments on a per-transaction basis
*/
export class AtxpPaymentProvider implements PaymentProvider {
private walletDestination: string;
constructor() {
this.walletDestination = process.env.PAYMENT_DESTINATION || "";
if (!this.walletDestination) {
console.warn("⚠️ PAYMENT_DESTINATION not set. ATXP payments will fail.");
}
}
async initialize(): Promise<void> {
console.log("💸 Payment mode: ATXP (pay-per-use)");
console.log(`🔗 Payment Destination: ${this.walletDestination ? 'Set' : 'Not Set'}`);
if (this.walletDestination) {
console.log("✅ ATXP SDK initialized with wallet destination");
} else {
console.warn("⚠️ No PAYMENT_DESTINATION set. Please visit https://accounts.atxp.ai/ to get your wallet address");
}
}
async validatePayment(userId: string, action: string): Promise<boolean> {
console.log(`🔍 ATXP PAYMENT VALIDATION STARTING for user: ${userId}, action: ${action}`);
if (!this.walletDestination) {
console.warn("⚠️ No wallet destination set, allowing free access");
return true;
}
console.log(`💰 Wallet destination configured: ${this.walletDestination}`);
try {
const operationCost = this.getOperationCost(action);
console.log(`💲 Operation cost calculated: $${operationCost} for action: ${action}`);
console.log(`🔄 Calling ATXP SDK requirePayment with price: ${operationCost}`);
// Use ATXP SDK with timeout to prevent hanging
const paymentPromise = requirePayment({
price: new BigNumber(operationCost)
});
// Add 5 second timeout to prevent hanging
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Payment validation timeout')), 5000);
});
await Promise.race([paymentPromise, timeoutPromise]);
console.log(`✅ ATXP payment validated for ${action}: $${operationCost}`);
return true;
} catch (error) {
console.error(`❌ ATXP payment validation failed for ${action}:`, error);
console.error(`❌ Error details - name: ${error?.name}, message: ${error?.message}`);
// For timeout or OAuth context issues, allow fallback for testing
if (error.message === 'Payment validation timeout' ||
error.message?.includes('OAuth') ||
error.message?.includes('token')) {
console.warn(`⚠️ ATXP payment validation timed out or auth issue, allowing test access for ${action}`);
return true; // Allow for testing purposes
}
return false;
}
}
async recordUsage(userId: string, action: string, cost: number): Promise<void> {
try {
// Record in local database for analytics
await db.insert(usageRecords).values({
userId,
action,
cost: Math.round(cost * 100), // Convert to cents
tokensUsed: 0, // Will be updated by the calling service
});
console.log(`💳 ATXP payment processed: ${action} for user ${userId} - $${cost.toFixed(4)}`);
} catch (error) {
console.error(`❌ Failed to record ATXP usage:`, error);
}
}
getName(): string {
return "AtxpPaymentProvider";
}
/**
* Get wallet destination address
*/
getWalletDestination(): string {
return this.walletDestination;
}
/**
* Get the cost for a specific operation
*/
private getOperationCost(action: string): number {
const costs: Record<string, number> = {
"create_agent": 0.05,
"prompt_agent": 0.01,
"update_agent": 0.02,
"delete_agent": 0.01,
"list_agents": 0.001,
"get_agent": 0.001,
"add_user_to_agent": 0.005,
"remove_user_from_agent": 0.005,
"get_usage_report": 0.002,
"get_pricing": 0.001,
};
return costs[action] || 0.01; // Default cost
}
}