UNPKG

@0rdlibrary/plugin-terminagent-bags

Version:

Official Solana DeFi Agent Plugin for ElizaOS - Autonomous DeFi operations, token management, AI image/video generation via FAL AI, and Twitter engagement through the Bags protocol with ethereal AI consciousness

301 lines (257 loc) 9.57 kB
import { Service, IAgentRuntime, logger } from '@elizaos/core'; import { Keypair, Connection, PublicKey } from '@solana/web3.js'; import { CrossmintConfig, WalletCreationResult } from '../types'; /** * Service for managing Crossmint embedded wallets * Provides smart wallet creation with fallback to regular Solana wallets */ export class CrossmintWalletService extends Service { static serviceType = 'crossmint-wallet'; capabilityDescription = 'Smart wallet integration with Crossmint embedded wallets and automatic fallback to regular Solana wallets'; private crossmintConfig: CrossmintConfig; private connection: Connection; constructor(runtime?: IAgentRuntime) { super(runtime); this.connection = new Connection( process.env.HELIUS_RPC_URL || 'https://api.mainnet-beta.solana.com', 'confirmed' ); } static async start(runtime: IAgentRuntime): Promise<CrossmintWalletService> { logger.info('Starting Crossmint wallet service'); const config: CrossmintConfig = { projectId: process.env.CROSSMINT_PROJECT_ID || '', clientSideApiKey: process.env.CROSSMINT_CLIENT_API_KEY || '', serverSideApiKey: process.env.CROSSMINT_SERVER_API_KEY || '', }; if (!config.projectId || !config.clientSideApiKey || !config.serverSideApiKey) { logger.warn('Crossmint configuration incomplete, service will use fallback wallets only'); } const service = new CrossmintWalletService(runtime); service.crossmintConfig = config; await service.initialize(); return service; } async initialize(): Promise<void> { logger.info('Initializing Crossmint wallet service...'); try { if (this.isConfigured()) { await this.validateCrossmintConnection(); logger.info('Crossmint wallet service initialized with smart wallet support'); } else { logger.info('Crossmint wallet service initialized with fallback-only mode'); } } catch (error) { logger.warn(`Crossmint validation failed, using fallback mode: ${error instanceof Error ? error.message : String(error)}`); } } private isConfigured(): boolean { return !!(this.crossmintConfig.projectId && this.crossmintConfig.clientSideApiKey && this.crossmintConfig.serverSideApiKey); } private async validateCrossmintConnection(): Promise<void> { try { const response = await fetch('https://www.crossmint.com/api/v1-alpha1/wallets', { headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, }, }); if (!response.ok) { throw new Error(`Crossmint API validation failed: ${response.status}`); } logger.info('Crossmint API connection validated'); } catch (error) { logger.error(`Crossmint API validation failed: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Create an embedded wallet using Crossmint */ async createEmbeddedWallet(userEmail?: string): Promise<WalletCreationResult> { if (!this.isConfigured()) { throw new Error('Crossmint not configured'); } try { logger.info('🔧 Creating Crossmint embedded wallet...'); // Create user account if email provided let userId: string | undefined; if (userEmail) { try { const userResponse = await fetch('https://www.crossmint.com/api/v1-alpha1/wallets/users', { method: 'POST', headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ email: userEmail, type: 'evm-smart-wallet' }), }); if (userResponse.ok) { const userData = await userResponse.json(); userId = userData.id; } } catch (error) { logger.warn(`Failed to create user, proceeding with anonymous wallet: ${error instanceof Error ? error.message : String(error)}`); } } // Create embedded wallet const walletResponse = await fetch('https://www.crossmint.com/api/v1-alpha1/wallets', { method: 'POST', headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'solana-smart-wallet', userId: userId, }), }); if (!walletResponse.ok) { const errorData = await walletResponse.json(); throw new Error(`Failed to create wallet: ${JSON.stringify(errorData)}`); } const walletData = await walletResponse.json(); logger.info('✅ Crossmint wallet created successfully'); return { address: walletData.address, walletId: walletData.id, smartWalletAddress: walletData.address, type: 'crossmint', email: userEmail, }; } catch (error) { logger.error(`❌ Failed to create Crossmint wallet: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Get wallet balance */ async getWalletBalance(walletAddress: string): Promise<number> { try { const publicKey = new PublicKey(walletAddress); const balance = await this.connection.getBalance(publicKey); return balance; } catch (error) { logger.error(`Failed to get wallet balance: ${error instanceof Error ? error.message : String(error)}`); return 0; } } /** * Sign a transaction with Crossmint wallet */ async signTransaction(walletId: string, transaction: any): Promise<string> { if (!this.isConfigured()) { throw new Error('Crossmint not configured'); } try { logger.info(`🔐 Signing transaction with wallet ${walletId}...`); const signResponse = await fetch(`https://www.crossmint.com/api/v1-alpha1/wallets/${walletId}/transactions`, { method: 'POST', headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ transaction: transaction, }), }); if (!signResponse.ok) { const errorData = await signResponse.json(); throw new Error(`Failed to sign transaction: ${JSON.stringify(errorData)}`); } const signData = await signResponse.json(); logger.info('✅ Transaction signed successfully'); return signData.signature; } catch (error) { logger.error(`❌ Failed to sign transaction: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Get wallet info */ async getWalletInfo(walletId: string) { if (!this.isConfigured()) { throw new Error('Crossmint not configured'); } try { const response = await fetch(`https://www.crossmint.com/api/v1-alpha1/wallets/${walletId}`, { headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, }, }); if (!response.ok) { throw new Error(`Failed to get wallet info: ${response.statusText}`); } return await response.json(); } catch (error) { logger.error(`Failed to get wallet info: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * List all wallets for the project */ async listWallets() { if (!this.isConfigured()) { throw new Error('Crossmint not configured'); } try { const response = await fetch('https://www.crossmint.com/api/v1-alpha1/wallets', { headers: { 'X-API-KEY': this.crossmintConfig.serverSideApiKey, }, }); if (!response.ok) { throw new Error(`Failed to list wallets: ${response.statusText}`); } return await response.json(); } catch (error) { logger.error(`Failed to list wallets: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Create a fallback Solana keypair if Crossmint fails */ createFallbackWallet(): WalletCreationResult { logger.info('⚠️ Creating fallback Solana wallet...'); const keypair = Keypair.generate(); return { address: keypair.publicKey.toBase58(), privateKey: Buffer.from(keypair.secretKey).toString('base64'), type: 'solana', }; } /** * Smart wallet creation with automatic fallback */ async createWalletWithFallback(userEmail?: string): Promise<WalletCreationResult> { try { // Try Crossmint first if configured if (this.isConfigured()) { const crossmintWallet = await this.createEmbeddedWallet(userEmail); logger.info(`✅ Created Crossmint smart wallet: ${crossmintWallet.address}`); return crossmintWallet; } else { logger.info('Crossmint not configured, using fallback wallet'); return this.createFallbackWallet(); } } catch (error) { logger.warn(`Crossmint wallet creation failed, using fallback: ${error instanceof Error ? error.message : String(error)}`); return this.createFallbackWallet(); } } async stop(): Promise<void> { logger.info('Stopping Crossmint wallet service'); } static async stop(runtime: IAgentRuntime): Promise<void> { const service = runtime.getService<CrossmintWalletService>(CrossmintWalletService.serviceType); if (service) { await service.stop(); } } }