SDK
Code Examples

Code Examples

Real-world code examples for common use cases with the Aegis SDK.

Basic Vault Operations

Create and Fund a Vault

import { AegisClient } from '@aegis-vaults/sdk';
import { Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js';
 
async function setupVault() {
  // Initialize client
  const client = new AegisClient({
    cluster: 'devnet',
    guardianApiUrl: 'https://aegis-guardian-production.up.railway.app',
  });
 
  // Load owner wallet
  const ownerKeypair = Keypair.fromSecretKey(/* secret key */);
 
  // Wrap keypair in Wallet before passing to client
  const { Wallet } = await import('@coral-xyz/anchor');
  const ownerWallet = new Wallet(ownerKeypair);
  client.setWallet(ownerWallet);
 
  // Generate agent keypair
  const agentKeypair = Keypair.generate();
 
  // Create vault
  const vault = await client.createVault({
    name: 'Production Trading Vault',
    agentSigner: agentKeypair.publicKey.toBase58(),
    dailyLimit: 10 * LAMPORTS_PER_SOL, // 10 SOL per day
  });
 
  console.log('✅ Vault created');
  console.log('Address:', vault.vaultAddress);
  console.log('Deposit:', vault.depositAddress);
  console.log('Nonce:', vault.nonce);
 
  // Fund vault (using Solana web3.js)
  const { SystemProgram, Transaction, sendAndConfirmTransaction } = await import('@solana/web3.js');
 
  const fundTx = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey: ownerKeypair.publicKey,
      toPubkey: new PublicKey(vault.depositAddress),
      lamports: 50 * LAMPORTS_PER_SOL, // 50 SOL
    })
  );
 
  const signature = await sendAndConfirmTransaction(
    client.connection,
    fundTx,
    [ownerKeypair]
  );
 
  console.log('✅ Vault funded:', signature);
 
  return { vault, agentKeypair };
}

Configure Vault Policies

async function configureVault(vaultAddress: string, vaultNonce: string, ownerKeypair: Keypair) {
  const client = new AegisClient({ cluster: 'devnet' });
 
  // Wrap keypair in Wallet before passing to client
  const { Wallet } = await import('@coral-xyz/anchor');
  const ownerWallet = new Wallet(ownerKeypair);
  client.setWallet(ownerWallet);
 
  // Add recipients to whitelist
  const recipients = [
    'JUPITER_PROGRAM_ID',
    'ORCA_PROGRAM_ID',
    'RAYDIUM_PROGRAM_ID',
    'VENDOR_WALLET_1',
    'VENDOR_WALLET_2',
  ];
 
  for (const recipient of recipients) {
    await client.addToWhitelist(vaultAddress, vaultNonce, recipient);
    console.log('✅ Whitelisted:', recipient);
  }
 
  // Update daily limit
  await client.updatePolicy({
    vault: vaultAddress,
    dailyLimit: 20 * LAMPORTS_PER_SOL, // 20 SOL per day
  });
 
  console.log('✅ Daily limit updated');
}

AI Agent Integration

Simple Payment Agent

import { AegisClient, DailyLimitExceededError, NotWhitelistedError } from '@aegis-vaults/sdk';
 
class PaymentAgent {
  private client: AegisClient;
  private vaultAddress: string;
  private vaultNonce: string;
 
  constructor(agentKeypair: Keypair) {
    this.client = new AegisClient({
      cluster: 'devnet',
      guardianApiUrl: 'https://aegis-guardian-production.up.railway.app',
      autoRequestOverride: true,
    });
 
    // Wrap agent keypair in Wallet before passing to client
    const { Wallet } = require('@coral-xyz/anchor');
    const agentWallet = new Wallet(agentKeypair);
    this.client.setWallet(agentWallet);
    this.vaultAddress = process.env.VAULT_ADDRESS!;
    this.vaultNonce = process.env.VAULT_NONCE!;
  }
 
  async sendPayment(recipient: string, amountSOL: number, purpose: string) {
    try {
      console.log(`Sending ${amountSOL} SOL to ${recipient}...`);
 
      const signature = await this.client.executeAgent({
        vault: this.vaultAddress,
        destination: recipient,
        amount: Math.floor(amountSOL * LAMPORTS_PER_SOL),
        vaultNonce: this.vaultNonce,
        purpose,
      });
 
      console.log('✅ Payment successful:', signature);
      return { success: true, signature };
 
    } catch (error: any) {
      if (error instanceof NotWhitelistedError) {
        console.log('⚠️ Recipient not whitelisted. Requesting override...');
        return { success: false, reason: 'not_whitelisted', blinkUrl: error.blinkUrl };
 
      } else if (error instanceof DailyLimitExceededError) {
        console.log('⚠️ Daily limit exceeded. Requesting override...');
        return { success: false, reason: 'limit_exceeded', blinkUrl: error.blinkUrl };
 
      } else {
        console.error('❌ Payment failed:', error.message);
        throw error;
      }
    }
  }
 
