diff --git a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs index c6e30b1fa..e91a7f181 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -398,3 +398,47 @@ fn invoke_log(sandbox: &TestEnv, id: &str) { r#"Log: {"vec":[{"string":"hello {}"},{"symbol":"world"}]}"#, )); } + +#[tokio::test] +async fn invoke_auth_uses_hd_path_for_addr_alias() { + let sandbox = &TestEnv::new(); + + // Fund path 1 of the "test" seed (path 0 is funded by default) + sandbox + .new_assert_cmd("keys") + .arg("fund") + .arg("test") + .arg("--hd-path=1") + .assert() + .success(); + + let addr_1 = sandbox + .new_assert_cmd("keys") + .arg("address") + .arg("test") + .arg("--hd-path=1") + .assert() + .stdout_as_str(); + + let id = &deploy_hello(sandbox).await; + extend_contract(sandbox, id).await; + + // --hd-path=1 must propagate to --addr alias resolution AND the auth signer. + // The contract's auth function returns the Address it was called with, so + // the output must be addr_1 (path 1), not path 0. + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--source") + .arg("test") + .arg("--hd-path=1") + .arg("--id") + .arg(id) + .arg("--") + .arg("auth") + .arg("--addr=test") + .arg("--world=world") + .assert() + .stdout(format!("\"{addr_1}\"\n")) + .success(); +} diff --git a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs index 28305b083..86297b456 100644 --- a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs +++ b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs @@ -447,7 +447,11 @@ fn resolve_address(addr_or_alias: &str, config: &config::Args) -> Result addr.to_string(), addr @ UnresolvedScAddress::Alias(_) => { - let addr = addr.resolve(&config.locator, &config.get_network()?.network_passphrase)?; + let addr = addr.resolve( + &config.locator, + &config.get_network()?.network_passphrase, + config.hd_path(), + )?; match addr { xdr::ScAddress::Account(account) => account.to_string(), contract @ xdr::ScAddress::Contract(_) => contract.to_string(), @@ -467,7 +471,7 @@ fn resolve_address(addr_or_alias: &str, config: &config::Args) -> Result Option { let secret = config.locator.get_secret_key(addr_or_alias).ok()?; let print = Print::new(false); - let signer = secret.signer(None, print).await.ok()?; + let signer = secret.signer(config.hd_path(), print).await.ok()?; Some(signer) } diff --git a/cmd/soroban-cli/src/config/mod.rs b/cmd/soroban-cli/src/config/mod.rs index 7eb79fff4..e3eb22a97 100644 --- a/cmd/soroban-cli/src/config/mod.rs +++ b/cmd/soroban-cli/src/config/mod.rs @@ -94,7 +94,7 @@ impl Args { pub async fn source_signer(&self) -> Result { let print = Print::new(true); let secret = &self.source_account.resolve_secret(&self.locator)?; - Ok(secret.signer(None, print).await?) + Ok(secret.signer(self.hd_path(), print).await?) } pub fn key_pair(&self) -> Result { diff --git a/cmd/soroban-cli/src/config/sc_address.rs b/cmd/soroban-cli/src/config/sc_address.rs index f5ac8ba7a..b5aecfff4 100644 --- a/cmd/soroban-cli/src/config/sc_address.rs +++ b/cmd/soroban-cli/src/config/sc_address.rs @@ -44,6 +44,7 @@ impl UnresolvedScAddress { self, locator: &locator::Args, network_passphrase: &str, + hd_path: Option, ) -> Result { let alias = match self { UnresolvedScAddress::Resolved(addr) => return Ok(addr), @@ -64,7 +65,7 @@ impl UnresolvedScAddress { xdr::Hash(contract.0), ))), (_, Ok(key)) => Ok(xdr::ScAddress::Account( - key.muxed_account(None)?.account_id(), + key.muxed_account(hd_path)?.account_id(), )), _ => Err(Error::AccountAliasNotFound(alias)), }