Skip to main content

canic_host/cycle_balance/
mod.rs

1//! Module: cycle_balance
2//!
3//! Responsibility: query the maintained Canic cycle-balance endpoint.
4//! Does not own: cycle accounting, local replica transport, or report aggregation.
5//! Boundary: decodes the canonical typed endpoint result into a host balance.
6
7use crate::{
8    icp::{IcpCli, IcpCommandError, IcpJsonResponseError, decode_json_result_response},
9    replica_query,
10};
11use std::{error::Error, fmt, path::Path};
12
13use canic_core::protocol;
14
15const ICP_JSON_OUTPUT: &str = "json";
16
17///
18/// CycleBalanceQueryError
19///
20
21#[derive(Debug)]
22pub enum CycleBalanceQueryError {
23    Icp(IcpCommandError),
24    Response(IcpJsonResponseError),
25}
26
27impl fmt::Display for CycleBalanceQueryError {
28    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match self {
30            Self::Icp(err) => write!(formatter, "{err}"),
31            Self::Response(err) => write!(formatter, "{err}"),
32        }
33    }
34}
35
36impl Error for CycleBalanceQueryError {
37    fn source(&self) -> Option<&(dyn Error + 'static)> {
38        match self {
39            Self::Icp(err) => Some(err),
40            Self::Response(err) => Some(err),
41        }
42    }
43}
44
45impl From<IcpCommandError> for CycleBalanceQueryError {
46    fn from(err: IcpCommandError) -> Self {
47        Self::Icp(err)
48    }
49}
50
51impl From<IcpJsonResponseError> for CycleBalanceQueryError {
52    fn from(err: IcpJsonResponseError) -> Self {
53        Self::Response(err)
54    }
55}
56
57/// Query `canic_cycle_balance`, using direct local replica calls when available.
58pub fn query_cycle_balance(
59    icp: &IcpCli,
60    canister_id: &str,
61    network: &str,
62    icp_root: Option<&Path>,
63    candid_path: Option<&Path>,
64) -> Result<u128, CycleBalanceQueryError> {
65    if replica_query::should_use_local_replica_query(Some(network))
66        && let Some(root) = icp_root
67        && let Ok(cycles) =
68            replica_query::query_cycle_balance_from_root(Some(network), canister_id, root)
69    {
70        return Ok(cycles);
71    }
72
73    let output = icp.canister_query_output_with_candid(
74        canister_id,
75        protocol::CANIC_CYCLE_BALANCE,
76        Some(ICP_JSON_OUTPUT),
77        candid_path,
78    )?;
79    decode_json_result_response(&output).map_err(Into::into)
80}