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
- Best Practices - Production tips
- Error Handling - Handle errors gracefully
- AI Integrations - OpenAI, LangChain, Claude