ic_agent/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! The `ic-agent` is a simple-to-use library that enables you to
//! build applications and interact with the [Internet Computer](https://internetcomputer.org)
//! in Rust. It serves as a Rust-based low-level backend for the
//! DFINITY Canister Software Development Kit (SDK) and the command-line execution environment
//! [`dfx`](https://internetcomputer.org/docs/current/developer-docs/setup/install).
//!
//! ## Overview
//! The `ic-agent` is a Rust crate that can connect directly to the Internet
//! Computer through the Internet Computer protocol (ICP).
//! The key software components of the ICP are broadly referred to as the
//! [replica](https://internetcomputer.org/docs/current/concepts/nodes-subnets).
//!
//! The agent is designed to be compatible with multiple versions of the
//! replica API, and to expose both low-level APIs for communicating with
//! Internet Computer protocol components like the replica and to provide
//! higher-level APIs for communicating with software applications deployed
//! as [canisters](https://internetcomputer.org/docs/current/concepts/canisters-code).
//!
//! ## Example
//! The following example illustrates how to use the Agent interface to send
//! a call to an Internet Computer canister that performs network management
//! operations. In this example, the call to the Internet Computer management
//! canister (`aaaaa-aa`) creates a placeholder for a new canister by
//! registering a network-specific identifier. The management canister then
//! returns the result in the form of the textual representation of the canister
//! identifier to the caller.
//!
//! ```ignore
//! # // This test is ignored because it requires an ic to be running. We run these
//! # // in the ic-ref workflow.
//! use ic_agent::{Agent, export::Principal};
//! use candid::{Encode, Decode, CandidType, Nat};
//! use serde::Deserialize;
//!
//! #[derive(CandidType)]
//! struct Argument {
//!   amount: Option<Nat>,
//! }
//!
//! #[derive(CandidType, Deserialize)]
//! struct CreateCanisterResult {
//!   canister_id: Principal,
//! }
//!
//! # fn create_identity() -> impl ic_agent::Identity {
//! #     let rng = ring::rand::SystemRandom::new();
//! #     let key_pair = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng)
//! #         .expect("Could not generate a key pair.");
//! #
//! #     ic_agent::identity::BasicIdentity::from_key_pair(
//! #         ring::signature::Ed25519KeyPair::from_pkcs8(key_pair.as_ref())
//! #           .expect("Could not read the key pair."),
//! #     )
//! # }
//! #
//! async fn create_a_canister() -> Result<Principal, Box<dyn std::error::Error>> {
//! # let url = format!("http://localhost:{}", option_env!("IC_REF_PORT").unwrap_or("4943"));
//!   let agent = Agent::builder()
//!     .with_url(url)
//!     .with_identity(create_identity())
//!     .build()?;
//!   // Only do the following call when not contacting the IC main net (e.g. a local emulator).
//!   // This is important as the main net public key is static and a rogue network could return
//!   // a different key.
//!   // If you know the root key ahead of time, you can use `agent.set_root_key(root_key);`.
//!   agent.fetch_root_key().await?;
//!   let management_canister_id = Principal::from_text("aaaaa-aa")?;
//!
//!   // Create a call to the management canister to create a new canister ID,
//!   // and wait for a result.
//!   // The effective canister id must belong to the canister ranges of the subnet at which the canister is created.
//!   let effective_canister_id = Principal::from_text("rwlgt-iiaaa-aaaaa-aaaaa-cai").unwrap();
//!   let response = agent.update(&management_canister_id, "provisional_create_canister_with_cycles")
//!     .with_effective_canister_id(effective_canister_id)
//!     .with_arg(Encode!(&Argument { amount: None})?)
//!     .await?;
//!
//!   let result = Decode!(response.as_slice(), CreateCanisterResult)?;
//!   let canister_id: Principal = result.canister_id;
//!   Ok(canister_id)
//! }
//!
//! # let mut runtime = tokio::runtime::Runtime::new().unwrap();
//! # runtime.block_on(async {
//! let canister_id = create_a_canister().await.unwrap();
//! eprintln!("{}", canister_id);
//! # });
//! ```
//! For more information about the Agent interface used in this example, see the
//! [Agent] documentation.
//!
//! ## References
//! For an introduction to the Internet Computer and the DFINITY Canister SDK,
//! see the following resources:
//!
//! - [How the IC Works](https://internetcomputer.org/docs/current/concepts/)
//! - [DFINITY Canister SDK](https://internetcomputer.org/docs/current/references/cli-reference/)
//!
//! The Internet Computer protocol and interface specifications are not
//! publicly available yet. When these specifications are made public and
//! generally available, additional details about the versions supported will
//! be available here.

#![warn(
    missing_docs,
    rustdoc::broken_intra_doc_links,
    rustdoc::private_intra_doc_links
)]
#![cfg_attr(not(target_family = "wasm"), warn(clippy::future_not_send))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

#[cfg(all(feature = "hyper", target_family = "wasm"))]
compile_error!("Feature `hyper` cannot be used from WASM.");

pub mod agent;
pub mod export;
pub mod identity;
mod util;

use agent::response_authentication::LookupPath;
#[doc(inline)]
pub use agent::{agent_error, agent_error::AgentError, Agent, NonceFactory, NonceGenerator};
#[doc(inline)]
pub use ic_transport_types::{to_request_id, RequestId, RequestIdError, TransportCallResponse};
#[doc(inline)]
pub use identity::{Identity, Signature};

// Re-export from ic_certification for backward compatibility.
pub use ic_certification::{hash_tree, Certificate};

/// Looks up a value in the certificate's tree at the specified hash.
///
/// Returns the value if it was found; otherwise, errors with `LookupPathAbsent`, `LookupPathUnknown`, or `LookupPathError`.
pub fn lookup_value<P: LookupPath, Storage: AsRef<[u8]>>(
    tree: &ic_certification::certificate::Certificate<Storage>,
    path: P,
) -> Result<&[u8], AgentError> {
    agent::response_authentication::lookup_value(&tree.tree, path)
}