The Cycles Plugin provides comprehensive cycles management for Internet Computer canisters, including balance monitoring, top-ups, transfers, and automated alerts.

Quick Start

import { ICPAgent } from 'icp-agent-kit';

const agent = new ICPAgent({ network: 'local' });

// Get cycles balance
const balance = await agent.cyclesPlugin.getBalance('rdmx6-jaaaa-aaaaa-aaadq-cai');
console.log(`Balance: ${agent.cyclesPlugin.formatCycles(balance.balance)}`);

// Top up a canister
await agent.cyclesPlugin.topUp('rdmx6-jaaaa-aaaaa-aaadq-cai', '2T');

// Transfer cycles between canisters
await agent.cyclesPlugin.transfer({
  from: 'rdmx6-jaaaa-aaaaa-aaadq-cai',
  to: 'rrkah-fqaaa-aaaaa-aaaaq-cai',
  amount: BigInt(1_000_000_000_000) // 1T cycles
});

Core Operations

Balance Management

// Get detailed balance information
const balance = await agent.cyclesPlugin.getBalance('canister-id');
console.log({
  balance: balance.balance,
  freezingThreshold: balance.freezingThreshold,
  memoryUsage: balance.memoryUsage,
  estimatedDaysUntilFrozen: balance.estimatedDaysUntilFrozen
});

// Check multiple canisters at once
const balances = await agent.cyclesPlugin.getBatchBalances([
  'canister-1',
  'canister-2',
  'canister-3'
]);

Top-up Operations

// Top up with different amount formats
await agent.cyclesPlugin.topUp('canister-id', '2T');         // 2 trillion cycles
await agent.cyclesPlugin.topUp('canister-id', '500GC');      // 500 billion cycles
await agent.cyclesPlugin.topUp('canister-id', BigInt(1e12)); // 1 trillion cycles

// Batch top-up multiple canisters
const results = await agent.cyclesPlugin.batchTopUp([
  { canisterId: 'canister-1', amount: '1T' },
  { canisterId: 'canister-2', amount: '2T' },
  { canisterId: 'canister-3', amount: '500GC' }
]);

// Check results
results.forEach(result => {
  if (result.success) {
    console.log(`✓ ${result.canisterId} topped up successfully`);
  } else {
    console.log(`✗ ${result.canisterId} failed: ${result.error}`);
  }
});

ICP to Cycles Conversion

// Convert ICP to cycles
const conversion = await agent.cyclesPlugin.convertIcpToCycles(
  BigInt(100_000_000), // 1 ICP (in e8s)
  {
    targetCanister: 'canister-id', // Optional: auto top-up target
    xdrRate: 5.0 // Optional: custom XDR rate
  }
);

console.log({
  icpUsed: conversion.icpUsed,
  cyclesReceived: conversion.cyclesReceived,
  conversionRate: conversion.conversionRate,
  transactionId: conversion.transactionId
});

// Get current pricing information
const pricing = await agent.cyclesPlugin.getPricing();
console.log({
  xdrToCycles: pricing.xdrToCycles,
  icpToXdr: pricing.icpToXdr,
  icpToCycles: pricing.icpToCycles
});

Monitoring and Analytics

Usage Metrics

// Get usage metrics for different time periods
const dailyMetrics = await agent.cyclesPlugin.getUsageMetrics('canister-id', 'day');
const weeklyMetrics = await agent.cyclesPlugin.getUsageMetrics('canister-id', 'week');

dailyMetrics.forEach(metric => {
  console.log({
    period: metric.period,
    totalConsumed: metric.totalConsumed,
    computeCycles: metric.computeCycles,
    memoryCycles: metric.memoryCycles,
    networkCycles: metric.networkCycles,
    averageConsumptionRate: metric.averageConsumptionRate
  });
});

// Get consumption forecast
const forecast = await agent.cyclesPlugin.getForecast('canister-id');
console.log({
  currentBalance: forecast.currentBalance,
  daysUntilDepletion: forecast.daysUntilDepletion,
  depletionDate: forecast.depletionDate,
  recommendedTopUp: forecast.recommendedTopUp,
  confidence: forecast.confidence
});

Automated Monitoring

// Start monitoring canisters for low cycles
await agent.cyclesPlugin.startMonitoring({
  canisterIds: ['canister-1', 'canister-2'],
  lowBalanceThreshold: BigInt(1_000_000_000_000), // 1T cycles
  checkInterval: 300, // Check every 5 minutes
  autoTopUp: {
    enabled: true,
    topUpAmount: BigInt(2_000_000_000_000), // 2T cycles
    maxTopUpsPerDay: 3
  }
});

