junobuild_shared/mgmt/
cmc.rsuse crate::constants::{IC_TRANSACTION_FEE_ICP, MEMO_CANISTER_TOP_UP};
use crate::env::CMC;
use crate::ledger::icp::transfer_payment;
use crate::mgmt::ic::install_code;
use crate::mgmt::settings::{create_canister_cycles, create_canister_settings};
use crate::mgmt::types::cmc::{
CreateCanister, CreateCanisterResult, Cycles, NotifyError, SubnetId, SubnetSelection,
TopUpCanisterArgs,
};
use crate::mgmt::types::ic::WasmArg;
use candid::Principal;
use ic_cdk::api::call::{call_with_payment128, CallResult};
use ic_cdk::api::management_canister::main::{CanisterId, CanisterInstallMode};
use ic_cdk::call;
use ic_ledger_types::{Subaccount, Tokens};
pub async fn top_up_canister(canister_id: &CanisterId, amount: &Tokens) -> Result<(), String> {
let send_amount = Tokens::from_e8s(amount.e8s() - (2 * IC_TRANSACTION_FEE_ICP.e8s()));
let cmc = Principal::from_text(CMC).unwrap();
let to_sub_account: Subaccount = convert_principal_to_sub_account(canister_id.as_slice());
let block_index = transfer_payment(
&cmc,
&to_sub_account,
MEMO_CANISTER_TOP_UP,
send_amount,
IC_TRANSACTION_FEE_ICP,
)
.await
.map_err(|e| format!("failed to call ledger: {:?}", e))?
.map_err(|e| format!("ledger transfer error {:?}", e))?;
let args = TopUpCanisterArgs {
block_index,
canister_id: *canister_id,
};
let result: CallResult<(Result<Cycles, NotifyError>,)> =
call(cmc, "notify_top_up", (args,)).await;
match result {
Err((_, message)) => {
Err(["Top-up failed.", &message].join(" - "))
}
Ok(_) => Ok(()),
}
}
fn convert_principal_to_sub_account(principal_id: &[u8]) -> Subaccount {
let mut bytes = [0u8; 32];
bytes[0] = principal_id.len().try_into().unwrap();
bytes[1..1 + principal_id.len()].copy_from_slice(principal_id);
Subaccount(bytes)
}
pub async fn cmc_create_canister_install_code(
controllers: Vec<Principal>,
wasm_arg: &WasmArg,
cycles: u128,
subnet_id: &SubnetId,
) -> Result<Principal, String> {
let cmc = Principal::from_text(CMC).unwrap();
let create_canister_arg = CreateCanister {
subnet_type: None,
subnet_selection: Some(SubnetSelection::Subnet { subnet: *subnet_id }),
settings: create_canister_settings(controllers),
};
let result: CallResult<(CreateCanisterResult,)> = call_with_payment128(
cmc,
"create_canister",
(create_canister_arg,),
create_canister_cycles(cycles),
)
.await;
match result {
Err((_, message)) => Err(["Failed to call CMC to create canister.", &message].join(" - ")),
Ok((result,)) => match result {
Err(err) => Err(format!("Failed to create canister with CMC - {}", err)),
Ok(canister_id) => {
let install =
install_code(canister_id, wasm_arg, CanisterInstallMode::Install).await;
match install {
Err(_) => {
Err("Failed to install code in canister created with CMC.".to_string())
}
Ok(_) => Ok(canister_id),
}
}
},
}
}