@pod-protocol/sdk-js
Version:
Pod Protocol SDK for JavaScript
1,193 lines (1,064 loc) • 38.5 kB
JavaScript
import { AgentService } from './services/agent.esm.js';
import { MessageService } from './services/message.esm.js';
import { ChannelService } from './services/channel.esm.js';
import { EscrowService } from './services/escrow.esm.js';
import { AnalyticsService } from './services/analytics.esm.js';
import { DiscoveryService } from './services/discovery.esm.js';
import { IPFSService } from './services/ipfs.esm.js';
import { ZKCompressionService } from './services/zkCompression.esm.js';
import { B as BaseService } from './base-KwxXjH0F.js';
import { ComputeBudgetProgram, Transaction, PublicKey, SystemProgram, Keypair, Connection } from '@solana/web3.js';
import { BN, AnchorProvider, Program } from '@coral-xyz/anchor';
import 'crypto-js';
export { AGENT_CAPABILITIES, ChannelVisibility, MessageStatus, MessageType, PROGRAM_ID, PodComError } from './types.esm.js';
import './utils/pda.esm.js';
import './utils/crypto.esm.js';
import 'axios';
import 'crypto';
/**
* 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 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(
ComputeBudgetProgram.setComputeUnitLimit({
units: config.computeUnits
})
);
}
if (config.priorityFee) {
computeInstructions.push(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: config.priorityFee
})
);
}
if (tx instanceof Transaction) {
tx = new Transaction().add(...computeInstructions, ...tx.instructions);
}
}
// Get recent blockhash
const { blockhash } = await this.connection.getLatestBlockhash().send();
if (tx instanceof 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 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 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 PublicKey(tipAccountString);
const tipInstruction = SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: tipAccount,
lamports: tipLamports
});
return {
transaction: new 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 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 = Keypair.generate(); // Use Keypair from @solana/web3.js
// Create session token account (PDA)
const wallet = this.ensureWallet();
const programIdPubkey = new PublicKey(this.programId); // Convert string to PublicKey
const [sessionTokenAccount] = 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 BN(expiresAt),
config.targetPrograms.map(p => new PublicKey(p)),
config.allowedInstructions
)
.accounts({
sessionToken: sessionTokenAccount,
sessionKey: sessionKeyPairSigner.publicKey,
authority: wallet.publicKey,
systemProgram: SystemProgram.programId
})
.instruction();
// Sign and send transaction
const transaction = new 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 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 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(import.meta.url);
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 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 AgentService(serviceConfig);
this.message = new MessageService(serviceConfig);
this.channel = new ChannelService(serviceConfig);
this.escrow = new EscrowService(serviceConfig);
this.analytics = new AnalyticsService(serviceConfig);
this.discovery = new DiscoveryService(serviceConfig);
this.ipfs = new IPFSService(this.config.ipfs);
this.zkCompression = new 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 AnchorProvider(
this.connection,
wallet,
{
commitment: this.commitment,
preflightCommitment: this.commitment,
}
);
// Initialize program
this.program = new 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;
export { AgentService, AnalyticsService, ChannelService, DiscoveryService, EscrowService, IPFSService, JitoBundlesService, MessageService, PodComClient, PodProtocolClient, SessionKeysService, ZKCompressionService, PodProtocolClient as default };
//# sourceMappingURL=index.esm.js.map