  async getVaultStatus() {
    const vault = await this.client.getVault(this.vaultAddress);
    const balance = await this.client.getVaultBalance(this.vaultAddress);
 
    return {
      balance: balance / LAMPORTS_PER_SOL,
      dailyLimit: vault.dailyLimit.toNumber() / LAMPORTS_PER_SOL,
      spentToday: vault.spentToday.toNumber() / LAMPORTS_PER_SOL,
      remaining: (vault.dailyLimit.toNumber() - vault.spentToday.toNumber()) / LAMPORTS_PER_SOL,
      paused: vault.paused,
    };
  }
}
 
// Usage
const agent = new PaymentAgent(agentKeypair);
 
await agent.sendPayment(
  'RECIPIENT_ADDRESS',
  0.1,
  'Payment for API subscription'
);
 
const status = await agent.getVaultStatus();
console.log('Vault Status:', status);

Batch Payment Processing

async function processBatchPayments(
  client: AegisClient,
  payments: Array<{ recipient: string; amount: number; purpose: string }>
) {
  const results = [];
 
  for (const payment of payments) {
    try {
      const signature = await client.executeAgent({
        vault: process.env.VAULT_ADDRESS!,
        destination: payment.recipient,
        amount: payment.amount,
        vaultNonce: process.env.VAULT_NONCE!,
        purpose: payment.purpose,
      });
 
      results.push({
        ...payment,
        status: 'success',
        signature,
      });
 
      // Small delay to avoid rate limits
      await new Promise(resolve => setTimeout(resolve, 1000));
 
    } catch (error: any) {
      results.push({
        ...payment,
        status: 'failed',
        error: error.message,
        blinkUrl: error.blinkUrl,
      });
    }
  }
 
  return results;
}
 
// Usage
const payments = [
  { recipient: 'ADDR_1', amount: 10_000_000, purpose: 'Invoice #001' },
  { recipient: 'ADDR_2', amount: 20_000_000, purpose: 'Invoice #002' },
  { recipient: 'ADDR_3', amount: 15_000_000, purpose: 'Invoice #003' },
];
 
const results = await processBatchPayments(client, payments);
 
console.log('Successful:', results.filter(r => r.status === 'success').length);
console.log('Failed:', results.filter(r => r.status === 'failed').length);

Transaction Monitoring

Real-time Vault Monitor

import { AegisClient } from '@aegis-vaults/sdk';
 
class VaultMonitor {
  private client: AegisClient;
  private vaultAddress: string;
  private checkInterval: NodeJS.Timeout | null = null;
 
  constructor(vaultAddress: string) {
    this.client = new AegisClient({ cluster: 'devnet' });
    this.vaultAddress = vaultAddress;
  }
 
  async start(intervalMs: number = 10000) {
    console.log('🔍 Starting vault monitor...');
 
    this.checkInterval = setInterval(async () => {
      await this.checkVault();
    }, intervalMs);
 
    // Initial check
    await this.checkVault();
  }
 
  stop() {
    if (this.checkInterval) {
      clearInterval(this.checkInterval);
      console.log('⏹️  Monitor stopped');
    }
  }
 
  private async checkVault() {
    try {
      const [vault, balance] = await Promise.all([
        this.client.getVault(this.vaultAddress),
        this.client.getVaultBalance(this.vaultAddress),
      ]);
 
      const status = {
        timestamp: new Date().toISOString(),
        balance: balance / LAMPORTS_PER_SOL,
        spentToday: vault.spentToday.toNumber() / LAMPORTS_PER_SOL,
        dailyLimit: vault.dailyLimit.toNumber() / LAMPORTS_PER_SOL,
        utilizationPct: (vault.spentToday.toNumber() / vault.dailyLimit.toNumber()) * 100,
        paused: vault.paused,
      };
 
      console.log('📊 Vault Status:', status);
 
      // Alerts
      if (status.balance < 1) {
        console.log('⚠️  LOW BALANCE ALERT: Less than 1 SOL remaining');
      }
 
      if (status.utilizationPct > 80) {
        console.log('⚠️  HIGH UTILIZATION: Over 80% of daily limit used');
      }
 
      if (vault.paused) {
        console.log('🛑 VAULT PAUSED: All transactions blocked');
      }
 
    } catch (error) {
      console.error('❌ Monitor error:', error);
    }
  }
}
 
// Usage
const monitor = new VaultMonitor(vaultAddress);
monitor.start(30000); // Check every 30 seconds
 
