From c736927254ccd4c5466544911caeca7135be9d34 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Tue, 7 Oct 2025 15:09:32 -0700 Subject: [PATCH 1/4] Deprecate `stellar contract optimize` in favor of `stellar contract build --optimize`. --- FULL_HELP_DOCS.md | 5 +- .../src/commands/contract/build.rs | 102 +++++++++++++++-- cmd/soroban-cli/src/commands/contract/mod.rs | 4 +- .../src/commands/contract/optimize.rs | 105 +++++++++++------- cmd/soroban-cli/src/print.rs | 2 +- licenses.rb | 5 - 6 files changed, 158 insertions(+), 65 deletions(-) delete mode 100644 licenses.rb diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index e15af8691c..67327fe2e1 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -93,7 +93,7 @@ Tools for smart contract developers - `upload` — Install a WASM file to the ledger without creating a contract instance - `install` — (Deprecated in favor of `contract upload` subcommand) Install a WASM file to the ledger without creating a contract instance - `invoke` — Invoke a contract function -- `optimize` — Optimize a WASM file +- `optimize` — (Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file - `read` — Print the current value of a contract-data ledger entry - `restore` — Restore an evicted value for a contract-data legder entry @@ -357,6 +357,7 @@ To view the commands that will be executed, without executing them, use the --pr - `--print-commands-only` — Print commands to build without executing them - `--meta ` — Add key-value to contract meta (adds the meta to the `contractmetav0` custom section) +- `--optimize` — Optimize the generated wasm ## `stellar contract extend` @@ -789,7 +790,7 @@ stellar contract invoke ... -- --help ## `stellar contract optimize` -Optimize a WASM file +(Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file **Usage:** `stellar contract optimize [OPTIONS] --wasm ...` diff --git a/cmd/soroban-cli/src/commands/contract/build.rs b/cmd/soroban-cli/src/commands/contract/build.rs index 7dbb296781..4f02901cf2 100644 --- a/cmd/soroban-cli/src/commands/contract/build.rs +++ b/cmd/soroban-cli/src/commands/contract/build.rs @@ -17,7 +17,11 @@ use std::{ }; use stellar_xdr::curr::{Limited, Limits, ScMetaEntry, ScMetaV0, StringM, WriteXdr}; -use crate::{commands::global, print::Print}; +use crate::{ + commands::{contract::optimize, global}, + print::Print, + wasm, +}; /// Build a contract from source /// @@ -32,6 +36,7 @@ use crate::{commands::global, print::Print}; /// To view the commands that will be executed, without executing them, use the /// --print-commands-only option. #[derive(Parser, Debug, Clone)] +#[allow(clippy::struct_excessive_bools)] pub struct Cmd { /// Path to Cargo.toml #[arg(long)] @@ -41,12 +46,15 @@ pub struct Cmd { /// If omitted, all packages that build for crate-type cdylib are built. #[arg(long)] pub package: Option, + /// Build with the specified profile #[arg(long, default_value = "release")] pub profile: String, + /// Build with the list of features activated, space or comma separated #[arg(long, help_heading = "Features")] pub features: Option, + /// Build with the all features activated #[arg( long, @@ -55,9 +63,11 @@ pub struct Cmd { help_heading = "Features" )] pub all_features: bool, + /// Build with the default feature not activated #[arg(long, help_heading = "Features")] pub no_default_features: bool, + /// Directory to copy wasm files to /// /// If provided, wasm files can be found in the cargo target directory, and @@ -66,12 +76,18 @@ pub struct Cmd { /// If ommitted, wasm files are written only to the cargo target directory. #[arg(long)] pub out_dir: Option, + /// Print commands to build without executing them #[arg(long, conflicts_with = "out_dir", help_heading = "Other")] pub print_commands_only: bool, + /// Add key-value to contract meta (adds the meta to the `contractmetav0` custom section) #[arg(long, num_args=1, value_parser=parse_meta_arg, action=clap::ArgAction::Append, help_heading = "Metadata")] pub meta: Vec<(String, String)>, + + /// Optimize the generated wasm. + #[arg(long)] + pub optimize: bool, } fn parse_meta_arg(s: &str) -> Result<(String, String), Error> { @@ -89,34 +105,54 @@ fn parse_meta_arg(s: &str) -> Result<(String, String), Error> { pub enum Error { #[error(transparent)] Metadata(#[from] cargo_metadata::Error), + #[error(transparent)] CargoCmd(io::Error), + #[error("exit status {0}")] Exit(ExitStatus), + #[error("package {package} not found")] PackageNotFound { package: String }, + #[error("finding absolute path of Cargo.toml: {0}")] AbsolutePath(io::Error), + #[error("creating out directory: {0}")] CreatingOutDir(io::Error), + #[error("deleting existing artifact: {0}")] DeletingArtifact(io::Error), + #[error("copying wasm file: {0}")] CopyingWasmFile(io::Error), + #[error("getting the current directory: {0}")] GettingCurrentDir(io::Error), + #[error("retreiving CARGO_HOME: {0}")] CargoHome(io::Error), + #[error("reading wasm file: {0}")] ReadingWasmFile(io::Error), + #[error("writing wasm file: {0}")] WritingWasmFile(io::Error), + #[error("invalid meta entry: {0}")] MetaArg(String), + #[error("use rust 1.81 or 1.84+ to build contracts (got {0})")] RustVersion(String), + #[error(transparent)] Xdr(#[from] stellar_xdr::curr::Error), + + #[error(transparent)] + Optimize(#[from] optimize::Error), + + #[error(transparent)] + Wasm(#[from] wasm::Error), } const WASM_TARGET: &str = "wasm32v1-none"; @@ -202,7 +238,8 @@ impl Cmd { return Err(Error::Exit(status)); } - let file = format!("{}.wasm", p.name.replace('-', "_")); + let wasm_name = p.name.replace('-', "_"); + let file = format!("{wasm_name}.wasm"); let target_file_path = Path::new(target_dir) .join(&wasm_target) .join(&self.profile) @@ -219,7 +256,17 @@ impl Cmd { target_file_path }; - Self::print_build_summary(&print, &final_path)?; + let optimized_file_path = if self.optimize { + let mut path = final_path.clone(); + path.set_extension("optimized.wasm"); + optimize::optimize(true, vec![final_path.clone()], Some(path.clone()))?; + + Some(path) + } else { + None + }; + + Self::print_build_summary(&print, &final_path, optimized_file_path)?; } } @@ -332,20 +379,49 @@ impl Cmd { Ok(buffer) } - fn print_build_summary(print: &Print, target_file_path: &PathBuf) -> Result<(), Error> { - print.infoln("Build Summary:"); - let rel_target_file_path = target_file_path + fn print_wasm_info( + print: &Print, + path: &PathBuf, + wasm_bytes: &Vec, + label: &str, + ) -> Result<(), Error> { + let rel_path = path .strip_prefix(env::current_dir().unwrap()) - .unwrap_or(target_file_path); - print.blankln(format!("Wasm File: {}", rel_target_file_path.display())); + .unwrap_or(path); + let wasm_size = wasm::len(path)?; - let wasm_bytes = fs::read(target_file_path).map_err(Error::ReadingWasmFile)?; + print.blankln(format!( + "{label} File: {path} ({wasm_size} bytes)", + path = rel_path.display() + )); print.blankln(format!( - "Wasm Hash: {}", - hex::encode(Sha256::digest(&wasm_bytes)) + "{label} Hash: {}", + hex::encode(Sha256::digest(wasm_bytes)) )); + Ok(()) + } + + fn print_build_summary( + print: &Print, + target_file_path: &PathBuf, + optimized_file_path: Option, + ) -> Result<(), Error> { + print.infoln("Build Summary:"); + let wasm_bytes = fs::read(target_file_path).map_err(Error::ReadingWasmFile)?; + Self::print_wasm_info(print, target_file_path, &wasm_bytes, "Wasm")?; + + if let Some(optimized_path) = optimized_file_path { + let optimized_wasm_bytes = fs::read(&optimized_path).map_err(Error::ReadingWasmFile)?; + Self::print_wasm_info( + print, + &optimized_path, + &optimized_wasm_bytes, + "Optimized Wasm", + )?; + } + let parser = wasmparser::Parser::new(0); let export_names: Vec<&str> = parser .parse_all(&wasm_bytes) @@ -363,6 +439,7 @@ impl Cmd { .map(|export| export.name) .sorted() .collect(); + if export_names.is_empty() { print.blankln("Exported Functions: None found"); } else { @@ -371,7 +448,8 @@ impl Cmd { print.blankln(format!(" • {name}")); } } - print.checkln("Build Complete"); + + print.checkln("Build Complete\n"); Ok(()) } diff --git a/cmd/soroban-cli/src/commands/contract/mod.rs b/cmd/soroban-cli/src/commands/contract/mod.rs index dd642755ad..911a4138fe 100644 --- a/cmd/soroban-cli/src/commands/contract/mod.rs +++ b/cmd/soroban-cli/src/commands/contract/mod.rs @@ -81,7 +81,7 @@ pub enum Cmd { /// stellar contract invoke ... -- --help Invoke(invoke::Cmd), - /// Optimize a WASM file + /// (Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file Optimize(optimize::Cmd), /// Print the current value of a contract-data ledger entry @@ -165,7 +165,7 @@ impl Cmd { } Cmd::Upload(upload) => upload.run(global_args).await?, Cmd::Invoke(invoke) => invoke.run(global_args).await?, - Cmd::Optimize(optimize) => optimize.run()?, + Cmd::Optimize(optimize) => optimize.run(global_args)?, Cmd::Fetch(fetch) => fetch.run().await?, Cmd::Read(read) => read.run().await?, Cmd::Restore(restore) => restore.run().await?, diff --git a/cmd/soroban-cli/src/commands/contract/optimize.rs b/cmd/soroban-cli/src/commands/contract/optimize.rs index e8d21cda44..5e2310afa1 100644 --- a/cmd/soroban-cli/src/commands/contract/optimize.rs +++ b/cmd/soroban-cli/src/commands/contract/optimize.rs @@ -3,6 +3,8 @@ use std::{fmt::Debug, path::PathBuf}; #[cfg(feature = "additional-libs")] use wasm_opt::{Feature, OptimizationError, OptimizationOptions}; +#[cfg(feature = "additional-libs")] +use crate::commands::global; use crate::wasm; #[derive(Parser, Debug, Clone)] @@ -36,60 +38,77 @@ pub enum Error { impl Cmd { #[cfg(not(feature = "additional-libs"))] - pub fn run(&self) -> Result<(), Error> { + pub fn run(&self, _global_args: &global::Args) -> Result<(), Error> { Err(Error::Install) } #[cfg(feature = "additional-libs")] - pub fn run(&self) -> Result<(), Error> { - if self.wasm.len() > 1 && self.wasm_out.is_some() { - return Err(Error::MultipleFilesOutput); - } + pub fn run(&self, global_args: &global::Args) -> Result<(), Error> { + use crate::print::Print; + + let print = Print::new(global_args.quiet); + print + .warnln("`stellar contract optimize` is deprecated and will be removed in the future. Use `stellar contract build --optimize` instead."); + + optimize(false, self.wasm.clone(), self.wasm_out.clone()) + } +} + +#[cfg(feature = "additional-libs")] +pub fn optimize( + quiet: bool, + wasm: Vec, + wasm_out: Option, +) -> Result<(), Error> { + if wasm.len() > 1 && wasm_out.is_some() { + return Err(Error::MultipleFilesOutput); + } - for wasm_path in &self.wasm { - let wasm_arg = wasm::Args { - wasm: wasm_path.into(), - }; - let wasm_size = wasm_arg.len()?; + for wasm_path in &wasm { + let wasm_arg = wasm::Args { + wasm: wasm_path.into(), + }; + if !quiet { println!( - "Reading: {} ({} bytes)", - wasm_arg.wasm.to_string_lossy(), - wasm_size + "Reading: {path} ({wasm_size} bytes)", + path = wasm_arg.wasm.to_string_lossy(), + wasm_size = wasm_arg.len()? ); + } - let wasm_out = self.wasm_out.clone().unwrap_or_else(|| { - let mut wasm_out = wasm_arg.wasm.clone(); - wasm_out.set_extension("optimized.wasm"); - wasm_out - }); - - let mut options = OptimizationOptions::new_optimize_for_size_aggressively(); - options.converge = true; - - // Explicitly set to MVP + sign-ext + mutable-globals, which happens to - // also be the default featureset, but just to be extra clear we set it - // explicitly. - // - // Formerly Soroban supported only the MVP feature set, but Rust 1.70 as - // well as Clang generate code with sign-ext + mutable-globals enabled, - // so Soroban has taken a change to support them also. - options.mvp_features_only(); - options.enable_feature(Feature::MutableGlobals); - options.enable_feature(Feature::SignExt); - - options - .run(&wasm_arg.wasm, &wasm_out) - .map_err(Error::OptimizationError)?; - - let wasm_out_size = wasm::len(&wasm_out)?; + let wasm_out = wasm_out.clone().unwrap_or_else(|| { + let mut wasm_out = wasm_arg.wasm.clone(); + wasm_out.set_extension("optimized.wasm"); + wasm_out + }); + + let mut options = OptimizationOptions::new_optimize_for_size_aggressively(); + options.converge = true; + + // Explicitly set to MVP + sign-ext + mutable-globals, which happens to + // also be the default featureset, but just to be extra clear we set it + // explicitly. + // + // Formerly Soroban supported only the MVP feature set, but Rust 1.70 as + // well as Clang generate code with sign-ext + mutable-globals enabled, + // so Soroban has taken a change to support them also. + options.mvp_features_only(); + options.enable_feature(Feature::MutableGlobals); + options.enable_feature(Feature::SignExt); + + options + .run(&wasm_arg.wasm, &wasm_out) + .map_err(Error::OptimizationError)?; + + if !quiet { println!( - "Optimized: {} ({} bytes)", - wasm_out.to_string_lossy(), - wasm_out_size + "Optimized: {path} ({size} bytes)", + path = wasm_out.to_string_lossy(), + size = wasm::len(&wasm_out)? ); } - - Ok(()) } + + Ok(()) } diff --git a/cmd/soroban-cli/src/print.rs b/cmd/soroban-cli/src/print.rs index eeea11ebb0..c947832919 100644 --- a/cmd/soroban-cli/src/print.rs +++ b/cmd/soroban-cli/src/print.rs @@ -116,6 +116,6 @@ create_print_functions!(exclaim, exclaimln, "❗️"); create_print_functions!(arrow, arrowln, "➡️"); create_print_functions!(log, logln, "📔"); create_print_functions!(event, eventln, "📅"); -create_print_functions!(blank, blankln, " "); +create_print_functions!(blank, blankln, " "); create_print_functions!(gear, gearln, "⚙️"); create_print_functions!(dir, dirln, "📁"); diff --git a/licenses.rb b/licenses.rb deleted file mode 100644 index 4cc6def02a..0000000000 --- a/licenses.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "json" - -metadata = JSON.parse(`cargo metadata --format-version 1 --frozen`) -packages = metadata["packages"] -puts JSON.pretty_generate(packages) From 85483777b6f98a415a02cf07647bd31ae8df2ce5 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Tue, 7 Oct 2025 16:06:03 -0700 Subject: [PATCH 2/4] Use the same output path for both optimized and original wasm files. --- FULL_HELP_DOCS.md | 12 +-- .../src/commands/contract/build.rs | 75 +++++++++---------- cmd/soroban-cli/src/commands/contract/mod.rs | 6 +- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 67327fe2e1..41be49507b 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -89,11 +89,11 @@ Tools for smart contract developers - `id` — Generate the contract id for a given contract or asset - `info` — Access info about contracts - `init` — Initialize a Soroban contract project -- `inspect` — (Deprecated in favor of `contract info` subcommand) Inspect a WASM file listing contract functions, meta, etc +- `inspect` — (Deprecated, use `contract info`) Inspect a WASM file listing contract functions, meta, etc - `upload` — Install a WASM file to the ledger without creating a contract instance -- `install` — (Deprecated in favor of `contract upload` subcommand) Install a WASM file to the ledger without creating a contract instance +- `install` — (Deprecated, use `contract upload`) Install a WASM file to the ledger without creating a contract instance - `invoke` — Invoke a contract function -- `optimize` — (Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file +- `optimize` — (Deprecated, use `build --optimize`) Optimize a WASM file - `read` — Print the current value of a contract-data ledger entry - `restore` — Restore an evicted value for a contract-data legder entry @@ -662,7 +662,7 @@ This command will create a Cargo workspace project and add a sample Stellar cont ## `stellar contract inspect` -(Deprecated in favor of `contract info` subcommand) Inspect a WASM file listing contract functions, meta, etc +(Deprecated, use `contract info`) Inspect a WASM file listing contract functions, meta, etc **Usage:** `stellar contract inspect [OPTIONS] --wasm ` @@ -714,7 +714,7 @@ Install a WASM file to the ledger without creating a contract instance ## `stellar contract install` -(Deprecated in favor of `contract upload` subcommand) Install a WASM file to the ledger without creating a contract instance +(Deprecated, use `contract upload`) Install a WASM file to the ledger without creating a contract instance **Usage:** `stellar contract install [OPTIONS] --source-account --wasm ` @@ -790,7 +790,7 @@ stellar contract invoke ... -- --help ## `stellar contract optimize` -(Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file +(Deprecated, use `build --optimize`) Optimize a WASM file **Usage:** `stellar contract optimize [OPTIONS] --wasm ...` diff --git a/cmd/soroban-cli/src/commands/contract/build.rs b/cmd/soroban-cli/src/commands/contract/build.rs index 4f02901cf2..38fe5e8b82 100644 --- a/cmd/soroban-cli/src/commands/contract/build.rs +++ b/cmd/soroban-cli/src/commands/contract/build.rs @@ -256,17 +256,20 @@ impl Cmd { target_file_path }; - let optimized_file_path = if self.optimize { + let wasm_bytes = fs::read(&final_path).map_err(Error::ReadingWasmFile)?; + let mut optimized_wasm_bytes: Vec = Vec::new(); + + if self.optimize { let mut path = final_path.clone(); path.set_extension("optimized.wasm"); optimize::optimize(true, vec![final_path.clone()], Some(path.clone()))?; + optimized_wasm_bytes = fs::read(&path).map_err(Error::ReadingWasmFile)?; - Some(path) - } else { - None - }; + fs::copy(&path, &final_path).map_err(Error::CopyingWasmFile)?; + fs::remove_file(&path).map_err(Error::DeletingArtifact)?; + } - Self::print_build_summary(&print, &final_path, optimized_file_path)?; + Self::print_build_summary(&print, &final_path, wasm_bytes, optimized_wasm_bytes); } } @@ -379,48 +382,40 @@ impl Cmd { Ok(buffer) } - fn print_wasm_info( + fn print_build_summary( print: &Print, - path: &PathBuf, - wasm_bytes: &Vec, - label: &str, - ) -> Result<(), Error> { + path: &Path, + wasm_bytes: Vec, + optimized_wasm_bytes: Vec, + ) { + print.infoln("Build Summary:"); + let rel_path = path .strip_prefix(env::current_dir().unwrap()) .unwrap_or(path); - let wasm_size = wasm::len(path)?; - print.blankln(format!( - "{label} File: {path} ({wasm_size} bytes)", - path = rel_path.display() - )); + let size = wasm_bytes.len(); + let optimized_size = optimized_wasm_bytes.len(); + + let size_description = if optimized_size > 0 { + format!("{optimized_size} bytes (original size was {size} bytes)") + } else { + format!("{size} bytes") + }; + + let bytes = if optimized_size > 0 { + &optimized_wasm_bytes + } else { + &wasm_bytes + }; print.blankln(format!( - "{label} Hash: {}", - hex::encode(Sha256::digest(wasm_bytes)) + "Wasm File: {path} ({size_description})", + path = rel_path.display() )); - Ok(()) - } - - fn print_build_summary( - print: &Print, - target_file_path: &PathBuf, - optimized_file_path: Option, - ) -> Result<(), Error> { - print.infoln("Build Summary:"); - let wasm_bytes = fs::read(target_file_path).map_err(Error::ReadingWasmFile)?; - Self::print_wasm_info(print, target_file_path, &wasm_bytes, "Wasm")?; - - if let Some(optimized_path) = optimized_file_path { - let optimized_wasm_bytes = fs::read(&optimized_path).map_err(Error::ReadingWasmFile)?; - Self::print_wasm_info( - print, - &optimized_path, - &optimized_wasm_bytes, - "Optimized Wasm", - )?; - } + print.blankln(format!("Wasm Hash: {}", hex::encode(Sha256::digest(bytes)))); + print.blankln(format!("Wasm Size: {size_description}")); let parser = wasmparser::Parser::new(0); let export_names: Vec<&str> = parser @@ -450,8 +445,6 @@ impl Cmd { } print.checkln("Build Complete\n"); - - Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/contract/mod.rs b/cmd/soroban-cli/src/commands/contract/mod.rs index 911a4138fe..0c2bd968ae 100644 --- a/cmd/soroban-cli/src/commands/contract/mod.rs +++ b/cmd/soroban-cli/src/commands/contract/mod.rs @@ -61,14 +61,14 @@ pub enum Cmd { /// be overwritten unless `--overwrite` is passed. Init(init::Cmd), - /// (Deprecated in favor of `contract info` subcommand) Inspect a WASM file listing contract functions, meta, etc + /// (Deprecated, use `contract info`) Inspect a WASM file listing contract functions, meta, etc #[command(display_order = 100)] Inspect(inspect::Cmd), /// Install a WASM file to the ledger without creating a contract instance Upload(upload::Cmd), - /// (Deprecated in favor of `contract upload` subcommand) Install a WASM file to the ledger without creating a contract instance + /// (Deprecated, use `contract upload`) Install a WASM file to the ledger without creating a contract instance Install(upload::Cmd), /// Invoke a contract function @@ -81,7 +81,7 @@ pub enum Cmd { /// stellar contract invoke ... -- --help Invoke(invoke::Cmd), - /// (Deprecated in favor of `build --optimize` subcommand) Optimize a WASM file + /// (Deprecated, use `build --optimize`) Optimize a WASM file Optimize(optimize::Cmd), /// Print the current value of a contract-data ledger entry From 7d869a2846371fbb39549590f203c8506c513eb8 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Tue, 7 Oct 2025 16:10:56 -0700 Subject: [PATCH 3/4] Change size message. --- cmd/soroban-cli/src/commands/contract/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/soroban-cli/src/commands/contract/build.rs b/cmd/soroban-cli/src/commands/contract/build.rs index 38fe5e8b82..2b1bb3af10 100644 --- a/cmd/soroban-cli/src/commands/contract/build.rs +++ b/cmd/soroban-cli/src/commands/contract/build.rs @@ -398,7 +398,7 @@ impl Cmd { let optimized_size = optimized_wasm_bytes.len(); let size_description = if optimized_size > 0 { - format!("{optimized_size} bytes (original size was {size} bytes)") + format!("{optimized_size} bytes optimized (original size was {size} bytes)") } else { format!("{size} bytes") }; From d623e36150d3ea7496f5dd9f80c4cbff9c9d9e09 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Tue, 7 Oct 2025 16:17:28 -0700 Subject: [PATCH 4/4] Remove original file, then rename optimized one. --- cmd/soroban-cli/src/commands/contract/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/soroban-cli/src/commands/contract/build.rs b/cmd/soroban-cli/src/commands/contract/build.rs index 2b1bb3af10..440eef9220 100644 --- a/cmd/soroban-cli/src/commands/contract/build.rs +++ b/cmd/soroban-cli/src/commands/contract/build.rs @@ -265,8 +265,8 @@ impl Cmd { optimize::optimize(true, vec![final_path.clone()], Some(path.clone()))?; optimized_wasm_bytes = fs::read(&path).map_err(Error::ReadingWasmFile)?; - fs::copy(&path, &final_path).map_err(Error::CopyingWasmFile)?; - fs::remove_file(&path).map_err(Error::DeletingArtifact)?; + fs::remove_file(&final_path).map_err(Error::DeletingArtifact)?; + fs::rename(&path, &final_path).map_err(Error::CopyingWasmFile)?; } Self::print_build_summary(&print, &final_path, wasm_bytes, optimized_wasm_bytes);