canic_core/ops/ic/
mod.rs

1//! Ops layer: approved execution surface and coordination boundary.
2//!
3//! The `ops` layer defines the **sanctioned capabilities** that higher layers
4//! (workflow, API, macros) are allowed to use. It sits between application logic
5//! and low-level infrastructure, providing a stable execution façade.
6//!
7//! Responsibilities:
8//! - Expose approved primitives and subsystems (IC access, runtime context,
9//!   metrics, logging, registries).
10//! - Add cross-cutting concerns such as metrics, logging, and normalization.
11//! - Aggregate infra errors into ops-scoped error types.
12//!
13//! Non-responsibilities:
14//! - No business policy or workflow orchestration.
15//! - No domain decisions or lifecycle management.
16//!
17//! Infra interaction:
18//! - `infra` owns **raw mechanical implementations** (IC calls, encoding,
19//!   decoding, management canister interactions).
20//! - `ops` may either wrap infra or call the CDK directly when the CDK API
21//!   already represents the desired primitive (e.g. ambient runtime context).
22//!
23//! Naming conventions:
24//! - Plain nouns (e.g. `Call`, `Runtime`, `Env`) represent approved execution
25//!   primitives.
26//! - `*Ops` types represent orchestration or aggregation roles (typically error
27//!   or coordination objects), not primitives themselves.
28
29pub mod call;
30pub mod http;
31pub mod icrc;
32pub mod ledger;
33pub mod mgmt;
34pub mod network;
35pub mod nns;
36pub mod signature;
37pub mod xrc;
38
39pub use cdk::types::{Cycles, TC};
40
41use crate::{
42    InternalError,
43    cdk::{self, types::Principal},
44    infra,
45    ops::OpsError,
46};
47use thiserror::Error as ThisError;
48
49///
50/// IcOpsError
51///
52
53#[derive(Debug, ThisError)]
54pub enum IcOpsError {
55    #[error(transparent)]
56    Infra(#[from] infra::InfraError),
57
58    #[error(transparent)]
59    CallOps(#[from] call::CallError),
60
61    #[error(transparent)]
62    HttpOps(#[from] http::HttpOpsError),
63
64    #[error(transparent)]
65    LedgerOps(#[from] ledger::LedgerOpsError),
66
67    #[error(transparent)]
68    XrcOps(#[from] xrc::XrcOpsError),
69}
70
71impl From<IcOpsError> for InternalError {
72    fn from(err: IcOpsError) -> Self {
73        OpsError::from(err).into()
74    }
75}
76
77///
78/// IcOps
79/// Ambient IC execution primitives
80///
81
82pub struct IcOps;
83
84impl IcOps {
85    /// Return the current canister principal.
86    #[must_use]
87    pub fn canister_self() -> Principal {
88        cdk::api::canister_self()
89    }
90
91    /// Return the current caller principal.
92    #[must_use]
93    pub fn msg_caller() -> Principal {
94        cdk::api::msg_caller()
95    }
96
97    /// Return the current UNIX epoch time in seconds.
98    #[must_use]
99    pub fn now_secs() -> u64 {
100        cdk::utils::time::now_secs()
101    }
102
103    /// Return the current UNIX epoch time in milliseconds.
104    #[must_use]
105    pub fn now_millis() -> u64 {
106        cdk::utils::time::now_millis()
107    }
108
109    /// Return the current UNIX epoch time in microseconds.
110    #[must_use]
111    pub fn now_micros() -> u64 {
112        cdk::utils::time::now_micros()
113    }
114
115    /// Return the current UNIX epoch time in nanoseconds.
116    #[must_use]
117    pub fn now_nanos() -> u64 {
118        cdk::utils::time::now_nanos()
119    }
120
121    /// Trap the canister with the provided message.
122    pub fn trap(message: &str) -> ! {
123        cdk::api::trap(message)
124    }
125
126    /// Print a line to the IC debug output.
127    pub fn println(message: &str) {
128        cdk::println!("{message}");
129    }
130
131    /// Spawn a task on the IC runtime.
132    pub fn spawn<F>(future: F)
133    where
134        F: Future<Output = ()> + 'static,
135    {
136        cdk::futures::spawn(future);
137    }
138}