// Check for alerts
const alerts = agent.cyclesPlugin.getAlerts();
alerts.forEach(alert => {
  console.log({
    type: alert.type,
    severity: alert.severity,
    canisterId: alert.canisterId.toText(),
    message: alert.message,
    currentBalance: alert.currentBalance,
    timestamp: alert.timestamp
  });
});

// Stop monitoring
agent.cyclesPlugin.stopMonitoring();

// Clear all alerts
agent.cyclesPlugin.clearAlerts();

Utility Functions

Amount Formatting and Parsing

// Format cycles for display
const formatted = agent.cyclesPlugin.formatCycles(BigInt(2_500_000_000_000));
console.log(formatted); // "2.500 TC"

// Parse cycles from strings
const amount = agent.cyclesPlugin.parseCycles('1.5T');
console.log(amount); // 1500000000000n

// Validate amounts
const isValid = agent.cyclesPlugin.validateAmount('2T');
console.log(isValid); // 2000000000000n (throws error if invalid)

// Check if canister exists
const exists = await agent.cyclesPlugin.canisterExists('canister-id');
console.log(exists); // true/false

Balance Summary

// Get formatted balance summary
const summary = await agent.cyclesPlugin.getBalanceSummary('canister-id');
console.log(summary);
/*
Canister: rdmx6-jaaaa-aaaaa-aaadq-cai
Balance: 2.500 TC
Status: healthy (Cycles balance is healthy)
Memory Usage: 1.50 MB
Daily Consumption: 127.00 GC
Estimated Days Until Depletion: 19
*/

// Estimate future consumption
const estimatedConsumption = await agent.cyclesPlugin.estimateConsumption('canister-id', 30);
console.log(`30-day estimate: ${agent.cyclesPlugin.formatCycles(estimatedConsumption)}`);

Cycles Ledger Integration

The plugin includes integration with the cycles ledger for advanced operations:
import { CyclesLedgerClient } from 'icp-agent-kit/cycles/ledger';

// Create ledger client
const ledgerClient = new CyclesLedgerClient(agent.agent, {
  network: 'mainnet',
  canisterId: 'um5iw-rqaaa-aaaaq-aab2q-cai'
});

// Create account
const account = CyclesLedgerClient.createAccount(
  Principal.fromText('your-principal'),
  CyclesLedgerClient.createDefaultSubaccount()
);

// Get ledger balance
const ledgerBalance = await ledgerClient.getBalance(account);

// Transfer via ledger
const transferResult = await ledgerClient.transfer({
  to: account,
  amount: BigInt(1_000_000_000_000),
  memo: new TextEncoder().encode('Transfer memo')
});

// Get transaction history
const transactions = await ledgerClient.getTransactions({
  start: 0n,
  length: 10n
});

Error Handling

import { ICPAgentError } from 'icp-agent-kit';

try {
  await agent.cyclesPlugin.topUp('invalid-canister', '1T');
} catch (error) {
  if (error instanceof ICPAgentError) {
    switch (error.code) {
      case 'INSUFFICIENT_CYCLES':
        console.log('Not enough cycles for operation');
        break;
      case 'INVALID_CANISTER_ID':
        console.log('Invalid canister ID format');
        break;
      case 'AMOUNT_TOO_SMALL':
        console.log('Amount below minimum required');
        break;
      case 'NETWORK_ERROR':
        console.log('Network connectivity issue');
        break;
      default:
        console.log(`Unexpected error: ${error.message}`);
    }
  }
}

Configuration

// The cycles plugin is automatically loaded with default settings
const agent = new ICPAgent({
  network: 'mainnet', // or 'local'
  // Plugin will use appropriate canister IDs for the network
});

// Access plugin methods directly
const balance = await agent.cyclesPlugin.getBalance('canister-id');

Amount Units

The plugin supports these cycle units:
  • C - Cycles (1)
  • KC - Kilo Cycles (1,000)
  • MC - Mega Cycles (1,000,000)
  • GC - Giga Cycles (1,000,000,000)
  • TC - Tera Cycles (1,000,000,000,000)
Examples:
  • '1T' = 1,000,000,000,000 cycles
  • '500GC' = 500,000,000,000 cycles
  • '2.5T' = 2,500,000,000,000 cycles

Network Support

The plugin automatically configures canister IDs based on network:
  • Mainnet: Production cycles ledger and minting canisters
  • Local: Local development replica canisters
  • IC: Alias for mainnet
Custom canister IDs can be configured if needed for specific deployments.