diff --git a/crates/loam-cli/src/commands/build/build_clients.rs b/crates/loam-cli/src/commands/build/build_clients.rs index d7061b08..b44f2b14 100644 --- a/crates/loam-cli/src/commands/build/build_clients.rs +++ b/crates/loam-cli/src/commands/build/build_clients.rs @@ -54,6 +54,8 @@ pub enum Error { #[error(transparent)] ConfigLocator(#[from] cli::config::locator::Error), #[error(transparent)] + ConfigAlias(#[from] cli::config::alias::Error), + #[error(transparent)] Clap(#[from] clap::Error), #[error(transparent)] WasmHash(#[from] xdrError), @@ -123,79 +125,57 @@ impl Args { Ok(()) } - - fn get_contract_alias(&self, name: &str) -> Result, Error> { - let config_dir = cli::config::locator::Args { - global: false, - config_dir: None, - }.config_dir()?; - let alias_file = config_dir.join("contract-ids").join(format!("{}.json", name)); - - if alias_file.exists() { - let content = std::fs::read_to_string(alias_file)?; - let alias_data: serde_json::Value = serde_json::from_str(&content)?; - let network_passphrase = std::env::var("STELLAR_NETWORK_PASSPHRASE") - .expect("No STELLAR_NETWORK_PASSPHRASE environment variable set"); - - if let Some(id) = alias_data["ids"].get(&network_passphrase) { - Ok(Some(id.as_str().unwrap().to_string())) - } else { - Ok(None) - } - } else { - Ok(None) - } - } - async fn contract_hash_matches(&self, contract_id: &str, hash: &str, network: &Network) -> Result { - let network_args = cli::network::Args { + + fn get_network_args(network: &Network) -> cli::network::Args { + cli::network::Args { rpc_url: network.rpc_url.clone(), network_passphrase: network.network_passphrase.clone(), network: network.name.clone(), - }; - let config_dir = cli::config::locator::Args { + } + } + + fn get_config_locator() -> cli::config::locator::Args { + cli::config::locator::Args { global: false, config_dir: None, - }; + } + } + + fn get_config_dir(network: &Network) -> cli::config::Args { + let account = std::env::var("STELLAR_ACCOUNT") + .expect("No STELLAR_ACCOUNT environment variable set"); + cli::config::Args { + network: Self::get_network_args(network), + locator: Self::get_config_locator(), + source_account: account, + hd_path: Some(0), + } + } + + fn get_contract_alias(&self, name: &str, network: &Network) -> Result, cli::config::alias::Error> { + let config_dir = Self::get_config_dir(network); + let network_passphrase = std::env::var("STELLAR_NETWORK_PASSPHRASE") + .expect("No STELLAR_NETWORK_PASSPHRASE environment variable set"); + config_dir.get_contract_id(name, &network_passphrase) + } + + async fn contract_hash_matches(&self, contract_id: &str, hash: &str, network: &Network) -> Result { let hash_vec = cli::contract::fetch::Cmd { contract_id: contract_id.to_string(), out_file: None, - locator: config_dir, - network: network_args, + locator: Self::get_config_locator(), + network: Self::get_network_args(network), } .run_against_rpc_server(None, None) .await?; let ctrct_hash = contract_hash(&hash_vec)?; - let c_hash_string = hex::encode(ctrct_hash).to_string(); - Ok(c_hash_string == hash) + Ok(hex::encode(ctrct_hash) == hash) } - fn save_contract_alias(&self, name: &str, contract_id: &str) -> Result<(), Error> { - let config_dir = cli::config::locator::Args { - global: false, - config_dir: None, - }.config_dir()?; - let alias_dir = config_dir.join("contract-ids"); - std::fs::create_dir_all(&alias_dir)?; - println!("{}", alias_dir.to_str().unwrap()); - - let alias_file = alias_dir.join(format!("{}.json", name)); - let network_passphrase = std::env::var("STELLAR_NETWORK_PASSPHRASE") - .expect("No STELLAR_NETWORK_PASSPHRASE environment variable set"); - - let mut alias_data = if alias_file.exists() { - let content = std::fs::read_to_string(&alias_file)?; - serde_json::from_str(&content)? - } else { - serde_json::json!({ "ids": {} }) - }; - - alias_data["ids"][&network_passphrase] = serde_json::Value::String(contract_id.to_string()); - - let content = serde_json::to_string_pretty(&alias_data)?; - std::fs::write(alias_file, content)?; - - Ok(()) + fn save_contract_alias(&self, name: &str, contract_id: &str, network: &Network) -> Result<(), cli::config::alias::Error> { + let config_dir = Self::get_config_dir(network); + config_dir.save_contract_id(contract_id, name) } fn write_contract_template(&self, workspace_root: &std::path::Path, name: &str, contract_id: &str) -> Result<(), Error> { @@ -258,8 +238,6 @@ impl Args { contracts: Option<&Map, env_toml::Contract>>, network: &Network, ) -> Result<(), Error> { - println!("Workspace root: {:?}", workspace_root); - println!("Contracts: {:?}", contracts); let Some(contracts) = contracts else { return Ok(()); }; @@ -284,22 +262,19 @@ impl Args { eprintln!(" ↳ hash: {hash}"); // Check if we have an alias saved for this contract - let alias = self.get_contract_alias(name)?; - println!("Debug: Contract name: {}, Alias: {:?}", name, alias); - + let alias = self.get_contract_alias(&name, &network)?; if let Some(contract_id) = alias { - // Check if the contract with that ID is using the current wasm hash - if self.contract_hash_matches(&contract_id, &hash, &network).await? { - eprintln!("✅ Contract {name:?} is up to date"); - continue; - } - - // For production environments, throw an error instead of updating - if self.loam_env() == "production" { - return Err(Error::ContractUpdateNotAllowed(name.to_string())); + match self.contract_hash_matches(&contract_id, &hash, &network).await { + Ok(true) => { + eprintln!("✅ Contract {name:?} is up to date"); + continue; + }, + Ok(false) if self.loam_env() == "production" => { + return Err(Error::ContractUpdateNotAllowed(name.to_string())); + }, + Ok(false) => eprintln!("🔄 Updating contract {name:?}"), + Err(e) => return Err(e), } - - eprintln!("🔄 Updating contract {name:?}"); } eprintln!("🪞 instantiating {name:?} smart contract"); @@ -312,7 +287,7 @@ impl Args { eprintln!(" ↳ contract_id: {contract_id}"); // Save the alias for future use - self.save_contract_alias(name, &contract_id)?; + self.save_contract_alias(&name, &contract_id, &network)?; eprintln!("🎭 binding {name:?} contract"); cli::contract::bindings::typescript::Cmd::parse_arg_vec(&[