diff --git a/extensions-utils/src/dependencies/download_wasms/nns.rs b/extensions-utils/src/dependencies/download_wasms/nns.rs index 06db139..6647a6b 100644 --- a/extensions-utils/src/dependencies/download_wasms/nns.rs +++ b/extensions-utils/src/dependencies/download_wasms/nns.rs @@ -152,6 +152,13 @@ pub const NNS_DAPP: StandardCanister = StandardCanister { wasm_name: "nns-dapp_local.wasm", wasm_url: "https://github.com/dfinity/nns-dapp/releases/download/tip/nns-dapp_t2.wasm", }; +/// Canister that can be used instead of cycle wallets +pub const CYCLES_LEDGER: StandardCanister = StandardCanister { + canister_name: "cycles_ledger", + canister_id: "um5iw-rqaaa-aaaaq-qaaba-cai", + wasm_name: "cycles_ledger.wasm.gz", + wasm_url: "https://github.com/dfinity/cycles-ledger/releases/download/cycles-ledger-v0.2.8/cycles-ledger.wasm.gz", +}; /// Backend canisters deployed by `ic nns init`. pub const NNS_CORE: &[&IcNnsInitCanister; 11] = &[ &NNS_REGISTRY, // 0 diff --git a/extensions/nns/src/install_nns.rs b/extensions/nns/src/install_nns.rs index 5041141..7a9a282 100644 --- a/extensions/nns/src/install_nns.rs +++ b/extensions/nns/src/install_nns.rs @@ -10,6 +10,7 @@ use dfx_core::canister::install_canister_wasm; use dfx_core::config::model::dfinity::{NetworksConfig, ReplicaSubnetType}; use dfx_core::config::model::network_descriptor::NetworkDescriptor; use dfx_core::identity::CallSender; +use dfx_extensions_utils::dependencies::download_wasms::nns::{CYCLES_LEDGER, NNS_CYCLES_MINTING}; use dfx_extensions_utils::{ call_extension_bundled_binary, download_nns_wasms, nns_wasm_dir, IcNnsInitCanister, SnsCanisterInstallation, StandardCanister, ED25519_TEST_ACCOUNT, NNS_CORE, NNS_FRONTEND, @@ -19,7 +20,7 @@ use dfx_extensions_utils::{ use anyhow::{anyhow, bail, Context}; use backoff::backoff::Backoff; use backoff::ExponentialBackoff; -use candid::Encode; +use candid::{CandidType, Encode}; use fn_error_context::context; use futures_util::future::try_join_all; use ic_agent::export::Principal; @@ -27,6 +28,7 @@ use ic_agent::Agent; use ic_utils::interfaces::management_canister::builders::InstallMode; use ic_utils::interfaces::ManagementCanister; use reqwest::Url; +use sha2::{Digest, Sha256}; use slog::Logger; use std::ffi::OsString; use std::fs; @@ -115,6 +117,7 @@ pub async fn install_nns( eprintln!("Configuring the NNS..."); set_xdr_rate(1234567, &nns_url, dfx_cache_path)?; set_cmc_authorized_subnets(&nns_url, &subnet_id, dfx_cache_path)?; + set_cycles_ledger_canister_id_in_cmc(&nns_url, dfx_cache_path)?; print_nns_details(provider_url)?; Ok(()) @@ -394,7 +397,7 @@ pub async fn download(source: &Url, target: &Path) -> anyhow::Result<()> { /// Arguments for the ic-nns-init command line function. pub struct IcNnsInitOpts { - /// An URL to accees one or more NNS subnet replicas. + /// An URL to access one or more NNS subnet replicas. nns_url: String, /// A directory that needs to be populated will all required wasms before calling ic-nns-init. wasm_dir: PathBuf, @@ -483,6 +486,60 @@ pub fn set_cmc_authorized_subnets( .map_err(|e| anyhow!("Call to propose to set authorized subnets failed: {e}")) } +/// Sets the cycles ledger canister id in the CMC +#[context("Failed to set the cycles ledger canister id in the CMC")] +pub fn set_cycles_ledger_canister_id_in_cmc( + nns_url: &Url, + dfx_cache_path: &Path, +) -> anyhow::Result<()> { + #[derive(CandidType, Clone, Debug, PartialEq, Eq)] + struct CyclesCanisterInitPayload { + pub cycles_ledger_canister_id: Option, + } + + let wasm_path = nns_wasm_dir(dfx_cache_path); + let cmc_wasm_path = wasm_path.join(NNS_CYCLES_MINTING.wasm_name); + let cmc_wasm_bytes = dfx_core::fs::read(&cmc_wasm_path)?; + let wasm_hash = Sha256::digest(cmc_wasm_bytes); + let mut upgrade_arg_file = tempfile::NamedTempFile::new()?; + upgrade_arg_file + .write_all( + &Encode!(&(Some(CyclesCanisterInitPayload { + cycles_ledger_canister_id: Some( + Principal::from_text(CYCLES_LEDGER.canister_id).unwrap() + ), + }),)) + .unwrap(), + ) + .context("Failed to write to tempfile.")?; + + let cmc_wasm_path_str = cmc_wasm_path.to_string_lossy(); + let wasm_hash_str = hex::encode(wasm_hash); + let upgrade_arg_file_str = upgrade_arg_file.path().to_string_lossy(); + let args = vec![ + "--nns-url", + nns_url.as_str(), + "propose-to-change-nns-canister", + "--test-neuron-proposer", + "--proposal-title", + "Set cycles ledger canister id in Cycles Minting Canister", + "--summary", + "Set cycles ledger canister id in Cycles Minting Canister", + "--mode", + "upgrade", + "--canister-id", + NNS_CYCLES_MINTING.canister_id, + "--wasm-module-path", + &cmc_wasm_path_str, + "--wasm-module-sha256", + &wasm_hash_str, + "--arg", + &upgrade_arg_file_str, + ]; + call_extension_bundled_binary("ic-admin", args, dfx_cache_path) + .map_err(|e| anyhow!("Call to set the cycles ledger canister id in the CMC: {e}")) +} + /// Uploads wasms to the nns-sns-wasm canister. #[context("Failed to upload wasm files to the nns-sns-wasm canister; it may not be possible to create an SNS.")] pub fn upload_nns_sns_wasms_canister_wasms(dfx_cache_path: &Path) -> anyhow::Result<()> {