// Stop after 5 minutes
setTimeout(() => monitor.stop(), 5 * 60 * 1000);

Transaction History Analysis

async function analyzeTransactions(client: AegisClient, vaultAddress: string) {
  const history = await client.getTransactionHistory({
    vault: vaultAddress,
    limit: 1000,
  });
 
  const analysis = {
    total: history.length,
    executed: history.filter(tx => tx.status === 'executed').length,
    blocked: history.filter(tx => tx.status === 'blocked').length,
    totalVolume: history.reduce((sum, tx) => sum + parseFloat(tx.amount), 0),
    byDestination: {} as Record<string, number>,
    byDay: {} as Record<string, number>,
  };
 
  // Group by destination
  for (const tx of history) {
    if (!analysis.byDestination[tx.destination]) {
      analysis.byDestination[tx.destination] = 0;
    }
    analysis.byDestination[tx.destination] += parseFloat(tx.amount);
  }
 
  // Group by day
  for (const tx of history) {
    const day = tx.timestamp.toISOString().split('T')[0];
    if (!analysis.byDay[day]) {
      analysis.byDay[day] = 0;
    }
    analysis.byDay[day] += parseFloat(tx.amount);
  }
 
  console.log('📈 Transaction Analysis:');
  console.log('Total Transactions:', analysis.total);
  console.log('Executed:', analysis.executed);
  console.log('Blocked:', analysis.blocked);
  console.log('Total Volume:', analysis.totalVolume / 1e9, 'SOL');
 
  console.log('\nTop Recipients:');
  const topRecipients = Object.entries(analysis.byDestination)
    .sort(([, a], [, b]) => b - a)
    .slice(0, 5);
 
  for (const [address, amount] of topRecipients) {
    console.log(`${address}: ${amount / 1e9} SOL`);
  }
 
  return analysis;
}

Error Handling Patterns

Graceful Degradation

async function executeWithFallback(
  client: AegisClient,
  options: ExecuteAgentOptions
) {
  try {
    // Try main execution
    return await client.executeAgent(options);
 
  } catch (error: any) {
    if (error.overrideRequested) {
      // Override requested - notify owner
      await notifyOwner({
        type: 'override_requested',
        blinkUrl: error.blinkUrl,
        amount: options.amount,
        destination: options.destination,
      });
 
      return { status: 'pending_approval', blinkUrl: error.blinkUrl };
 
    } else if (error instanceof InsufficientBalanceError) {
      // Request vault funding
      await notifyOwner({
        type: 'low_balance',
        vaultAddress: options.vault,
      });
 
      throw new Error('Vault needs funding');
 
    } else {
      // Other errors - log and rethrow
      console.error('Transaction failed:', error);
      throw error;
    }
  }
}

Retry with Exponential Backoff

async function executeWithRetry(
  client: AegisClient,
  options: ExecuteAgentOptions,
  maxRetries: number = 3
): Promise<string> {
  let lastError;
 
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await client.executeAgent(options);
    } catch (error: any) {
      lastError = error;
 
      // Don't retry policy errors
      if (error instanceof NotWhitelistedError ||
          error instanceof DailyLimitExceededError ||
          error instanceof VaultPausedError) {
        throw error;
      }
 
      // Exponential backoff
      const delay = Math.pow(2, i) * 1000;
      console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
 
  throw lastError;
}

Pre-flight Checks

Validate Before Execution

async function canExecuteTransaction(
  client: AegisClient,
  vault: string,
  destination: string,
  amount: number
): Promise<{ canExecute: boolean; reason?: string }> {
  const vaultData = await client.getVault(vault);
  const balance = await client.getVaultBalance(vault);
 
  // Check if paused
  if (vaultData.paused) {
    return { canExecute: false, reason: 'Vault is paused' };
  }
 
  // Check balance
  if (balance < amount) {
    return { canExecute: false, reason: 'Insufficient balance' };
  }
 
  // Check whitelist
  const isWhitelisted = vaultData.whitelist
    .slice(0, vaultData.whitelistCount)
    .some(addr => addr.toBase58() === destination);
 
  if (!isWhitelisted) {
    return { canExecute: false, reason: 'Destination not whitelisted' };
  }
 
  // Check daily limit
  const remaining = vaultData.dailyLimit.sub(vaultData.spentToday);
  if (remaining.toNumber() < amount) {
    return { canExecute: false, reason: 'Would exceed daily limit' };
  }
 
  return { canExecute: true };
}
 
// Usage
const check = await canExecuteTransaction(
  client,
  vaultAddress,
  destination,
  10_000_000
);
 
if (check.canExecute) {
  await client.executeAgent({...});
} else {
  console.log('Cannot execute:', check.reason);
}

Next Steps