Refund of cycles after canister deletion

I have a parent canister which creates a child canister with 900B cycles:

await (with cycles = 900_000_000_000) Child.Child()

After creation and installation, the child canister has ~400B cycles. (500B was just for creation).

If an error occurs during creation/installation, I will delete that canister:

await ic.stop_canister({ canister_id = Principal.fromActor(child) });
await ic.delete_canister({ canister_id = Principal.fromActor(child) });

The question is: Why don’t I get the 900B cycles back? If I delete a canister from the command line, I get cycles. Why wouldn’t I get them if I delete it like above? I was expected to receive the 900B cycles in the canister and see them with the dfx canister status command or receive them in the wallet, but they are lost.

There is no option to uninstall the code or reuse the canister id or transfer the ~400B cycles manually from the child.

I don’t think this works well in Motoko. You may need to change coding patterns here if this is a common thing for your use case. I can ping Motoko folks that know better how to do this if you’re interested.

When you call ic.delete_canister, the canister gets deleted and no cycles refunded. This is explicitly mentioned in the spec. The reason you get cycles back when you do it via dfx is that dfx first installs a WASM to the to-be-deleted-canister that allows it to send as many cycles out as possible, deposits those cycles to your cycles ledger account, and only then deletes the canister. If you want to recover cycles you will need to follow a similar pattern.

Btw when you try to send out as many cycles as possible you will need to hold back 0.1-0.2T cycles because of how things like the freezing threshold and reserved cycles for response processing work. So in your example where you create a canister with 0.9T you can probably get back 0.2T cycles (0.5T lost to canister creation, 0.2T lost to reservations)

2 Likes

hi @blitz26,
According to the spec, cycles are discarded when a canister is deleted:

Deleting a canister cannot be undone, any state stored on the canister is permanently deleted and its cycles are discarded.

The cycles should be explicitly transferred form the child canister, which is what dfx does under the hood.

I’m not a Motoko expert, so there may be ready-to-use patterns for this. I’ll ping the Motoko folks for their input.

1 Like