{"id":30703166,"url":"https://github.com/dfinity/canfund","last_synced_at":"2025-09-02T16:56:44.324Z","repository":{"id":257798614,"uuid":"844576639","full_name":"dfinity/canfund","owner":"dfinity","description":"Library for automated cycles management of canisters on the Internet Computer","archived":false,"fork":false,"pushed_at":"2025-06-11T07:59:30.000Z","size":1722,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-20T05:56:20.301Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfinity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-08-19T14:37:41.000Z","updated_at":"2025-06-13T05:37:40.000Z","dependencies_parsed_at":"2024-11-01T12:17:21.778Z","dependency_job_id":"b48b3778-438d-4918-af24-b5ab68dc9015","html_url":"https://github.com/dfinity/canfund","commit_stats":null,"previous_names":["dfinity/canfund"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/dfinity/canfund","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fcanfund","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fcanfund/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fcanfund/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fcanfund/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfinity","download_url":"https://codeload.github.com/dfinity/canfund/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fcanfund/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273317765,"owners_count":25084037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-02T02:00:09.530Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-02T16:56:39.194Z","updated_at":"2025-09-02T16:56:44.307Z","avatar_url":"https://github.com/dfinity.png","language":"Rust","readme":"[![Internet Computer portal](https://img.shields.io/badge/InternetComputer-grey?logo=internet%20computer\u0026style=for-the-badge)](https://internetcomputer.org)\n[![DFinity Forum](https://img.shields.io/badge/help-post%20on%20forum.dfinity.org-blue?style=for-the-badge)](https://forum.dfinity.org/)\n[![GitHub license](https://img.shields.io/badge/license-Apache%202.0-blue.svg?logo=apache\u0026style=for-the-badge)](LICENSE)\n\n\n# canfund\n\nWelcome to **`canfund`**! This library provides automated cycles management for canisters on the Internet Computer (IC). `canfund` helps ensure your canisters have sufficient cycles by automating the process of balance checking, funding, and cycle-minting based on configurable rules.\n\n## Features\n\n- **Automated Cycles Management**: Automatically manages cycles for specified canisters, including the canister running `canfund`, according to predefined rules.\n- **Periodic Balance Monitoring**: `canfund` periodically checks cycle balances using ICP timers, ensuring your canisters stay adequately funded.\n- **Optional Cycle Minting**: If funding canister lacks sufficient cycles, `canfund` can mint new cycles from ICP.\n- **Configurable Funding Strategies**: Offers three customizable strategies for managing cycles, allowing you to tailor it to specific needs.\n- **Configurable Balance Fetching**: Supports multiple methods for fetching the cycle balance of canisters during registration, accommodating different levels of access and canister configurations.\n- **Funding Callback**: Canfund supports providing a callback function that is triggered after each funding round, which can be used for monitoring or logging purposes.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Configuration](#configuration)\n  - [Canister Registration](#canister-registration)\n  - [Funding Strategies](#funding-strategies)\n  - [Minting Cycles](#obtaining-cycles)\n  - [Funding Callback](#funding-callback)\n- [Examples](#examples)\n- [License](#license)\n\n## Installation\n\nTo integrate `canfund` into your Internet Computer project, add the library as a dependency:\n\n```bash\ncargo install `canfund`\n```\n\nOr alternatively manually define the dependency in your `Cargo.toml` file:\n\n```json\n{\n  \"dependencies\": {\n    \"canfund\": {\n      \"git\": \"https://github.com/dfinity/canfund\",\n      \"version\": \"0.1.0\"\n    }\n  }\n}\n```\n\nThen, use `canfund` in your canister code:\n\n```rust,ignore\nuse canfund;\n```\n\n## Usage\n\n### Configuration\n\nTo use `canfund`, configure it with rules for managing cycles for your canisters. The configuration includes:\n\n- **Target Canisters**: Specify the canisters that should be managed.\n- **Funding Rules**: Set the thresholds and strategies that trigger additional cycle funding.\n- **Cycle Minting**: Enable or disable the minting of cycles from the ICP balance when necessary.\n\n\n### Canister Registration\n\nEach canister that you want to fund using `canfund` must be registered. During registration, you must specify the method by which the canister's cycle balance will be fetched. `canfund` supports two different balance-fetching methods:\n\n1. **FetchCyclesBalanceFromCanisterStatus**: Retrieves the cycle balance from the response of an update call to a canister, typically using the `canister_status` method on the management canister. It can also work with responses from other canisters, such as a blackhole, or from self-exposed methods on any canister, as long as the response follows the [CanisterStatusResponse specification](https://docs.rs/ic-cdk/0.15.0/ic_cdk/api/management_canister/main/struct.CanisterStatusResponse.html). \n\n   This method is only applicable if the funding canister has the required permissions to invoke the target canister’s method, such as being a controller when interacting with the management canister.\n\n   ```rust,ignore\n   // By default, using the management canister (funding canister is a controller)\n   let fetcher = FetchCyclesBalanceFromCanisterStatus::new();\n   \n   // Using the blackhole canister (Blackhole is a controller)\n   let fetcher = FetchCyclesBalanceFromCanisterStatus::new()\n           .with_proxy(Principal::from_text(\"e3mmv-5qaaa-aaaah-aadma-cai\").unwrap()));\n   );\n   \n   // Using a custom method of a canister (method is public)\n   let fetcher = FetchCyclesBalanceFromCanisterStatus::new()\n           .with_proxy(Principal::from_text(\"ml52i-qqaaa-aaaar-qaaba-cai\").unwrap())\n           .with_method(\"get_canister_status\".to_string());\n   );\n   ```\n   **Note:** This method is currently the only one that accounts for the freezing threshold of the funded canister. As a result, the runtime and threshold-based funding strategies (explained below) are calculated based on when the canister becomes frozen. This behavior does not apply to the Blackhole proxy, as it currently does not return the required _idle_cycles_burned_per_day_ field in its response.\n\n\n3. **FetchCyclesBalanceFromPrometheusMetrics**: Fetches the cycle balance by leveraging Prometheus metrics exposed by the canister through an HTTP endpoint.\n\n   ```rust,ignore\n   let fetcher = FetchCyclesBalanceFromPrometheusMetrics::new(\n       \"/metrics\".to_string(), // path\n       \"canister_cycles_balance\".to_string(), // metric name\n   );\n   ```\n\nTo register a canister with selected `fetcher`:\n\n```rust,ignore\nfund_manager.register(\n    Principal::from_text(\"funded_canister_id\").unwrap(),\n    RegisterOpts::new().with_cycles_fetcher(\n        Arc::new(fetcher)\n    ),\n);\n```\n\n### Funding Strategies\n\n`canfund` provides three distinct strategies for funding your canisters:\n\n1. **BelowThreshold (Default)**: Funds the canister when its cycle balance falls below a predefined threshold.\n\n   ```rust,ignore\n   let strategy = FundStrategy::BelowThreshold(\n       CyclesThreshold::new()\n           .with_min_cycles(125_000_000_000)\n           .with_fund_cycles(250_000_000_000)\n   );\n   ```\n\n2. **BelowEstimatedRuntime**: Funds the canister based on an estimated runtime in seconds. This strategy calculates the required cycles to keep the canister running for the specified duration.\n\n   ```rust,ignore\n   let strategy = FundStrategy::BelowEstimatedRuntime(\n       EstimatedRuntime::new()\n           .with_min_runtime_secs(2 * 24 * 60 * 60) // 2 day\n           .with_fund_runtime_secs(3 * 24 * 60 * 60) // 3 days\n           .with_max_runtime_cycles_fund(1_000_000_000_000)\n           .with_fallback_min_cycles(125_000_000_000)\n           .with_fallback_fund_cycles(250_000_000_000),\n   );\n   ```\n\n3. **Always**: Funds the canister at a fixed interval with a specified amount of cycles, regardless of the current balance.\n\n   ```rust,ignore\n   let strategy = FundStrategy::Always(1_000);\n   ```\n\n### Obtaining Cycles\n\n`canfund` can be configured to obtain cycles if your canister requires more cycles than it currently holds. This is achieved by interacting with the ICP Ledger and the Cycles Minting Canister (CMC) or by withdrawing cycles from the cycles ledger. Only one strategy can be set at a time.\n\n#### Minting Cycles\nTo enable minting cycles, you must provide the necessary configuration to allow `canfund` to mint cycles. This configuration can also be set for each registered canister to override the global configuration.\n\n```rust,ignore\nlet obtain_cycles_config = ObtainCyclesOptions {\n    obtain_cycles: Arc::new(MintCycles {\n        ledger: Arc::new(IcLedgerCanister::new(MAINNET_LEDGER_CANISTER_ID)),\n        cmc: Arc::new(IcCyclesMintingCanister::new(\n            MAINNET_CYCLES_MINTING_CANISTER_ID,\n        )),\n        from_subaccount: Subaccount::from(DEFAULT_SUBACCOUNT),\n    }),\n};\n\nfunding_options.with_obtain_cycles_options(Some(obtain_cycles_config));\n```\n\nWith this configuration, `canfund` will periodically check the ICP balance and mint new cycles as needed to ensure that your canisters remain adequately funded.\n\n#### Withdrawing Cycles\n\nAlternatively, `canfund` can be configured to withdraw cycles from the [cycles ledger](https://dashboard.internetcomputer.org/canister/um5iw-rqaaa-aaaaq-qaaba-cai). This is achieved by interacting with the Cycles Ledger using the `WithdrawFromCyclesLedger` struct.\n\nTo enable this feature, you must provide the necessary configuration to allow `canfund` to withdraw cycles. This configuration can also be set for each registered canister to override the global configuration.\n\n```rust,ignore\nlet obtain_cycles_config = ObtainCyclesOptions {\n    obtain_cycles: Arc::new(WithdrawFromCyclesLedger {\n        ledger: Arc::new(CyclesLedgerCanister::new(MAINNET_CYCLES_LEDGER_CANISTER_ID)),\n        from_subaccount: None,\n    }),\n};\n\nfunding_options.with_obtain_cycles_options(Some(obtain_cycles_config));\n```\n\nWith this configuration, canfund will periodically check the cycles balance and withdraw cycles as needed to ensure that your canisters remain adequately funded.\n\n### Funding Callback\n\n`canfund` also supports registering a callback function that will be triggered after a funding round is completed. This feature is useful for monitoring and logging purposes, allowing you to capture and read data such as the remaining cycle balances and total cycles deposited per canister.\n\nExample of registering a callback:\n\n```rust,ignore\nlet funding_config = FundManagerOptions::new()\n    .with_funding_callback(Rc::new(|canister_records| {\n        // custom monitoring || logging logic\n    })\n); \n```\n\nFunding callback can also be used to handle funding failures. For example, if the funding canister does not have enough cycles to fund the target canister, the callback can be used to notify the user or trigger a different action.\n\nFunding failures can be accessed through the `canister_records` parameter, which contains an optional `funding_failure` enum field. This field will be `Some` if the latest funding operation failed, and `None` otherwise.\n\n\n\n### Initialization\n\nInitialize `canfund` with your configuration:\n\n```rust,ignore\nlet funding_config = FundManagerOptions::new()\n        .with_interval_secs(12 * 60 * 60) // check twice a day\n        .with_strategy(strategy); \n\nfund_manager.with_options(funding_config);\n```\n\n## Examples\n\nHere's a basic example of using `canfund` for automated cycles management:\n\n```rust,ignore\nuse canfund::{manager::{options::{CyclesThreshold, FundManagerOptions, FundStrategy}, RegisterOpts}, operations::fetch::FetchCyclesBalanceFromCanisterStatus, FundManager};\n\n#[ic_cdk_macros::init]\nfn initialize() {\n    let mut fund_manager = FundManager::new();\n\n    let funding_config = FundManagerOptions::new()\n        .with_interval_secs(12 * 60 * 60)\n        .with_strategy(FundStrategy::BelowThreshold(\n            CyclesThreshold::new()\n                .with_min_cycles(125_000_000_000)\n                .with_fund_cycles(250_000_000_000),\n    ));        \n\n    fund_manager.with_options(funding_config);\n    \n    fund_manager.register(\n        Principal::from_text(\"funded_canister_id\").unwrap(),\n        RegisterOpts::new().with_cycles_fetcher(\n            Arc::new(FetchCyclesBalanceFromCanisterStatus::new())\n        ),\n    );\n\n    // Note: the funding canister is NOT automatically registered\n    fund_manager.register(\n        id(),\n        RegisterOpts::new(),\n    );\n\n    fund_manager.start();\n}\n```\n\nFull examples can be found in the examples folder for [simple](examples/simple_funding/src/lib.rs) and [advanced](examples/advanced_funding/src/lib.rs) funding configurations.\n\n## License\n\nThis project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.\n\n---\n\nThis README provides an overview of `canfund`, along with installation instructions and examples to help you get started. Contributions and feedback are welcome!","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfinity%2Fcanfund","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfinity%2Fcanfund","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfinity%2Fcanfund/lists"}