ic_cdk/
api.rs

1//! System API bindings.
2//!
3//! This module provides Rust ergonomic bindings to the system APIs.
4//!
5//! Some APIs require more advanced handling and are organized into separate modules:
6//! * For the inter-canister calls API, see the [`call`](mod@crate::call) module.
7//! * For the stable memory management API, see the .
8//!   * The basic bindings are provided in this module including [`stable_size`], [`stable_grow`], [`stable_read`] and [`stable_write`].
9//!   * The [`stable`](crate::stable) module provides more advanced functionalities, e.g. support for `std::io` traits.
10//!
11//! APIs that are only available for `wasm32` are not included.
12//! As a result, system APIs with a numeric postfix (indicating the data bit width) are bound to names without the postfix.
13//! For example, `ic0::msg_cycles_available128` is bound to [`msg_cycles_available`], while `ic0::msg_cycles_available` has no binding.
14//!
15//! Functions that provide bindings for a single system API method share the same name as the system API.
16//! For example, `ic0::msg_reject_code` is bound to [`msg_reject_code`].
17//!
18//! Functions that wrap multiple system API methods are named using the common prefix of the wrapped methods.
19//! For example, [`msg_arg_data`] wraps both `ic0::msg_arg_data_size` and `ic0::msg_arg_data_copy`.
20
21use candid::Principal;
22use std::{convert::TryFrom, num::NonZeroU64};
23
24#[deprecated(
25    since = "0.18.0",
26    note = "The `api::call` module is deprecated. Individual items within this module have their own deprecation notices with specific migration guidance."
27)]
28pub mod call;
29#[deprecated(
30    since = "0.18.0",
31    note = "The `api::management_canister` module is deprecated. Please use the `management_canister` and `bitcoin_canister` modules at the crate root."
32)]
33pub mod management_canister;
34#[deprecated(
35    since = "0.18.0",
36    note = "The `api::stable` module has been moved to `stable` (crate root)."
37)]
38pub mod stable;
39
40/// Gets the message argument data.
41pub fn msg_arg_data() -> Vec<u8> {
42    // SAFETY: `ic0.msg_arg_data`_size is always safe to call.
43    let len = unsafe { ic0::msg_arg_data_size() };
44    let mut buf = vec![0u8; len];
45    // SAFETY:
46    // `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.msg_arg_data_copy` with a 0-offset.
47    unsafe {
48        ic0::msg_arg_data_copy(buf.as_mut_ptr() as usize, 0, len);
49    }
50    buf
51}
52
53/// Gets the identity of the caller, which may be a canister id or a user id.
54///
55/// During canister installation or upgrade, this is the id of the user or canister requesting the installation or upgrade.
56/// During a system task (heartbeat or global timer), this is the id of the management canister.
57pub fn msg_caller() -> Principal {
58    // SAFETY: `ic0.msg_caller_size` is always safe to call.
59    let len = unsafe { ic0::msg_caller_size() };
60    let mut buf = vec![0u8; len];
61    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.msg_caller_copy` with a 0-offset.
62    unsafe {
63        ic0::msg_caller_copy(buf.as_mut_ptr() as usize, 0, len);
64    }
65    // Trust that the system always returns a valid principal.
66    Principal::try_from(&buf).unwrap()
67}
68
69/// Returns the reject code, if the current function is invoked as a reject callback.
70pub fn msg_reject_code() -> u32 {
71    // SAFETY: `ic0.msg_reject_code` is always safe to call.
72    unsafe { ic0::msg_reject_code() }
73}
74
75/// Gets the reject message.
76///
77/// This function can only be called in the reject callback.
78///
79/// Traps if there is no reject message (i.e. if reject_code is 0).
80pub fn msg_reject_msg() -> String {
81    // SAFETY: `ic0.msg_reject_msg_size` is always safe to call.
82    let len = unsafe { ic0::msg_reject_msg_size() };
83    let mut buf = vec![0u8; len];
84    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.msg_reject_msg_copy` with a 0-offset.
85    unsafe {
86        ic0::msg_reject_msg_copy(buf.as_mut_ptr() as usize, 0, len);
87    }
88    String::from_utf8_lossy(&buf).into_owned()
89}
90
91/// Gets the deadline, in nanoseconds since 1970-01-01, after which the caller might stop waiting for a response.
92///
93/// For calls to update methods with best-effort responses and their callbacks,
94/// the deadline is computed based on the time the call was made,
95/// and the `timeout_seconds` parameter provided by the caller.
96/// In such cases, the deadline value will be converted to `NonZeroU64` and wrapped in `Some`.
97/// To get the deadline value as a `u64`, call `get()` on the `NonZeroU64` value.
98///
99/// ```rust,no_run
100/// use ic_cdk::api::msg_deadline;
101/// if let Some(deadline) = msg_deadline() {
102///     let deadline_value : u64 = deadline.get();
103/// }
104/// ```
105///
106/// For other calls (ingress messages and all calls to query and composite query methods,
107/// including calls in replicated mode), a `None` is returned.
108/// Please note that the raw `msg_deadline` system API returns 0 in such cases.
109/// This function is a wrapper around the raw system API that provides more semantic information through the return type.
110pub fn msg_deadline() -> Option<NonZeroU64> {
111    // SAFETY: `ic0.msg_deadline` is always safe to call.
112    let nano_seconds = unsafe { ic0::msg_deadline() };
113    match nano_seconds {
114        0 => None,
115        _ => Some(NonZeroU64::new(nano_seconds).unwrap()),
116    }
117}
118
119/// Replies to the sender with the data.
120pub fn msg_reply<T: AsRef<[u8]>>(data: T) {
121    let buf = data.as_ref();
122    if !buf.is_empty() {
123        // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to `ic0.msg_reply`.
124        unsafe { ic0::msg_reply_data_append(buf.as_ptr() as usize, buf.len()) }
125    };
126    // SAFETY: `ic0.msg_reply` is always safe to call.
127    unsafe { ic0::msg_reply() };
128}
129
130/// Rejects the call with a diagnostic message.
131pub fn msg_reject<T: AsRef<str>>(message: T) {
132    let buf = message.as_ref();
133    // SAFETY: `buf`, being &str, is a readable sequence of UTF8 bytes and therefore can be passed to `ic0.msg_reject`.
134    unsafe {
135        ic0::msg_reject(buf.as_ptr() as usize, buf.len());
136    }
137}
138
139/// Gets the number of cycles transferred by the caller of the current call, still available in this message.
140pub fn msg_cycles_available() -> u128 {
141    let mut dst = 0u128;
142    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.msg_cycles_available128`.
143    unsafe {
144        ic0::msg_cycles_available128(&mut dst as *mut u128 as usize);
145    }
146    dst
147}
148
149/// Gets the amount of cycles that came back with the response as a refund
150///
151/// This function can only be used in a callback handler (reply or reject).
152/// The refund has already been added to the canister balance automatically.
153pub fn msg_cycles_refunded() -> u128 {
154    let mut dst = 0u128;
155    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.msg_cycles_refunded128`.
156    unsafe {
157        ic0::msg_cycles_refunded128(&mut dst as *mut u128 as usize);
158    }
159    dst
160}
161
162/// Moves cycles from the call to the canister balance.
163///
164/// The actual amount moved will be returned.
165pub fn msg_cycles_accept(max_amount: u128) -> u128 {
166    let high = (max_amount >> 64) as u64;
167    let low = (max_amount & u64::MAX as u128) as u64;
168    let mut dst = 0u128;
169    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.msg_cycles_accept128`.
170    unsafe {
171        ic0::msg_cycles_accept128(high, low, &mut dst as *mut u128 as usize);
172    }
173    dst
174}
175
176/// Burns cycles from the canister.
177///
178/// Returns the amount of cycles that were actually burned.
179pub fn cycles_burn(amount: u128) -> u128 {
180    let amount_high = (amount >> 64) as u64;
181    let amount_low = (amount & u64::MAX as u128) as u64;
182    let mut dst = 0u128;
183    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cycles_burn128`.
184    unsafe { ic0::cycles_burn128(amount_high, amount_low, &mut dst as *mut u128 as usize) }
185    dst
186}
187
188/// Gets canister's own identity.
189pub fn canister_self() -> Principal {
190    // SAFETY: `ic0.canister_self_size` is always safe to call.
191    let len = unsafe { ic0::canister_self_size() };
192    let mut buf = vec![0u8; len];
193    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.canister_self_copy` with a 0-offset.
194    unsafe {
195        ic0::canister_self_copy(buf.as_mut_ptr() as usize, 0, len);
196    }
197    // Trust that the system always returns a valid principal.
198    Principal::try_from(&buf).unwrap()
199}
200
201/// Gets the current cycle balance of the canister.
202pub fn canister_cycle_balance() -> u128 {
203    let mut dst = 0u128;
204    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.canister_cycle_balance128`.
205    unsafe { ic0::canister_cycle_balance128(&mut dst as *mut u128 as usize) }
206    dst
207}
208
209/// Gets the current amount of cycles that is available for spending in calls and execution.
210pub fn canister_liquid_cycle_balance() -> u128 {
211    let mut dst = 0u128;
212    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.canister_liquid_cycle_balance128`.
213    unsafe { ic0::canister_liquid_cycle_balance128(&mut dst as *mut u128 as usize) }
214    dst
215}
216
217/// Gets the status of the canister.
218///
219/// The status is one of the following:
220///.- 1: Running
221///.- 2: Stopping
222///.- 3: Stopped
223pub fn canister_status() -> CanisterStatusCode {
224    // SAFETY: `ic0.canister_status` is always safe to call.
225    unsafe { ic0::canister_status() }.into()
226}
227
228/// The status of a canister.
229///
230/// See [Canister status](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-canister-status).
231#[derive(Debug, PartialEq, Eq, Clone, Copy)]
232#[repr(u32)]
233pub enum CanisterStatusCode {
234    /// Running.
235    Running = 1,
236    /// Stopping.
237    Stopping = 2,
238    /// Stopped.
239    Stopped = 3,
240    /// A status code that is not recognized by this library.
241    Unrecognized(u32),
242}
243
244impl From<u32> for CanisterStatusCode {
245    fn from(value: u32) -> Self {
246        match value {
247            1 => Self::Running,
248            2 => Self::Stopping,
249            3 => Self::Stopped,
250            _ => Self::Unrecognized(value),
251        }
252    }
253}
254
255impl From<CanisterStatusCode> for u32 {
256    fn from(value: CanisterStatusCode) -> Self {
257        match value {
258            CanisterStatusCode::Running => 1,
259            CanisterStatusCode::Stopping => 2,
260            CanisterStatusCode::Stopped => 3,
261            CanisterStatusCode::Unrecognized(value) => value,
262        }
263    }
264}
265
266impl PartialEq<u32> for CanisterStatusCode {
267    fn eq(&self, other: &u32) -> bool {
268        let self_as_u32: u32 = (*self).into();
269        self_as_u32 == *other
270    }
271}
272
273/// Gets the canister version.
274///
275/// See [Canister version](https://internetcomputer.org/docs/current/references/ic-interface-spec/#system-api-canister-version).
276pub fn canister_version() -> u64 {
277    // SAFETY: `ic0.canister_version` is always safe to call.
278    unsafe { ic0::canister_version() }
279}
280
281/// Gets the ID of the subnet on which the canister is running.
282pub fn subnet_self() -> Principal {
283    // SAFETY: `ic0.subnet_self_size` is always safe to call.
284    let len = unsafe { ic0::subnet_self_size() };
285    let mut buf = vec![0u8; len];
286    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.subnet_self_copy` with a 0-offset.
287    unsafe {
288        ic0::subnet_self_copy(buf.as_mut_ptr() as usize, 0, len);
289    }
290    // Trust that the system always returns a valid principal.
291    Principal::try_from(&buf).unwrap()
292}
293
294/// Gets the name of the method to be inspected.
295///
296/// This function is only available in the `canister_inspect_message` context.
297pub fn msg_method_name() -> String {
298    // SAFETY: `ic0.msg_method_name_size` is always safe to call.
299    let len: u32 = unsafe { ic0::msg_method_name_size() as u32 };
300    let mut buf = vec![0u8; len as usize];
301    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.msg_method_name_copy` with a 0-offset.
302    unsafe {
303        ic0::msg_method_name_copy(buf.as_mut_ptr() as usize, 0, len as usize);
304    }
305    String::from_utf8_lossy(&buf).into_owned()
306}
307
308/// Accepts the message in `canister_inspect_message`.
309///
310/// This function is only available in the `canister_inspect_message` context.
311/// This function traps if invoked twice.
312pub fn accept_message() {
313    // SAFETY: `ic0.accept_message` is always safe to call.
314    unsafe { ic0::accept_message() }
315}
316
317/// Gets the current size of the stable memory (in WebAssembly pages).
318///
319/// One WebAssembly page is 64KiB.
320pub fn stable_size() -> u64 {
321    // SAFETY: `ic0.stable64_size` is always safe to call.
322    unsafe { ic0::stable64_size() }
323}
324
325/// Attempts to grow the stable memory by `new_pages` many pages containing zeroes.
326///
327/// One WebAssembly page is 64KiB.
328///
329/// If successful, returns the previous size of the memory (in pages).
330/// Otherwise, returns `u64::MAX`.
331pub fn stable_grow(new_pages: u64) -> u64 {
332    // SAFETY: `ic0.stable64_grow` is always safe to call.
333    unsafe { ic0::stable64_grow(new_pages) }
334}
335
336/// Writes data to the stable memory location specified by an offset.
337///
338/// # Warning
339/// This will panic if `offset + buf.len()` exceeds the current size of stable memory.
340/// Call [`stable_grow`] to request more stable memory if needed.
341pub fn stable_write(offset: u64, buf: &[u8]) {
342    // SAFETY: `buf`, being &[u8], is a readable sequence of bytes, and therefore valid to pass to `ic0.stable64_write`.
343    unsafe {
344        ic0::stable64_write(offset, buf.as_ptr() as u64, buf.len() as u64);
345    }
346}
347
348/// Reads data from the stable memory location specified by an offset.
349///
350/// # Warning
351/// This will panic if `offset + buf.len()` exceeds the current size of stable memory.
352pub fn stable_read(offset: u64, buf: &mut [u8]) {
353    // SAFETY: `buf`, being &mut [u8], is a writable sequence of bytes, and therefore valid to pass to ic0.stable64_read.
354    unsafe {
355        ic0::stable64_read(buf.as_ptr() as u64, offset, buf.len() as u64);
356    }
357}
358
359/// Gets the public key (a DER-encoded BLS key) of the root key of this instance of the Internet Computer Protocol.
360///
361/// # Note
362///
363/// This traps in non-replicated mode.
364pub fn root_key() -> Vec<u8> {
365    // SAFETY: `ic0.root_key_size` is always safe to call.
366    let len = unsafe { ic0::root_key_size() };
367    let mut buf = vec![0u8; len];
368    // SAFETY: `buf` is a mutable reference to a `len`-byte buffer, it is safe to be passed to `ic0.root_key_copy` with a 0-offset.
369    unsafe {
370        ic0::root_key_copy(buf.as_mut_ptr() as usize, 0, len);
371    }
372    buf
373}
374
375/// Sets the certified data of this canister.
376///
377/// Canisters can store up to 32 bytes of data that is certified by
378/// the system on a regular basis.  One can call [data_certificate]
379/// function from a query call to get a certificate authenticating the
380/// value set by calling this function.
381///
382/// This function can only be called from the following contexts:
383///. - "canister_init", "canister_pre_upgrade" and "canister_post_upgrade"
384///    hooks.
385///. - "canister_update" calls.
386///. - reply or reject callbacks.
387///
388/// # Panics
389///
390///.- This function traps if data.len() > 32.
391///.- This function traps if it's called from an illegal context
392///   (e.g., from a query call).
393pub fn certified_data_set<T: AsRef<[u8]>>(data: T) {
394    let buf = data.as_ref();
395    // SAFETY: `buf` is a slice ref, its pointer and length are valid to pass to ic0.certified_data_set.
396    unsafe { ic0::certified_data_set(buf.as_ptr() as usize, buf.len()) }
397}
398
399/// When called from a query call, returns the data certificate authenticating
400/// certified_data set by this canister.
401///
402/// Returns `None` if called not from a query call.
403pub fn data_certificate() -> Option<Vec<u8>> {
404    // SAFETY: ic0.data_certificate_present is always safe to call.
405    if unsafe { ic0::data_certificate_present() } == 0 {
406        return None;
407    }
408    // SAFETY: ic0.data_certificate_size is always safe to call.
409    let n = unsafe { ic0::data_certificate_size() };
410    let mut buf = vec![0u8; n];
411    // SAFETY: Because `buf` is mutable and allocated to `n` bytes, it is valid to receive from ic0.data_certificate_bytes with no offset
412    unsafe {
413        ic0::data_certificate_copy(buf.as_mut_ptr() as usize, 0, n);
414    }
415    Some(buf)
416}
417
418/// Gets current timestamp, in nanoseconds since the epoch (1970-01-01)
419pub fn time() -> u64 {
420    // SAFETY: ic0.time is always safe to call.
421    unsafe { ic0::time() }
422}
423
424/// Sets global timer.
425///
426/// The canister can set a global timer to make the system
427/// schedule a call to the exported `canister_global_timer`
428/// Wasm method after the specified time.
429/// The time must be provided as nanoseconds since 1970-01-01.
430///
431/// The function returns the previous value of the timer.
432/// If no timer is set before invoking the function, then the function returns zero.
433///
434/// Passing zero as an argument to the function deactivates the timer and thus
435/// prevents the system from scheduling calls to the canister's `canister_global_timer` Wasm method.
436pub fn global_timer_set(timestamp: u64) -> u64 {
437    // SAFETY: ic0.global_timer_set is always safe to call.
438    unsafe { ic0::global_timer_set(timestamp) }
439}
440
441/// Gets the value of specified performance counter.
442///
443/// See [`PerformanceCounterType`] for available counter types.
444#[inline]
445pub fn performance_counter(counter_type: impl Into<PerformanceCounterType>) -> u64 {
446    let counter_type: u32 = counter_type.into().into();
447    // SAFETY: ic0.performance_counter is always safe to call.
448    unsafe { ic0::performance_counter(counter_type) }
449}
450
451/// The type of performance counter.
452#[derive(Debug, PartialEq, Eq, Clone, Copy)]
453#[repr(u32)]
454pub enum PerformanceCounterType {
455    /// Current execution instruction counter.
456    ///
457    /// The number of WebAssembly instructions the canister has executed
458    /// since the beginning of the current Message execution.
459    InstructionCounter,
460    /// Call context instruction counter
461    ///
462    /// The number of WebAssembly instructions the canister has executed
463    /// within the call context of the current Message execution
464    /// since Call context creation.
465    /// The counter monotonically increases across all message executions
466    /// in the call context until the corresponding call context is removed.
467    CallContextInstructionCounter,
468    /// A performance counter type that is not recognized by this library.
469    Unrecognized(u32),
470}
471
472impl From<u32> for PerformanceCounterType {
473    fn from(value: u32) -> Self {
474        match value {
475            0 => Self::InstructionCounter,
476            1 => Self::CallContextInstructionCounter,
477            _ => Self::Unrecognized(value),
478        }
479    }
480}
481
482impl From<PerformanceCounterType> for u32 {
483    fn from(value: PerformanceCounterType) -> Self {
484        match value {
485            PerformanceCounterType::InstructionCounter => 0,
486            PerformanceCounterType::CallContextInstructionCounter => 1,
487            PerformanceCounterType::Unrecognized(value) => value,
488        }
489    }
490}
491
492impl PartialEq<u32> for PerformanceCounterType {
493    fn eq(&self, other: &u32) -> bool {
494        let self_as_u32: u32 = (*self).into();
495        self_as_u32 == *other
496    }
497}
498
499/// Returns the number of instructions that the canister executed since the last [entry
500/// point](https://internetcomputer.org/docs/current/references/ic-interface-spec/#entry-points).
501#[inline]
502pub fn instruction_counter() -> u64 {
503    performance_counter(0)
504}
505
506/// Returns the number of WebAssembly instructions the canister has executed
507/// within the call context of the current Message execution since
508/// Call context creation.
509///
510/// The counter monotonically increases across all message executions
511/// in the call context until the corresponding call context is removed.
512#[inline]
513pub fn call_context_instruction_counter() -> u64 {
514    performance_counter(1)
515}
516
517/// Determines if a Principal is a controller of the canister.
518pub fn is_controller(principal: &Principal) -> bool {
519    let slice = principal.as_slice();
520    // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`.
521    unsafe { ic0::is_controller(slice.as_ptr() as usize, slice.len()) != 0 }
522}
523
524/// Checks if in replicated execution.
525///
526/// The canister can check whether it is currently running in replicated or non replicated execution.
527pub fn in_replicated_execution() -> bool {
528    // SAFETY: `ic0.in_replicated_execution` is always safe to call.
529    match unsafe { ic0::in_replicated_execution() } {
530        0 => false,
531        1 => true,
532        _ => unreachable!(),
533    }
534}
535
536/// Gets the amount of cycles that a canister needs to be above the freezing threshold in order to successfully make an inter-canister call.
537pub fn cost_call(method_name_size: u64, payload_size: u64) -> u128 {
538    let mut dst = 0u128;
539    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_call`.
540    unsafe {
541        ic0::cost_call(
542            method_name_size,
543            payload_size,
544            &mut dst as *mut u128 as usize,
545        )
546    }
547    dst
548}
549
550/// Gets the cycle cost of the Management canister method [`creating_canister`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-create_canister).
551///
552/// # Note
553///
554/// [`create_canister`](crate::management_canister::create_canister) and
555/// [`create_canister_with_extra_cycles`](crate::management_canister::create_canister_with_extra_cycles)
556/// invoke this function inside and attach the required cycles to the call.
557pub fn cost_create_canister() -> u128 {
558    let mut dst = 0u128;
559    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_create_canister`.
560    unsafe { ic0::cost_create_canister(&mut dst as *mut u128 as usize) }
561    dst
562}
563
564/// Gets the cycle cost of the Management canister method [`http_request`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-http_request).
565///
566/// # Note
567///
568/// [`http_request`](crate::management_canister::http_request) and [`http_request_with_closure`](crate::management_canister::http_request_with_closure)
569/// invoke this function inside and attach the required cycles to the call.
570pub fn cost_http_request(request_size: u64, max_res_bytes: u64) -> u128 {
571    let mut dst = 0u128;
572    // SAFETY: `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_http_request`.
573    unsafe { ic0::cost_http_request(request_size, max_res_bytes, &mut dst as *mut u128 as usize) }
574    dst
575}
576
577/// The error type for [`cost_sign_with_ecdsa`] and [`cost_sign_with_schnorr`].
578#[derive(thiserror::Error, Debug, Clone)]
579pub enum SignCostError {
580    /// The ECDSA/vetKD curve or Schnorr algorithm is invalid.
581    #[error("invalid curve or algorithm")]
582    InvalidCurveOrAlgorithm,
583
584    /// The key name is invalid for the provided curve or algorithm.
585    #[error("invalid key name")]
586    InvalidKeyName,
587    /// Unrecognized error.
588    ///
589    /// This error is returned when the System API returns an unrecognized error code.
590    /// Please report to ic-cdk maintainers.
591    #[error("unrecognized error: {0}")]
592    UnrecognizedError(u32),
593}
594
595/// Helper function to handle the result of a signature cost function.
596fn sign_cost_result(dst: u128, code: u32) -> Result<u128, SignCostError> {
597    match code {
598        0 => Ok(dst),
599        1 => Err(SignCostError::InvalidCurveOrAlgorithm),
600        2 => Err(SignCostError::InvalidKeyName),
601        _ => Err(SignCostError::UnrecognizedError(code)),
602    }
603}
604
605/// Gets the cycle cost of the Management canister method [`sign_with_ecdsa`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-sign_with_ecdsa).
606///
607/// # Note
608///
609/// Alternatively, [`management_canister::cost_sign_with_ecdsa`](crate::management_canister::cost_sign_with_ecdsa) provides a higher-level API that wraps this function.
610///
611/// # Errors
612///
613/// This function will return an error if the `key_name` or the `ecdsa_curve` is invalid.
614/// The error type [`SignCostError`] provides more information about the reason of the error.
615pub fn cost_sign_with_ecdsa<T: AsRef<str>>(
616    key_name: T,
617    ecdsa_curve: u32,
618) -> Result<u128, SignCostError> {
619    let buf = key_name.as_ref();
620    let mut dst = 0u128;
621    // SAFETY:
622    // `buf`, being &str, is a readable sequence of UTF8 bytes and therefore can be passed to `ic0.cost_sign_with_ecdsa`.
623    // `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_sign_with_ecdsa`.
624    let code = unsafe {
625        ic0::cost_sign_with_ecdsa(
626            buf.as_ptr() as usize,
627            buf.len(),
628            ecdsa_curve,
629            &mut dst as *mut u128 as usize,
630        )
631    };
632    sign_cost_result(dst, code)
633}
634
635/// Gets the cycle cost of the Management canister method [`sign_with_schnorr`](https://internetcomputer.org/docs/references/ic-interface-spec#ic-sign_with_schnorr).
636///
637/// # Note
638///
639/// Alternatively, [`management_canister::cost_sign_with_schnorr`](crate::management_canister::cost_sign_with_schnorr) provides a higher-level API that wraps this function.
640///
641/// # Errors
642///
643/// This function will return an error if the `key_name` or the `algorithm` is invalid.
644/// The error type [`SignCostError`] provides more information about the reason of the error.
645pub fn cost_sign_with_schnorr<T: AsRef<str>>(
646    key_name: T,
647    algorithm: u32,
648) -> Result<u128, SignCostError> {
649    let buf = key_name.as_ref();
650    let mut dst = 0u128;
651    // SAFETY:
652    // `buf`, being &str, is a readable sequence of UTF8 bytes and therefore can be passed to `ic0.cost_sign_with_schnorr`.
653    // `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_sign_with_schnorr`.
654    let code = unsafe {
655        ic0::cost_sign_with_schnorr(
656            buf.as_ptr() as usize,
657            buf.len(),
658            algorithm,
659            &mut dst as *mut u128 as usize,
660        )
661    };
662    sign_cost_result(dst, code)
663}
664
665/// Gets the cycle cost of the Management canister method [`vetkd_derive_key`](https://github.com/dfinity/portal/pull/3763).
666///
667/// Later, the description will be available in [the interface spec](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-vetkd_derive_key).
668///
669/// # Note
670///
671/// Alternatively, [`management_canister::cost_vetkd_derive_key`](crate::management_canister::cost_vetkd_derive_key) provides a higher-level API that wraps this function.
672///
673/// # Errors
674///
675/// This function will return an error if the `key_name` or the `vetkd_curve` is invalid.
676/// The error type [`SignCostError`] provides more information about the reason of the error.
677pub fn cost_vetkd_derive_key<T: AsRef<str>>(
678    key_name: T,
679    vetkd_curve: u32,
680) -> Result<u128, SignCostError> {
681    let buf = key_name.as_ref();
682    let mut dst = 0u128;
683    // SAFETY:
684    // `buf`, being &str, is a readable sequence of UTF8 bytes and therefore can be passed to `ic0.cost_vetkd_derive_key`.
685    // `dst` is a mutable reference to a 16-byte buffer, which is the expected size for `ic0.cost_vetkd_derive_key`.
686    let code = unsafe {
687        ic0::cost_vetkd_derive_key(
688            buf.as_ptr() as usize,
689            buf.len(),
690            vetkd_curve,
691            &mut dst as *mut u128 as usize,
692        )
693    };
694    sign_cost_result(dst, code)
695}
696
697/// Emits textual trace messages.
698///
699/// On the "real" network, these do not do anything.
700///
701/// When executing in an environment that supports debugging, this copies out the data
702/// and logs, prints or stores it in an environment-appropriate way.
703pub fn debug_print<T: AsRef<str>>(data: T) {
704    let buf = data.as_ref();
705    // SAFETY: `buf` is a readable sequence of bytes and therefore can be passed to ic0.debug_print.
706    unsafe {
707        ic0::debug_print(buf.as_ptr() as usize, buf.len());
708    }
709}
710
711/// Traps with the given message.
712///
713/// The environment may copy out the data and log, print or store it in an environment-appropriate way,
714/// or include it in system-generated reject messages where appropriate.
715pub fn trap<T: AsRef<str>>(data: T) -> ! {
716    let buf = data.as_ref();
717    // SAFETY: `buf` is a readable sequence of bytes and therefore can be passed to ic0.trap.
718    unsafe {
719        ic0::trap(buf.as_ptr() as usize, buf.len());
720    }
721    unreachable!()
722}
723
724// # Deprecated API bindings
725//
726// The following functions are deprecated and will be removed in the future.
727// They are kept here for compatibility with existing code.
728
729/// Prints the given message.
730#[deprecated(since = "0.18.0", note = "Use `debug_print` instead")]
731pub fn print<S: std::convert::AsRef<str>>(s: S) {
732    let s = s.as_ref();
733    // SAFETY: `s`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.debug_print.
734    unsafe {
735        ic0::debug_print(s.as_ptr() as usize, s.len());
736    }
737}
738
739/// Returns the caller of the current call.
740#[deprecated(since = "0.18.0", note = "Use `msg_caller` instead")]
741pub fn caller() -> Principal {
742    // SAFETY: ic0.msg_caller_size is always safe to call.
743    let len = unsafe { ic0::msg_caller_size() };
744    let mut bytes = vec![0u8; len];
745    // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.msg_caller_copy` with a 0-offset.
746    unsafe {
747        ic0::msg_caller_copy(bytes.as_mut_ptr() as usize, 0, len);
748    }
749    Principal::try_from(&bytes).unwrap()
750}
751
752/// Returns the canister id as a blob.
753#[deprecated(since = "0.18.0", note = "Use `canister_self` instead")]
754pub fn id() -> Principal {
755    // SAFETY: ic0.canister_self_size is always safe to call.
756    let len = unsafe { ic0::canister_self_size() };
757    let mut bytes = vec![0u8; len];
758    // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.canister_self_copy` with a 0-offset.
759    unsafe {
760        ic0::canister_self_copy(bytes.as_mut_ptr() as usize, 0, len);
761    }
762    Principal::try_from(&bytes).unwrap()
763}
764
765/// Gets the amount of funds available in the canister.
766///
767/// # Panic
768///
769/// When the cycle balance is greater than `u64::MAX`, this function will panic.
770/// As this function is deprecated, it is recommended to use [`canister_cycle_balance`].
771#[deprecated(since = "0.18.0", note = "Use `canister_cycle_balance` instead")]
772pub fn canister_balance() -> u64 {
773    // ic0 no longer provides `ic0.canister_cycle_balance` which returns a u64,
774    // so we use the u128 version and convert it to u64.
775    // When the cycle balance is greater than `u64::MAX`, `ic0.canister_cycle_balance` also panics.
776    canister_cycle_balance()
777        .try_into()
778        .expect("the cycle balance is greater than u64::MAX, please use canister_cycle_balance which returns u128")
779}
780
781/// Gets the amount of funds available in the canister.
782#[deprecated(since = "0.18.0", note = "Use `canister_cycle_balance` instead")]
783pub fn canister_balance128() -> u128 {
784    canister_cycle_balance()
785}
786
787/// Sets the certified data of this canister.
788///
789/// Canisters can store up to 32 bytes of data that is certified by
790/// the system on a regular basis.  One can call [data_certificate]
791/// function from a query call to get a certificate authenticating the
792/// value set by calling this function.
793///
794/// This function can only be called from the following contexts:
795///. - "canister_init", "canister_pre_upgrade" and "canister_post_upgrade"
796///    hooks.
797///. - "canister_update" calls.
798///. - reply or reject callbacks.
799///
800/// # Panics
801///
802///.- This function traps if data.len() > 32.
803///.- This function traps if it's called from an illegal context
804///   (e.g., from a query call).
805#[deprecated(since = "0.18.0", note = "Use `certified_data_set` instead")]
806pub fn set_certified_data(data: &[u8]) {
807    // SAFETY: because data is a slice ref, its pointer and length are valid to pass to ic0.certified_data_set.
808    unsafe { ic0::certified_data_set(data.as_ptr() as usize, data.len()) }
809}
810
811/// Sets global timer.
812///
813/// The canister can set a global timer to make the system
814/// schedule a call to the exported canister_global_timer
815/// Wasm method after the specified time.
816/// The time must be provided as nanoseconds since 1970-01-01.
817///
818/// The function returns the previous value of the timer.
819/// If no timer is set before invoking the function, then the function returns zero.
820///
821/// Passing zero as an argument to the function deactivates the timer and thus
822/// prevents the system from scheduling calls to the canister's canister_global_timer Wasm method.
823#[deprecated(since = "0.18.0", note = "Use `global_timer_set` instead")]
824pub fn set_global_timer(timestamp: u64) -> u64 {
825    // SAFETY: ic0.global_timer_set is always safe to call.
826    unsafe { ic0::global_timer_set(timestamp) }
827}