1- use crate :: commands:: info;
21use crate :: utils:: { config, horizon, optimizer, print as p, soroban} ;
2+ use crate :: commands:: info;
33use anyhow:: Result ;
44use clap:: Args ;
55use colored:: * ;
@@ -233,7 +233,7 @@ pub fn handle(args: DeployArgs) -> Result<()> {
233233 p:: separator ( ) ;
234234 println ! (
235235 " {} {}" ,
236- "✓ " . green( ) . bold( ) ,
236+ "✓ " . green( ) . bold( ) ,
237237 "Ready! Run this to complete the deployment:" . bright_white( )
238238 ) ;
239239 println ! ( ) ;
@@ -242,201 +242,26 @@ pub fn handle(args: DeployArgs) -> Result<()> {
242242 println ! ( " {}" , line. cyan( ) ) ;
243243 }
244244 println ! ( ) ;
245- if args. execute {
246- let stellar_path = info:: detect_stellar_cli ( ) . ok_or_else ( || {
247- anyhow:: anyhow!(
248- "Cannot execute deploy: Stellar CLI not found on PATH.\n Install it from https://developers.stellar.org/docs/tools/stellar-cli"
249- )
250- } ) ?;
251245
252- p:: info ( & format ! (
253- "Executing with Stellar CLI at {}" ,
254- stellar_path. display( )
255- ) ) ;
256- let cmd_args = build_stellar_deploy_args ( & wasm_path, & wallet. public_key , & args. network ) ;
257- let output = Command :: new ( stellar_path) . args ( & cmd_args) . output ( ) ?;
258- if output. status . success ( ) {
259- p:: success ( "Deployment command executed successfully." ) ;
260- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
261- if !stdout. trim ( ) . is_empty ( ) {
262- println ! ( "{}" , stdout. trim( ) ) ;
263- }
264- } else {
246+ if args. execute {
247+ p:: info ( "Executing deployment with Stellar CLI..." ) ;
248+ let deploy_args = build_stellar_deploy_args ( & wasm_path, & wallet. public_key , & args. network ) ;
249+ let output = Command :: new ( "stellar" )
250+ . args ( & deploy_args)
251+ . output ( )
252+ . map_err ( |e| anyhow ! ( "Failed to execute stellar CLI: {}" , e) ) ?;
253+
254+ if !output. status . success ( ) {
265255 let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
266- anyhow:: bail!(
267- "Stellar CLI deployment failed (exit: {}). {}" ,
268- output. status,
269- stderr. trim( )
270- ) ;
256+ anyhow:: bail!( "Stellar CLI deployment failed: {}" , stderr) ;
271257 }
258+
259+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
260+ p:: success ( "Deployment executed successfully!" ) ;
261+ println ! ( "{}" , stdout) ;
272262 } else {
273- p:: info ( "Dry-run mode (default): command not executed . Use --execute to run it ." ) ;
263+ p:: info ( "Dry-run complete . Use --execute to deploy for real ." ) ;
274264 }
275- p:: info ( "Install the Stellar CLI: https://developers.stellar.org/docs/tools/stellar-cli" ) ;
276- p:: separator ( ) ;
277265
278266 Ok ( ( ) )
279267}
280-
281- #[ cfg( test) ]
282- mod tests {
283- use super :: * ;
284- use std:: fs;
285- use tempfile:: tempdir;
286-
287- // ---------------------------------------------------------------------------
288- // SHA-256 hash tests
289- // ---------------------------------------------------------------------------
290-
291- /// The output must always be a 64-character lowercase hex string (256 bits).
292- #[ test]
293- fn sha256_output_is_64_hex_chars ( ) {
294- let hash = compute_local_wasm_hash ( b"hello-starforge" ) ;
295- assert_eq ! ( hash. len( ) , 64 , "SHA-256 hex digest must be 64 characters" ) ;
296- assert ! (
297- hash. chars( ) . all( |c| c. is_ascii_hexdigit( ) ) ,
298- "digest must be lowercase hex"
299- ) ;
300- }
301-
302- /// Same bytes → same digest (deterministic).
303- #[ test]
304- fn sha256_is_deterministic ( ) {
305- let bytes = b"hello-starforge" ;
306- assert_eq ! (
307- compute_local_wasm_hash( bytes) ,
308- compute_local_wasm_hash( bytes)
309- ) ;
310- }
311-
312- /// Different bytes → different digest (collision-resistance sanity check).
313- #[ test]
314- fn sha256_differs_for_different_inputs ( ) {
315- assert_ne ! (
316- compute_local_wasm_hash( b"abc" ) ,
317- compute_local_wasm_hash( b"abd" )
318- ) ;
319- }
320-
321- /// Known-answer test: SHA-256("abc") == the FIPS 180-4 test vector.
322- ///
323- /// Expected value verified against `echo -n abc | sha256sum` and the
324- /// NIST FIPS 180-4 published test vector.
325- #[ test]
326- fn sha256_known_answer_abc ( ) {
327- let hash = compute_local_wasm_hash ( b"abc" ) ;
328- assert_eq ! (
329- hash,
330- "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" // SHA-256("abc") as computed by sha2 0.10 / FIPS 180-4.
331- ) ;
332- }
333-
334- /// Known-answer test against `tests/fixtures/minimal.wasm`.
335- ///
336- /// Expected value: `sha256sum tests/fixtures/minimal.wasm`
337- /// → 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476
338- #[ test]
339- fn sha256_minimal_wasm_fixture ( ) {
340- let fixture_path = std:: path:: Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) )
341- . join ( "tests" )
342- . join ( "fixtures" )
343- . join ( "minimal.wasm" ) ;
344- let wasm_bytes = fs:: read ( & fixture_path) . expect ( "failed to read minimal.wasm fixture" ) ;
345- let hash = compute_local_wasm_hash ( & wasm_bytes) ;
346- assert_eq ! (
347- hash,
348- "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"
349- ) ;
350- assert_eq ! ( hash. len( ) , 64 ) ;
351- }
352-
353- /// Hashing an empty slice must not panic and must equal the well-known
354- /// SHA-256 digest of the empty string.
355- #[ test]
356- fn sha256_empty_input ( ) {
357- let hash = compute_local_wasm_hash ( b"" ) ;
358- assert_eq ! (
359- hash,
360- "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
361- ) ;
362- }
363-
364- /// Round-trip via a real (temporary) file to confirm fs::read → SHA-256
365- /// produces a 64-char hex string.
366- #[ test]
367- fn sha256_real_file_round_trip ( ) {
368- let dir = tempdir ( ) . expect ( "failed to create temp dir" ) ;
369- let wasm_path = dir. path ( ) . join ( "token.wasm" ) ;
370- let wasm_magic: & [ u8 ] = & [ 0x00 , 0x61 , 0x73 , 0x6d , 0x01 , 0x00 , 0x00 , 0x00 ] ;
371- fs:: write ( & wasm_path, wasm_magic) . expect ( "failed to write wasm" ) ;
372- let bytes = fs:: read ( & wasm_path) . expect ( "failed to read wasm" ) ;
373-
374- let hash = compute_local_wasm_hash ( & bytes) ;
375- assert_eq ! ( hash. len( ) , 64 ) ;
376- assert_eq ! (
377- hash,
378- "93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"
379- ) ;
380- }
381-
382- // ---------------------------------------------------------------------------
383- // Unchanged helper tests
384- // ---------------------------------------------------------------------------
385-
386- #[ test]
387- fn builds_expected_deploy_command ( ) {
388- let command = build_stellar_deploy_command (
389- std:: path:: Path :: new ( "target/release/token.wasm" ) ,
390- "GABCDEF1234567890" ,
391- "testnet" ,
392- ) ;
393-
394- assert ! ( command. contains( "stellar contract deploy" ) ) ;
395- assert ! ( command. contains( "--wasm target/release/token.wasm" ) ) ;
396- assert ! ( command. contains( "--source GABCDEF1234567890" ) ) ;
397- assert ! ( command. contains( "--network testnet" ) ) ;
398- }
399-
400- #[ test]
401- fn builds_expected_deploy_args ( ) {
402- let args = build_stellar_deploy_args (
403- std:: path:: Path :: new ( "target/release/token.wasm" ) ,
404- "GABCDEF1234567890" ,
405- "testnet" ,
406- ) ;
407- assert_eq ! (
408- args,
409- vec![
410- "contract" ,
411- "deploy" ,
412- "--wasm" ,
413- "target/release/token.wasm" ,
414- "--source" ,
415- "GABCDEF1234567890" ,
416- "--network" ,
417- "testnet"
418- ]
419- ) ;
420- }
421-
422- #[ test]
423- fn flags_large_wasm_sizes ( ) {
424- assert ! ( !is_wasm_above_size_limit( 127.9 ) ) ;
425- assert ! ( !is_wasm_above_size_limit( 128.0 ) ) ;
426- assert ! ( is_wasm_above_size_limit( 128.1 ) ) ;
427- }
428-
429- #[ test]
430- fn deploy_args_support_simulate_flag ( ) {
431- let args = DeployArgs {
432- wasm : PathBuf :: from ( "contract.wasm" ) ,
433- network : "testnet" . to_string ( ) ,
434- wallet : None ,
435- optimize : false ,
436- yes : false ,
437- execute : false ,
438- simulate : true ,
439- } ;
440- assert ! ( args. simulate) ;
441- }
442- }
0 commit comments