Automatically recycle cycles in unused canisters

I’m building a tool called recycle, the goal is to help developers automatically reclaim cycles from unused canisters to their cycles wallet, but I got some problems in testing:

I’m trying to send cycles from an unused canister to my own cycles wallet, I reinstalled the following code to the canister, then called recycle, but got this error:

The Replica returned an error: code 5, message: "Canister gagfc-iqaaa-aaaah-qcdvq-cai trapped explicitly: could not perform remote call"

Code:

import Nat "mo:base/Nat";
import Error "mo:base/Error";
import Principal "mo:base/Principal";
import Result "mo:base/Result";
import Cycles = "mo:base/ExperimentalCycles";
import ic "./ic"

shared(msg) actor class Recycle(owner_: Principal) = this {

    private stable var owner: Principal = owner_;
    private stable var IC: ic.ICActor = actor("aaaaa-aa");

    public type CyclesWallet = actor {
        wallet_receive: shared() -> async ();
    };

    public query func cycles(): async Nat {
        return Cycles.balance();
    };

    public shared(msg) func get_freezing_threshold(canister_id: Principal): async Nat {
        try {
            let status = await IC.canister_status({canister_id = canister_id});
            switch(status.settings.freezing_threshold) {
                case(?n) { return n; };
                case(_) { return 0; };
            };
        } catch (e) {
            return 2_592_000;
        };
    };

    public shared(msg) func recycle(to: Principal, leftover: Nat): async Bool {
        assert(msg.caller == owner);
        let bal = Cycles.balance();
        let amount: Nat = bal - leftover;

        let wallet: CyclesWallet = actor(Principal.toText(to));
        Cycles.add(amount);
        await wallet.wallet_receive();
        return true;
    };
}

BTW, another two questions:

  1. how to get the actual freezing_threshold of a canister? I used dfx canister --network ic status xxx, the freezing threshold is 2_592_000, but when I try to send ExperimentalCycles.balance() - 2_592_000 amount of cycles to my cycles wallet, I got this error telling me the freezing threshold is 122346093:
The Replica returned an error: code 5, message: "Canister gagfc-iqaaa-aaaah-qcdvq-cai is out of cycles: requested 3897751976035 cycles but the available balance is 3897751904703 cycles and the freezing threshold 122346093 cycles"
  1. is there any better way to destroy the unused canister and get back as many cycles as I can to my cycles wallet? Or any suggestions on how to build such a tool?
1 Like

This might help

Thanks, I’ll take a look into it

Hi, Did you find the reason for the problem “Canister xxx trapped explicitly: could not perform remote call”
I have the same problem.
Thanks

Nope, still don’t know the reason

There are some global variables in the canister, and when the request tries to access one of them, I got this error, and others are ok.

I’ve seen this error seemingly when a canister does not have enough cycles to complete an update call.