The Canister Plugin provides comprehensive canister management capabilities, including lifecycle operations, WASM deployment, method calls, and controller management.

Overview

The Canister Plugin supports:
  • Lifecycle Management: Create, start, stop, delete canisters
  • Code Deployment: Install, upgrade, uninstall WASM modules
  • Method Calls: Query and update calls with IDL support
  • Actor Creation: Direct typed actor creation
  • Controller Management: Add/remove controllers, update settings
  • Metrics Tracking: Call counts, response times, error rates

Lifecycle Operations

create(options?)

Create a new canister. Parameters:
  • options (optional): ICanisterCreateOptions
    • settings: ICanisterSettings - Initial canister settings
    • cycles: bigint | string - Initial cycles amount
Returns: Promise<{ canisterId: Principal }> - Created canister information Example:
// Create basic canister
const { canisterId } = await agent.canisterPlugin.create();

// Create with custom settings and cycles
const { canisterId: customCanister } = await agent.canisterPlugin.create({
  cycles: '5T', // 5 trillion cycles
  settings: {
    controllers: [Principal.fromText('controller-principal')],
    computeAllocation: 10,
    memoryAllocation: BigInt(1024 * 1024), // 1MB
    freezingThreshold: 2592000 // 30 days
  }
});

deploy(options)

Deploy WASM code to a canister. Parameters:
  • options: ICanisterDeployOptions
    • canisterId: Principal - Target canister ID
    • wasmModule: Uint8Array - WASM module bytes
    • installArgs: Uint8Array - Installation arguments (optional)
    • mode: 'install' | 'upgrade' | 'reinstall' - Installation mode (default: ‘install’)
Returns: Promise<IDeployResult>
  • canisterId: Principal - Deployed canister ID
  • moduleHash: string - Hash of deployed module
  • cyclesUsed: bigint - Cycles consumed during deployment
Example:
import { readFileSync } from 'fs';

// Load WASM module
const wasmModule = readFileSync('./hello-world.wasm');

// Deploy to canister
const result = await agent.canisterPlugin.deploy({
  canisterId: Principal.fromText('canister-id'),
  wasmModule,
  mode: 'install'
});

console.log('Deployed with hash:', result.moduleHash);
console.log('Cycles used:', agent.canisterPlugin.formatCycles(result.cyclesUsed));

start(canisterId)

Start a stopped canister. Parameters:
  • canisterId: Principal | string - Canister to start
Returns: Promise<void> Example:
await agent.canisterPlugin.start('canister-id');
console.log('Canister started');

stop(canisterId)

Stop a running canister. Parameters:
  • canisterId: Principal | string - Canister to stop
Returns: Promise<void> Example:
await agent.canisterPlugin.stop('canister-id');
console.log('Canister stopped');

delete(canisterId)

Delete a canister (must be stopped first). Parameters:
  • canisterId: Principal | string - Canister to delete
Returns: Promise<void> Example:
// Stop then delete
await agent.canisterPlugin.stop('canister-id');
await agent.canisterPlugin.delete('canister-id');
console.log('Canister deleted');

Method Calls

call(options)

Execute an update call on a canister. Parameters:
  • options: ICanisterCallOptions
    • canisterId: Principal - Target canister
    • methodName: string - Method to call
    • args: unknown[] - Method arguments
    • idlFactory: IDL.InterfaceFactory - Candid interface factory
Returns: Promise<unknown> - Method result Example:
import { idlFactory } from './hello-world.did.js';

const result = await agent.canisterPlugin.call({
  canisterId: Principal.fromText('canister-id'),
  methodName: 'greet',
  args: ['World'],
  idlFactory
});

console.log('Greeting result:', result);

query(options)

Execute a query call on a canister (read-only, faster). Parameters:
  • options: ICanisterQueryOptions
    • canisterId: Principal - Target canister
    • methodName: string - Method to call
    • args: unknown[] - Method arguments
    • idlFactory: IDL.InterfaceFactory - Candid interface factory
Returns: Promise<unknown> - Method result Example:
const balance = await agent.canisterPlugin.query({
  canisterId: Principal.fromText('canister-id'),
  methodName: 'getBalance',
  args: [],
  idlFactory
});

console.log('Current balance:', balance);

createActor(canisterId, idlFactory)

Create a typed actor for easier method calls. Parameters:
  • canisterId: Principal | string - Target canister
  • idlFactory: IDL.InterfaceFactory - Candid interface factory
Returns: ActorSubclass<T> - Typed actor instance Example:
import { idlFactory } from './hello-world.did.js';

const actor = agent.canisterPlugin.createActor('canister-id', idlFactory);

// Use actor methods directly
const greeting = await actor.greet('World');
const balance = await actor.getBalance();
const result = await actor.updateCounter(42);

Status and Information

getStatus(canisterId)

Get detailed canister status information. Parameters:
  • canisterId: Principal | string - Canister to query
Returns: Promise<ICanisterStatus>
  • canisterId: Principal - Canister ID
  • status: 'running' | 'stopping' | 'stopped' - Current status
  • settings: ICanisterSettings - Current settings
  • memorySize: bigint - Memory usage in bytes
  • cycles: bigint - Current cycles balance
  • moduleHash: string - Hash of installed module
Example:
const status = await agent.canisterPlugin.getStatus('canister-id');

console.log('Status:', status.status);
console.log('Cycles:', agent.canisterPlugin.formatCycles(status.cycles));
console.log('Memory:', status.memorySize, 'bytes');
console.log('Controllers:', status.settings.controllers?.map(p => p.toText()));

Controller Management

updateSettings(canisterId, settings)

