I am currently developing a program that involves a process where A canister calls B canister , and I have noticed that it occupies a portion of A’s cycle. Do you have any idea what this might be about?
The docs AI is useful for these sorts of questions. Enter the ICP ecosystem
Inter-Canister Call Charging
Inter-Canister Call Charging
Inter-canister calls (also called Xnet calls) are charged to the sending canister, not the receiving one. Here’s how the costs break down:
Cost Components
Component 13-node subnet 34-node subnet Base fee per call (request + response overhead) 260,000 cycles 680,000 cycles Per byte transmitted 1,000 cycles/byte 2,615 cycles/byte Update message execution (base fee on target) 5,000,000 cycles 13,076,923 cycles Per 1B Wasm instructions executed 1,000,000,000 cycles 2,615,384,615 cycles Who Pays What
- Sending canister pays the Xnet call overhead (base + per-byte transmission costs).
- Receiving canister pays for executing the message (update message base fee + instruction costs).
- Ingress messages (user → canister) are charged to the receiving canister instead.
Reply Cost Reservation
When a canister makes an inter-canister call, it prepays the maximum-size reply cost upfront. If the actual reply is smaller than the maximum, the difference is refunded. This is handled at the protocol level via
ic0.call_perform, which sets asideMAX_CYCLES_PER_RESPONSEcycles for response processing.Attaching Cycles to a Call
Some canister methods require cycles to be explicitly attached as a per-request fee (e.g., the exchange rate canister charges 1 billion cycles per request). You can do this in:
Motoko:
await (with cycles = 500_000_000) target.someMethod();Rust:
Call::unbounded_wait(principal, "someMethod") .with_cycles(500_000_000u128) .await .expect("call failed");Programmatic Cost Lookup
Rather than hardcoding costs, use the
ic0.cost_callsystem API to get the current cost at runtime — it accounts for method name size, payload size, and the current cost schedule.Query Calls Are Free
Query calls are not charged — they run on a single node, bypass consensus, and incur no cycle cost.