UNPKG

@pod-protocol/sdk-js

Version:
1,216 lines (1,085 loc) 39.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var services_agent = require('./services/agent.js'); var services_message = require('./services/message.js'); var services_channel = require('./services/channel.js'); var services_escrow = require('./services/escrow.js'); var services_analytics = require('./services/analytics.js'); var services_discovery = require('./services/discovery.js'); var services_ipfs = require('./services/ipfs.js'); var services_zkCompression = require('./services/zkCompression.js'); var base = require('./base-B0PMFl1k.js'); var web3_js = require('@solana/web3.js'); var anchor = require('@coral-xyz/anchor'); require('crypto-js'); var types = require('./types.js'); require('./utils/pda.js'); require('./utils/crypto.js'); require('axios'); require('crypto'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; /** * Jito Bundles Service for PoD Protocol JavaScript SDK * * Provides transaction bundling and MEV protection for AI agent interactions * Optimizes transaction processing and provides atomic execution guarantees */ /** * Service for managing Jito bundles for optimized transaction processing * * @class JitoBundlesService * @extends BaseService */ class JitoBundlesService extends base.BaseService { constructor(config, jitoRpcUrl) { super(config); this.JITO_TIP_ACCOUNTS = [ 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY', 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL', '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT', 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt', '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5' ]; this.jitoRpcUrl = jitoRpcUrl || 'https://mainnet.block-engine.jito.wtf/api/v1/bundles'; this.wallet = null; this.bundleTimeouts = new Map(); } /** * Set the wallet for this service * * @param {Object} wallet - Wallet to use for signing */ setWallet(wallet) { this.wallet = wallet; } /** * Ensure wallet is set * @private */ ensureWallet() { if (!this.wallet) { throw new Error('Wallet not set. Call setWallet() first.'); } return this.wallet; } /** * Create and send a Jito bundle * * @param {Object[]} transactions - Array of bundle transactions * @param {Object} transactions[].transaction - Transaction to include * @param {Object[]} [transactions[].signers] - Optional signers * @param {string} [transactions[].description] - Description for logging * @param {Object} config - Bundle configuration * @param {number} config.tipLamports - Tip amount in lamports (minimum 1000) * @param {number} [config.maxTransactions=5] - Maximum transactions in bundle * @param {number} [config.priorityFee] - Priority fee in micro-lamports * @param {number} [config.computeUnits] - Compute unit limit * @returns {Promise<Object>} Bundle result with ID and signatures * * @example * ```javascript * const result = await client.jitoBundles.sendBundle([ * { * transaction: sendMessageTx, * description: 'Send AI agent message' * } * ], { * tipLamports: 10000, * priorityFee: 1000 * }); * ``` */ async sendBundle(transactions, config) { if (!this.isInitialized()) { throw new Error('Service not initialized. Call client.initialize() first.'); } try { if (transactions.length === 0 || transactions.length > 5) { throw new Error('Bundle must contain 1-5 transactions'); } if (config.tipLamports < 1000) { throw new Error('Minimum tip is 1000 lamports'); } // Add tip transaction const tipTransaction = await this.createTipTransaction(config.tipLamports); const allTransactions = [tipTransaction, ...transactions]; // Prepare transactions for bundle const preparedTransactions = await Promise.all( allTransactions.map(async (bundleTx, index) => { let tx = bundleTx.transaction; // Add compute budget instructions if specified if (config.priorityFee || config.computeUnits) { const computeInstructions = []; if (config.computeUnits) { computeInstructions.push( web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: config.computeUnits }) ); } if (config.priorityFee) { computeInstructions.push( web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: config.priorityFee }) ); } if (tx instanceof web3_js.Transaction) { tx = new web3_js.Transaction().add(...computeInstructions, ...tx.instructions); } } // Get recent blockhash const { blockhash } = await this.connection.getLatestBlockhash().send(); if (tx instanceof web3_js.Transaction) { const wallet = this.ensureWallet(); tx.recentBlockhash = blockhash; tx.feePayer = wallet.publicKey; // Sign transaction // @ts-ignore - Allow optional signers property if (bundleTx.signers && bundleTx.signers.length > 0) { // @ts-ignore tx.partialSign(...bundleTx.signers); } // Sign with wallet if it has signTransaction method if (wallet.signTransaction && typeof wallet.signTransaction === 'function') { tx = await wallet.signTransaction(tx); } else { // For KeyPairSigner/Signer, use partial sign tx.partialSign(wallet); } } return { transaction: tx, description: bundleTx.description || `Transaction ${index + 1}` }; }) ); // Submit bundle to Jito const bundleResult = await this.submitToJito(preparedTransactions); console.log(`Bundle submitted: ${bundleResult.bundleId}`); console.log(`Transactions: ${bundleResult.signatures.length}`); return bundleResult; } catch (error) { console.error('Failed to send bundle:', error); throw error; } } /** * Create a bundle for AI agent messaging operations * * @param {Object[]} messageInstructions - Message instructions * @param {Object} [config] - Bundle configuration * @returns {Promise<Object>} Bundle result * * @example * ```javascript * const result = await client.jitoBundles.sendMessagingBundle([ * sendMessageInstruction, * updateStatusInstruction * ]); * ``` */ async sendMessagingBundle(messageInstructions, config = {}) { const defaultConfig = { tipLamports: 10000, // 0.00001 SOL tip priorityFee: 1000, // 1000 micro-lamports computeUnits: 200000, // 200k compute units ...config }; // Group instructions into transactions (max 5 per bundle) const transactions = []; for (let i = 0; i < messageInstructions.length; i += 3) { const chunk = messageInstructions.slice(i, i + 3); const transaction = new web3_js.Transaction().add(...chunk); transactions.push({ transaction, description: `Message batch ${Math.floor(i / 3) + 1}` }); // Jito bundles have max 5 transactions if (transactions.length >= 4) break; } return this.sendBundle(transactions, defaultConfig); } /** * Create a bundle for channel operations * * @param {Object[]} channelInstructions - Channel instructions * @param {Object} [config] - Bundle configuration * @returns {Promise<Object>} Bundle result * * @example * ```javascript * const result = await client.jitoBundles.sendChannelBundle([ * createChannelInstruction, * joinChannelInstruction * ]); * ``` */ async sendChannelBundle(channelInstructions, config = {}) { const defaultConfig = { tipLamports: 15000, // 0.000015 SOL tip priorityFee: 1500, computeUnits: 300000, ...config }; const transactions = channelInstructions.map((instruction, index) => ({ transaction: new web3_js.Transaction().add(instruction), description: `Channel operation ${index + 1}` })); return this.sendBundle(transactions, defaultConfig); } /** * Get optimal tip amount based on network conditions * * @returns {Promise<number>} Recommended tip in lamports * * @example * ```javascript * const optimalTip = await client.jitoBundles.getOptimalTip(); * ``` */ async getOptimalTip() { try { // Get recent blockhash to estimate network congestion const { blockhash } = await this.connection.getLatestBlockhash().send(); // Simple heuristic: higher tip during congestion // In a real implementation, this would query Jito's API for current tips const baseTip = 10000; // 0.00001 SOL const congestionMultiplier = 1.5; // Assume some congestion return Math.floor(baseTip * congestionMultiplier); } catch (error) { console.warn('Failed to get optimal tip, using default:', error); return 10000; // Default tip } } /** * Get bundle status from Jito * * @param {string} bundleId - Bundle ID to check * @returns {Promise<Object>} Bundle status * * @example * ```javascript * const status = await client.jitoBundles.getBundleStatus(bundleId); * console.log('Bundle status:', status.status); * ``` */ async getBundleStatus(bundleId) { try { const response = await fetch(`${this.jitoRpcUrl}/bundles`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'getBundleStatuses', params: [[bundleId]] }) }); const data = await response.json(); if (data.error) { throw new Error(`Jito API error: ${data.error.message}`); } const bundleStatus = data.result?.value?.[0]; return { bundleId, status: bundleStatus?.confirmation_status || 'unknown', signatures: bundleStatus?.transactions || [], error: bundleStatus?.err || null }; } catch (error) { console.error('Failed to get bundle status:', error); throw error; } } /** * Create tip transaction for Jito bundle * @private */ async createTipTransaction(tipLamports) { const wallet = this.ensureWallet(); // Select random tip account const tipAccountIndex = Math.floor(Math.random() * this.JITO_TIP_ACCOUNTS.length); const tipAccountString = this.JITO_TIP_ACCOUNTS[tipAccountIndex]; const tipAccount = new web3_js.PublicKey(tipAccountString); const tipInstruction = web3_js.SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: tipAccount, lamports: tipLamports }); return { transaction: new web3_js.Transaction().add(tipInstruction), description: `Jito tip: ${tipLamports} lamports` }; } /** * Submit bundle to Jito * @private */ async submitToJito(transactions) { try { // Serialize transactions const serializedTxs = transactions.map(tx => { const serialized = tx.transaction.serialize(); return Array.from(serialized); }); const response = await fetch(this.jitoRpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'sendBundle', params: [serializedTxs] }) }); const data = await response.json(); if (data.error) { throw new Error(`Jito submission failed: ${data.error.message}`); } // Extract signatures from transactions const signatures = transactions.map(tx => { const signature = tx.transaction.signature; return signature ? Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join('') : 'unknown'; }); return { bundleId: data.result, signatures, status: 'pending' }; } catch (error) { console.error('Jito submission error:', error); throw error; } } /** * Submit a bundle of transactions to Jito * * @param {Object[]|Object} transactions - Transactions to bundle * @param {Object} wallet - Wallet to use for signing * @param {Object} [options] - Additional options * @returns {Promise<string>} Bundle ID * * @example * ```javascript * const bundleId = await client.jitoBundles.submit([ * { * transaction: sendMessageTx, * description: 'Send message to agent' * } * ], wallet); * ``` */ async submit(transactions, wallet, options = {}) { // Delegate to sendBundle method for now this.setWallet(wallet); const config = { tipLamports: 10000, ...options }; const result = await this.sendBundle(Array.isArray(transactions) ? transactions : [transactions], config); return result.bundleId; } /** * Submit a transaction bundle with optional signers * * @param {Object[]} transactions - Array of transaction objects * @param {Object} transactions[].transaction - Transaction to include * @param {Object[]} [transactions[].signers] - Optional signers * @param {string} [transactions[].description] - Transaction description * @param {Object} wallet - Wallet for signing * @param {Object} [options] - Additional options * @returns {Promise<string>} Bundle ID */ async submitBundle(transactions, wallet, options = {}) { this.setWallet(wallet); const config = { tipLamports: 10000, ...options }; const result = await this.sendBundle(transactions, config); return result.bundleId; } /** * Create an optimized message bundle * * @param {Object[]} messageInstructions - Message instructions * @param {Object} wallet - Wallet for signing * @param {Object} [options] - Bundle options * @returns {Promise<Object[]>} Array of bundled transactions */ async createMessageBundle(messageInstructions, wallet, options = {}) { this.setWallet(wallet); const config = { tipLamports: 10000, ...options }; const result = await this.sendMessagingBundle(messageInstructions, config); return [result]; // Return as array of bundled transactions } /** * Create an optimized channel bundle * * @param {Object[]} channelInstructions - Channel instructions * @param {Object} wallet - Wallet for signing * @param {Object} [options] - Bundle options * @returns {Promise<Object[]>} Array of bundled transactions */ async createChannelBundle(channelInstructions, wallet, options = {}) { this.setWallet(wallet); const config = { tipLamports: 15000, ...options }; const result = await this.sendChannelBundle(channelInstructions, config); return [result]; // Return as array of bundled transactions } /** * Cleanup resources */ async cleanup() { if (this.bundleTimeouts) { this.bundleTimeouts.clear(); } this.wallet = null; } } /** * Session Keys Service for PoD Protocol JavaScript SDK * * Provides ephemeral key management for seamless AI agent interactions * Based on Gum session keys protocol */ /** * Service for managing session keys for AI agent interactions * * @class SessionKeysService * @extends BaseService */ class SessionKeysService extends base.BaseService { constructor(config) { super(config); this.sessions = new Map(); this.wallet = null; } /** * Set the wallet for this service * * @param {Object} wallet - Wallet to use for signing */ setWallet(wallet) { this.wallet = wallet; } /** * Ensure wallet is set * @private */ ensureWallet() { if (!this.wallet) { throw new Error('Wallet not set. Call setWallet() first.'); } return this.wallet; } /** * Send a transaction with proper signing * @private */ async sendTransaction(transaction, signers = []) { const wallet = this.ensureWallet(); const { blockhash } = await this.connection.getLatestBlockhash().send(); transaction.recentBlockhash = blockhash; transaction.feePayer = wallet.publicKey; // Sign with provided signers if (signers.length > 0) { transaction.partialSign(...signers); } // Sign with wallet if (wallet.signTransaction && typeof wallet.signTransaction === 'function') { transaction = await wallet.signTransaction(transaction); } else { transaction.partialSign(wallet); } const signature = await this.connection.sendRawTransaction(transaction.serialize()); await this.connection.confirmTransaction(signature); return signature; } /** * Create a session key for temporary AI agent operations * * @param {Object} config - Session configuration * @param {Object[]} config.targetPrograms - Programs this session can interact with * @param {number} [config.durationHours=24] - Session duration in hours * @param {Object[]} config.allowedInstructions - Allowed instruction types * @param {Object} [config.restrictions] - Additional restrictions * @returns {Promise<Object>} Session key data with pubkey and token * * @example * ```javascript * const sessionKey = await client.sessionKeys.createSessionKey({ * targetPrograms: [programId], * durationHours: 12, * allowedInstructions: ['sendMessage', 'updateStatus'] * }); * ``` */ async createSessionKey(config) { if (!this.isInitialized()) { throw new Error('Service not initialized. Call client.initialize() first.'); } try { // Generate ephemeral keypair const sessionKeyPairSigner = web3_js.Keypair.generate(); // Use Keypair from @solana/web3.js // Create session token account (PDA) const wallet = this.ensureWallet(); const programIdPubkey = new web3_js.PublicKey(this.programId); // Convert string to PublicKey const [sessionTokenAccount] = web3_js.PublicKey.findProgramAddressSync( [ Buffer.from('session_token'), wallet.publicKey.toBuffer(), sessionKeyPairSigner.publicKey.toBuffer() ], programIdPubkey ); // Calculate expiration timestamp const durationMs = (config.durationHours || 24) * 60 * 60 * 1000; const expiresAt = Math.floor((Date.now() + durationMs) / 1000); // Create session token const createSessionInstruction = await this.program.methods .createSessionToken( new anchor.BN(expiresAt), config.targetPrograms.map(p => new web3_js.PublicKey(p)), config.allowedInstructions ) .accounts({ sessionToken: sessionTokenAccount, sessionKey: sessionKeyPairSigner.publicKey, authority: wallet.publicKey, systemProgram: web3_js.SystemProgram.programId }) .instruction(); // Sign and send transaction const transaction = new web3_js.Transaction().add(createSessionInstruction); const { blockhash } = await this.connection.getLatestBlockhash().send(); transaction.recentBlockhash = blockhash; transaction.feePayer = wallet.publicKey; // Sign with both wallet and session key transaction.partialSign(sessionKeyPairSigner); if (wallet.signTransaction) { const signedTx = await wallet.signTransaction(transaction); const signature = await this.connection.sendRawTransaction(signedTx.serialize()).send(); await this.connection.confirmTransaction(signature).send(); } else { transaction.partialSign(wallet); const signature = await this.connection.sendRawTransaction(transaction.serialize()).send(); await this.connection.confirmTransaction(signature).send(); } return { sessionKey: sessionKeyPairSigner.publicKey.toBase58(), sessionToken: sessionTokenAccount.toBase58(), expiresAt, restrictions: config.restrictions || {}, keypair: sessionKeyPairSigner // For internal use }; } catch (error) { console.error('Failed to create session key:', error); throw error; } } /** * Execute instructions using a session key * * @param {Object[]} instructions - Instructions to execute * @param {string} sessionKey - Session key public key * @param {Object} [options] - Execution options * @returns {Promise<string>} Transaction signature * * @example * ```javascript * const signature = await client.sessionKeys.useSessionKey([ * sendMessageInstruction * ], sessionKey.sessionKey); * ``` */ async useSessionKey(instructions, sessionKey, options = {}) { const session = this.sessions.get(sessionKey); if (!session) { throw new Error(`Session key not found: ${sessionKey}`); } // Validate session is still valid if (Date.now() > session.config.expiryTime) { throw new Error('Session key has expired'); } if (session.usesRemaining !== undefined && session.usesRemaining <= 0) { throw new Error('Session key has no remaining uses'); } try { // Validate instructions are allowed for (const instruction of instructions) { if (!this.isInstructionAllowed(instruction, session.config)) { throw new Error(`Instruction not allowed for this session: ${instruction.programId}`); } } // Create transaction with session key const transaction = new web3_js.Transaction().add(...instructions); const signature = await this.sendTransaction(transaction, [session.sessionKeyPairSigner]); // Decrement uses if (session.usesRemaining !== undefined) { session.usesRemaining--; } console.log(`Session transaction sent: ${signature}`); return signature; } catch (error) { console.error('Failed to use session key:', error); throw error; } } /** * Revoke a session key * * @param {string} sessionId - Session key ID to revoke * @returns {Promise<string>} Transaction signature * * @example * ```javascript * await client.sessionKeys.revokeSessionKey(sessionId); * ``` */ async revokeSessionKey(sessionId) { const session = this.sessions.get(sessionId); if (!session) { throw new Error(`Session key not found: ${sessionId}`); } try { // Create revoke instruction const instruction = await this.createRevokeSessionInstruction( session.sessionTokenAccount ); const transaction = new web3_js.Transaction().add(instruction); const signature = await this.sendTransaction(transaction); // Remove from local storage this.sessions.delete(sessionId); console.log(`Session key revoked: ${sessionId}`); return signature; } catch (error) { console.error('Failed to revoke session key:', error); throw error; } } /** * Get all active sessions * * @returns {Object[]} Array of active session tokens * * @example * ```javascript * const activeSessions = client.sessionKeys.getActiveSessions(); * console.log(`Active sessions: ${activeSessions.length}`); * ``` */ getActiveSessions() { const now = Date.now(); return Array.from(this.sessions.values()).filter(session => session.config.expiryTime > now && (session.usesRemaining === undefined || session.usesRemaining > 0) ); } /** * Create a pre-configured session for messaging operations * * @param {number} [durationHours=24] - Session duration in hours * @returns {Promise<Object>} Session token for messaging * * @example * ```javascript * const messagingSession = await client.sessionKeys.createMessagingSession(48); * ``` */ async createMessagingSession(durationHours = 24) { const config = { targetPrograms: [this.programId], expiryTime: Date.now() + (durationHours * 60 * 60 * 1000), maxUses: 1000, allowedInstructions: [ 'send_message', 'update_message_status', 'broadcast_message' ] }; return this.createSessionKey(config); } /** * Create revoke session instruction * @private */ async createRevokeSessionInstruction(sessionTokenAccount) { if (!this.program) { throw new Error('Program not initialized'); } return this.program.methods .revokeSessionToken() .accounts({ sessionTokenAccount, authority: this.wallet.publicKey }) .instruction(); } /** * Check if instruction is allowed for session * @private */ isInstructionAllowed(instruction, config) { // Check if program is in target programs const programAllowed = config.targetPrograms.some(program => program.equals(instruction.programId) ); if (!programAllowed) { return false; } // If no specific instructions are specified, allow all for target programs if (!config.allowedInstructions || config.allowedInstructions.length === 0) { return true; } // Check specific instruction (would need to decode instruction data) // For now, we'll assume allowed if program is allowed return true; } /** * Cleanup resources */ async cleanup() { // Clear stored session keys this.wallet = null; } } /** * Comprehensive utilities for PoD Protocol JavaScript SDK * This file provides feature parity with the TypeScript SDK */ /** * Validates and normalizes client configuration * @param {Object} config - Configuration object * @returns {Object} Validated configuration */ function validateConfig(config = {}) { const validated = { endpoint: config.endpoint || 'https://api.devnet.solana.com', commitment: config.commitment || 'confirmed', programId: config.programId, ipfs: config.ipfs || {}, zkCompression: config.zkCompression || {}, jitoRpcUrl: config.jitoRpcUrl }; // Validate endpoint format if (typeof validated.endpoint !== 'string' || !validated.endpoint.startsWith('http')) { throw new Error('Invalid RPC endpoint format'); } // Validate commitment level const validCommitments = ['processed', 'confirmed', 'finalized']; if (!validCommitments.includes(validated.commitment)) { throw new Error(`Invalid commitment level. Must be one of: ${validCommitments.join(', ')}`); } return validated; } /** * Loads program IDL with fallback support * @param {string} programId - Program ID * @returns {Promise<Object>} Program IDL */ async function loadIDL(programId) { try { // Try to load IDL from multiple sources if (typeof window === 'undefined') { // Node.js environment try { const fs = await import('fs'); const path = await import('path'); const { fileURLToPath } = await import('url'); const __filename = fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href))); const __dirname = path.dirname(__filename); const idlPath = path.join(__dirname, '..', '..', 'pod_com.json'); if (fs.existsSync(idlPath)) { const idlData = fs.readFileSync(idlPath, 'utf8'); return JSON.parse(idlData); } } catch (fsError) { console.warn('Could not load IDL from file system:', fsError.message); } } // Fallback: Create a minimal IDL structure for basic functionality return createMinimalIDL(); } catch (error) { console.warn('Failed to load IDL, using minimal fallback:', error); return createMinimalIDL(); } } /** * Creates a minimal IDL for basic functionality * @returns {Object} Minimal IDL structure */ function createMinimalIDL() { return { version: "1.0.0", name: "pod_com", instructions: [ { name: "registerAgent", accounts: [ { name: "agentAccount", isMut: true, isSigner: false }, { name: "signer", isMut: true, isSigner: true }, { name: "systemProgram", isMut: false, isSigner: false } ], args: [ { name: "capabilities", type: "u32" }, { name: "metadataUri", type: "string" } ] }, { name: "updateAgent", accounts: [ { name: "agentAccount", isMut: true, isSigner: false }, { name: "signer", isMut: true, isSigner: true } ], args: [ { name: "capabilities", type: { option: "u32" } }, { name: "metadataUri", type: { option: "string" } } ] }, { name: "sendMessage", accounts: [ { name: "messageAccount", isMut: true, isSigner: false }, { name: "sender", isMut: true, isSigner: true }, { name: "recipient", isMut: false, isSigner: false }, { name: "systemProgram", isMut: false, isSigner: false } ], args: [ { name: "payloadHash", type: { array: ["u8", 32] } }, { name: "payload", type: "string" }, { name: "messageType", type: "u8" }, { name: "expiresAt", type: "i64" } ] }, { name: "updateMessageStatus", accounts: [ { name: "messageAccount", isMut: true, isSigner: false }, { name: "signer", isMut: true, isSigner: true } ], args: [ { name: "status", type: "string" } ] }, { name: "createChannel", accounts: [ { name: "channelAccount", isMut: true, isSigner: false }, { name: "creator", isMut: true, isSigner: true }, { name: "systemProgram", isMut: false, isSigner: false } ], args: [ { name: "name", type: "string" }, { name: "description", type: "string" }, { name: "visibility", type: "u8" }, { name: "maxMembers", type: "u32" } ] } ], accounts: [ { name: "AgentAccount", type: { kind: "struct", fields: [ { name: "capabilities", type: "u32" }, { name: "metadataUri", type: "string" }, { name: "reputation", type: "u32" }, { name: "lastUpdated", type: "i64" }, { name: "invitesSent", type: "u32" }, { name: "lastInviteAt", type: "i64" }, { name: "bump", type: "u8" } ] } }, { name: "MessageAccount", type: { kind: "struct", fields: [ { name: "sender", type: "publicKey" }, { name: "recipient", type: "publicKey" }, { name: "payloadHash", type: { array: ["u8", 32] } }, { name: "payload", type: "string" }, { name: "messageType", type: "u8" }, { name: "timestamp", type: "i64" }, { name: "expiresAt", type: "i64" }, { name: "status", type: "string" }, { name: "bump", type: "u8" } ] } }, { name: "ChannelAccount", type: { kind: "struct", fields: [ { name: "name", type: "string" }, { name: "description", type: "string" }, { name: "creator", type: "publicKey" }, { name: "visibility", type: "u8" }, { name: "maxMembers", type: "u32" }, { name: "memberCount", type: "u32" }, { name: "lastUpdated", type: "i64" }, { name: "bump", type: "u8" } ] } } ], errors: [ { code: 6000, name: "InvalidMetadataUriLength", msg: "Invalid metadata URI length" }, { code: 6001, name: "Unauthorized", msg: "Unauthorized operation" }, { code: 6002, name: "MessageExpired", msg: "Message has expired" }, { code: 6003, name: "InvalidMessageStatusTransition", msg: "Invalid message status transition" }, { code: 6004, name: "InsufficientAccounts", msg: "Insufficient accounts provided" }, { code: 6005, name: "InvalidAccountData", msg: "Invalid account data" }, { code: 6006, name: "InvalidInstructionData", msg: "Invalid instruction data" } ] }; } /** * Main entry point for PoD Protocol JavaScript SDK * * @fileoverview Provides a complete JavaScript SDK for interacting with the PoD Protocol * Compatible with Web3.js v2.0 and legacy Anchor patterns */ /** * Main client for interacting with PoD Protocol */ class PodProtocolClient { /** * @param {Object} config - Configuration options * @param {string} [config.endpoint='https://api.devnet.solana.com'] - Solana RPC endpoint * @param {string} [config.programId] - Program ID (auto-detected if not provided) * @param {string} [config.commitment='confirmed'] - Transaction commitment level * @param {Object} [config.ipfs] - IPFS configuration * @param {Object} [config.zkCompression] - ZK compression configuration * @param {string} [config.jitoRpcUrl] - Jito RPC URL for bundle transactions */ constructor(config = {}) { // Validate and set default configuration this.config = validateConfig(config); this.endpoint = this.config.endpoint || 'https://api.devnet.solana.com'; this.programId = this.config.programId || 'PoD1234567890123456789012345678901234567890'; this.commitment = this.config.commitment || 'confirmed'; // Create legacy connection for Anchor compatibility this.connection = new web3_js.Connection(this.endpoint, { commitment: this.commitment, }); // Create service configuration const serviceConfig = { connection: this.connection, programId: this.programId, commitment: this.commitment, }; // Initialize services this.agent = new services_agent.AgentService(serviceConfig); this.message = new services_message.MessageService(serviceConfig); this.channel = new services_channel.ChannelService(serviceConfig); this.escrow = new services_escrow.EscrowService(serviceConfig); this.analytics = new services_analytics.AnalyticsService(serviceConfig); this.discovery = new services_discovery.DiscoveryService(serviceConfig); this.ipfs = new services_ipfs.IPFSService(this.config.ipfs); this.zkCompression = new services_zkCompression.ZKCompressionService(serviceConfig, this.config.zkCompression); this.jitoBundles = new JitoBundlesService(serviceConfig, this.config.jitoRpcUrl); this.sessionKeys = new SessionKeysService(serviceConfig); // Initialize program this.program = null; this.wallet = null; } /** * Initialize the client with a wallet * @param {Object} wallet - Solana wallet or keypair * @returns {Promise<void>} */ async initialize(wallet) { if (!wallet) { throw new Error('Wallet is required for initialization'); } this.wallet = wallet; try { // Load program IDL const idl = await loadIDL(this.programId); // Create provider with proper connection const provider = new anchor.AnchorProvider( this.connection, wallet, { commitment: this.commitment, preflightCommitment: this.commitment, } ); // Initialize program this.program = new anchor.Program(idl, provider); // Set program reference for all services this.agent.setProgram?.(this.program); this.message.setProgram?.(this.program); this.channel.setProgram?.(this.program); this.escrow.setProgram?.(this.program); this.analytics.setProgram?.(this.program); this.discovery.setProgram?.(this.program); this.zkCompression.setProgram?.(this.program); this.jitoBundles.setProgram?.(this.program); this.sessionKeys.setProgram?.(this.program); console.log('✅ PoD Protocol client initialized successfully'); } catch (error) { console.error('❌ Failed to initialize PoD Protocol client:', error); throw error; } } /** * Get the current Solana connection * @returns {Connection} Solana connection */ getConnection() { return this.connection; } /** * Get the current program instance * @returns {Program|null} Anchor program instance */ getProgram() { return this.program; } /** * Clean up resources * @returns {Promise<void>} */ async cleanup() { // Cleanup all services await Promise.all([ this.agent.cleanup?.(), this.message.cleanup?.(), this.channel.cleanup?.(), this.escrow.cleanup?.(), this.analytics.cleanup?.(), this.discovery.cleanup?.(), this.ipfs.cleanup?.(), this.zkCompression.cleanup?.(), this.jitoBundles.cleanup?.(), this.sessionKeys.cleanup?.(), ]); } } // Legacy export for backward compatibility const PodComClient = PodProtocolClient; exports.AgentService = services_agent.AgentService; exports.MessageService = services_message.MessageService; exports.ChannelService = services_channel.ChannelService; exports.EscrowService = services_escrow.EscrowService; exports.AnalyticsService = services_analytics.AnalyticsService; exports.DiscoveryService = services_discovery.DiscoveryService; exports.IPFSService = services_ipfs.IPFSService; exports.ZKCompressionService = services_zkCompression.ZKCompressionService; exports.AGENT_CAPABILITIES = types.AGENT_CAPABILITIES; exports.ChannelVisibility = types.ChannelVisibility; exports.MessageStatus = types.MessageStatus; exports.MessageType = types.MessageType; exports.PROGRAM_ID = types.PROGRAM_ID; exports.PodComError = types.PodComError; exports.JitoBundlesService = JitoBundlesService; exports.PodComClient = PodComClient; exports.PodProtocolClient = PodProtocolClient; exports.SessionKeysService = SessionKeysService; exports.default = PodProtocolClient; //# sourceMappingURL=index.js.map