use super::*;
use crate::{execute_fee, log, OfflineQuery, PrivateKey, RecordPlaintext, Transaction};
use crate::types::native::{
CurrentAleo,
CurrentNetwork,
ProcessNative,
ProgramIDNative,
ProgramNative,
ProgramOwnerNative,
RecordPlaintextNative,
TransactionNative,
};
use js_sys::Object;
use rand::{rngs::StdRng, SeedableRng};
use std::str::FromStr;
#[wasm_bindgen]
impl ProgramManager {
#[wasm_bindgen(js_name = buildDeploymentTransaction)]
#[allow(clippy::too_many_arguments)]
pub async fn deploy(
private_key: &PrivateKey,
program: &str,
fee_credits: f64,
fee_record: Option<RecordPlaintext>,
url: Option<String>,
imports: Option<Object>,
fee_proving_key: Option<ProvingKey>,
fee_verifying_key: Option<VerifyingKey>,
offline_query: Option<OfflineQuery>,
) -> Result<Transaction, String> {
log("Creating deployment transaction");
let fee_microcredits = match &fee_record {
Some(fee_record) => Self::validate_amount(fee_credits, fee_record, true)?,
None => (fee_credits * 1_000_000.0) as u64,
};
let mut process_native = ProcessNative::load_web().map_err(|err| err.to_string())?;
let process = &mut process_native;
log("Checking program has a valid name");
let program = ProgramNative::from_str(program).map_err(|err| err.to_string())?;
log("Checking program imports are valid and add them to the process");
ProgramManager::resolve_imports(process, &program, imports)?;
let rng = &mut StdRng::from_entropy();
log("Creating deployment");
let node_url = url.as_deref().unwrap_or(DEFAULT_URL);
let deployment = process.deploy::<CurrentAleo, _>(&program, rng).map_err(|err| err.to_string())?;
if deployment.program().functions().is_empty() {
return Err("Attempted to create an empty transaction deployment".to_string());
}
log("Ensuring the fee is sufficient to pay for the deployment");
let (minimum_deployment_cost, (_, _, _)) =
deployment_cost::<CurrentNetwork>(&deployment).map_err(|err| err.to_string())?;
if fee_microcredits < minimum_deployment_cost {
return Err(format!(
"Fee is too low to pay for the deployment. The minimum fee is {} credits",
minimum_deployment_cost as f64 / 1_000_000.0
));
}
let deployment_id = deployment.to_deployment_id().map_err(|e| e.to_string())?;
let fee = execute_fee!(
process,
private_key,
fee_record,
fee_microcredits,
node_url,
fee_proving_key,
fee_verifying_key,
deployment_id,
rng,
offline_query
);
let owner = ProgramOwnerNative::new(private_key, deployment_id, &mut StdRng::from_entropy())
.map_err(|err| err.to_string())?;
log("Verifying the deployment and fees");
process
.verify_deployment::<CurrentAleo, _>(&deployment, &mut StdRng::from_entropy())
.map_err(|err| err.to_string())?;
log("Creating deployment transaction");
Ok(Transaction::from(
TransactionNative::from_deployment(owner, deployment, fee).map_err(|err| err.to_string())?,
))
}
#[wasm_bindgen(js_name = estimateDeploymentFee)]
pub async fn estimate_deployment_fee(program: &str, imports: Option<Object>) -> Result<u64, String> {
log(
"Disclaimer: Fee estimation is experimental and may not represent a correct estimate on any current or future network",
);
let mut process_native = ProcessNative::load_web().map_err(|err| err.to_string())?;
let process = &mut process_native;
log("Check program has a valid name");
let program = ProgramNative::from_str(program).map_err(|err| err.to_string())?;
log("Check program imports are valid and add them to the process");
ProgramManager::resolve_imports(process, &program, imports)?;
log("Create sample deployment");
let deployment =
process.deploy::<CurrentAleo, _>(&program, &mut StdRng::from_entropy()).map_err(|err| err.to_string())?;
if deployment.program().functions().is_empty() {
return Err("Attempted to create an empty transaction deployment".to_string());
}
log("Estimate the deployment fee");
let (minimum_deployment_cost, (_, _, _)) =
deployment_cost::<CurrentNetwork>(&deployment).map_err(|err| err.to_string())?;
Ok(minimum_deployment_cost)
}
#[wasm_bindgen(js_name = estimateProgramNameCost)]
pub fn program_name_cost(name: &str) -> Result<u64, String> {
log(
"Disclaimer: Fee estimation is experimental and may not represent a correct estimate on any current or future network",
);
let num_characters = name.chars().count() as u32;
let namespace_cost = 10u64
.checked_pow(10u32.saturating_sub(num_characters))
.ok_or("The namespace cost computation overflowed for a deployment")?
.saturating_mul(1_000_000); Ok(namespace_cost)
}
}