Update canister settings. Parameters:
  • canisterId: Principal | string - Target canister
  • settings: Partial<ICanisterSettings> - Settings to update
Returns: Promise<void> Example:
await agent.canisterPlugin.updateSettings('canister-id', {
  computeAllocation: 20,
  memoryAllocation: BigInt(2 * 1024 * 1024), // 2MB
  freezingThreshold: 7776000 // 90 days
});

addController(canisterId, controller)

Add a new controller to a canister. Parameters:
  • canisterId: Principal | string - Target canister
  • controller: Principal | string - New controller principal
Returns: Promise<void> Example:
await agent.canisterPlugin.addController(
  'canister-id',
  'new-controller-principal'
);

removeController(canisterId, controller)

Remove a controller from a canister. Parameters:
  • canisterId: Principal | string - Target canister
  • controller: Principal | string - Controller to remove
Returns: Promise<void> Example:
await agent.canisterPlugin.removeController(
  'canister-id',
  'old-controller-principal'
);

Utility Functions

formatCycles(cycles)

Format cycles amount for display. Parameters:
  • cycles: bigint - Cycles amount
Returns: string - Formatted cycles (e.g., “2.5T”, “1.2B”) Example:
const formatted = agent.canisterPlugin.formatCycles(BigInt('2500000000000'));
console.log(formatted); // "2.5T"

parseCycles(cycles)

Parse cycles string to bigint. Parameters:
  • cycles: string - Cycles string (e.g., “2.5T”, “1B”)
Returns: bigint - Parsed cycles amount Example:
const amount = agent.canisterPlugin.parseCycles('2.5T');
console.log(amount); // 2500000000000n

exists(canisterId)

Check if a canister exists. Parameters:
  • canisterId: Principal | string - Canister to check
Returns: Promise<boolean> - Whether canister exists Example:
const exists = await agent.canisterPlugin.exists('canister-id');
if (exists) {
  console.log('Canister exists');
}

isController(canisterId)

Check if current identity is a controller of the canister. Parameters:
  • canisterId: Principal | string - Canister to check
Returns: Promise<boolean> - Whether current identity is a controller Example:
const isController = await agent.canisterPlugin.isController('canister-id');
if (isController) {
  console.log('You are a controller of this canister');
}

Types

ICanisterSettings

Canister configuration settings.
interface ICanisterSettings {
  controllers?: Principal[];
  computeAllocation?: number; // 0-100
  memoryAllocation?: bigint; // bytes
  freezingThreshold?: number; // seconds
}

ICanisterDeployOptions

Options for deploying WASM to a canister.
interface ICanisterDeployOptions {
  canisterId: Principal;
  wasmModule: Uint8Array;
  installArgs?: Uint8Array;
  mode?: 'install' | 'upgrade' | 'reinstall';
}

IDeployResult

Result of canister deployment.
interface IDeployResult {
  canisterId: Principal;
  moduleHash: string;
  cyclesUsed: bigint;
}

ICanisterCallOptions

Options for canister method calls.
interface ICanisterCallOptions {
  canisterId: Principal;
  methodName: string;
  args: unknown[];
  idlFactory: IDL.InterfaceFactory;
}

Usage Patterns

Complete Canister Lifecycle

// 1. Create canister
const { canisterId } = await agent.canisterPlugin.create({
  cycles: '10T'
});

// 2. Deploy WASM
const wasmModule = await fetch('/hello-world.wasm').then(r => r.arrayBuffer());
await agent.canisterPlugin.deploy({
  canisterId,
  wasmModule: new Uint8Array(wasmModule)
});

// 3. Create actor for method calls
const actor = agent.canisterPlugin.createActor(canisterId, idlFactory);

// 4. Call methods
const result = await actor.greet('World');
console.log('Result:', result);

// 5. Monitor status
const status = await agent.canisterPlugin.getStatus(canisterId);
console.log('Remaining cycles:', agent.canisterPlugin.formatCycles(status.cycles));

Multi-Canister Management

const canisters = ['canister-1', 'canister-2', 'canister-3'];

// Check status of all canisters
for (const canisterId of canisters) {
  const status = await agent.canisterPlugin.getStatus(canisterId);
  console.log(`${canisterId}: ${status.status}, ${agent.canisterPlugin.formatCycles(status.cycles)} cycles`);
}

// Stop all canisters
await Promise.all(canisters.map(id => agent.canisterPlugin.stop(id)));

// Update settings for all
const newSettings = { computeAllocation: 10 };
await Promise.all(canisters.map(id => 
  agent.canisterPlugin.updateSettings(id, newSettings)
));

Canister Upgrade Pattern

// Upgrade existing canister
const newWasmModule = await fetch('/hello-world-v2.wasm').then(r => r.arrayBuffer());

// First, check if we're a controller
const isController = await agent.canisterPlugin.isController('canister-id');
if (!isController) {
  throw new Error('Not authorized to upgrade canister');
}

// Perform upgrade
await agent.canisterPlugin.deploy({
  canisterId: Principal.fromText('canister-id'),
  wasmModule: new Uint8Array(newWasmModule),
  mode: 'upgrade'
});

console.log('Canister upgraded successfully');

Error Handling

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

try {
  await agent.canisterPlugin.call({
    canisterId: Principal.fromText('invalid-canister'),
    methodName: 'test',
    args: [],
    idlFactory
  });
} catch (error) {
  if (error instanceof ICPAgentError) {
    if (error.code === 'CANISTER_NOT_FOUND') {
      console.log('Canister does not exist');
    } else if (error.code === 'INSUFFICIENT_CYCLES') {
      console.log('Not enough cycles for operation');
    }
  }
}