pub mod build_network;
pub mod call;
pub mod icp_refill;
pub mod mgmt;
pub mod nns;
use crate::{InternalError, cdk::types::Principal, infra, ops::OpsError};
use std::time::SystemTime;
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum IcOpsError {
#[error(transparent)]
Infra(#[from] infra::InfraError),
#[error(transparent)]
CallOps(#[from] call::CallError),
#[error(transparent)]
IcpRefillOps(#[from] icp_refill::IcpRefillOpsError),
}
impl From<IcOpsError> for InternalError {
fn from(err: IcOpsError) -> Self {
OpsError::from(err).into()
}
}
pub struct IcOps;
impl IcOps {
#[must_use]
pub fn canister_self() -> Principal {
ic_cdk::api::canister_self()
}
#[must_use]
pub fn canister_cycle_balance() -> crate::cdk::types::Cycles {
ic_cdk::api::canister_cycle_balance().into()
}
#[must_use]
pub fn msg_caller() -> Principal {
ic_cdk::api::msg_caller()
}
#[must_use]
#[cfg_attr(
not(target_arch = "wasm32"),
expect(
clippy::missing_const_for_fn,
reason = "wasm path delegates to ic0-backed caller lookup, which is not const"
)
)]
pub(crate) fn metadata_entropy_caller() -> Principal {
#[cfg(target_arch = "wasm32")]
{
Self::msg_caller()
}
#[cfg(not(target_arch = "wasm32"))]
{
Principal::anonymous()
}
}
#[must_use]
#[cfg_attr(
not(target_arch = "wasm32"),
expect(
clippy::missing_const_for_fn,
reason = "wasm path delegates to ic0-backed canister lookup, which is not const"
)
)]
pub(crate) fn metadata_entropy_canister() -> Principal {
#[cfg(target_arch = "wasm32")]
{
Self::canister_self()
}
#[cfg(not(target_arch = "wasm32"))]
{
Principal::management_canister()
}
}
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub fn now_secs() -> u64 {
(time_nanos() / 1_000_000_000) as u64
}
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub fn now_millis() -> u64 {
(time_nanos() / 1_000_000) as u64
}
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub fn now_micros() -> u64 {
(time_nanos() / 1_000) as u64
}
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub fn now_nanos() -> u64 {
time_nanos() as u64
}
pub fn println(message: &str) {
ic_cdk::println!("{message}");
}
pub fn spawn<F>(future: F)
where
F: Future<Output = ()> + 'static,
{
ic_cdk::futures::spawn(future);
}
}
#[cfg_attr(target_arch = "wasm32", expect(unreachable_code))]
fn time_nanos() -> u128 {
#[cfg(target_arch = "wasm32")]
{
return u128::from(ic_cdk::api::time());
}
match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(duration) => duration.as_nanos(),
Err(_) => 0,
}
}
#[cfg(test)]
mod tests {
use super::IcOps;
#[test]
fn current_time_is_a_recent_unix_timestamp() {
assert!(IcOps::now_secs() > 1_700_000_000);
}
}