From fbb6a436b0b7382358507c32bf0331d86ab74aad Mon Sep 17 00:00:00 2001 From: Gerold Steiner Date: Wed, 4 Nov 2026 14:10:17 +0000 Subject: [PATCH] Allow wallet address lookup without a configured remote --- rust/modality-cli-contract/src/commit.rs | 1 + rust/modality-cli-contract/src/wallet.rs | 46 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/rust/modality-cli-contract/src/commit.rs b/rust/modality-cli-contract/src/commit.rs index edde2a86..58b5ce4b 100644 --- a/rust/modality-cli-contract/src/commit.rs +++ b/rust/modality-cli-contract/src/commit.rs @@ -382,6 +382,7 @@ pub async fn make(opts: &Opts) -> Result> { // Validate against contract rules (signature predicates, etc.) store.validate_commit_against_rules(&commit)?; + #[cfg_attr(not(feature = "model-status"), allow(unused_mut))] let mut model_repair = None; let theory_preview = match validate_commit_against_model(&dir, &store, &commit, &opts.theory) { Ok(preview) => preview, diff --git a/rust/modality-cli-contract/src/wallet.rs b/rust/modality-cli-contract/src/wallet.rs index 9b21526b..a8ca37db 100644 --- a/rust/modality-cli-contract/src/wallet.rs +++ b/rust/modality-cli-contract/src/wallet.rs @@ -487,16 +487,56 @@ async fn create(opts: &CreateOpts) -> Result<()> { Ok(()) } +fn local_address(opts: &WalletOpts) -> Result { + let dir = wallet_dir(&opts.dir)?; + let store = ContractStore::open(&dir) + .with_context(|| format!("no wallet at {}; run `modal wallet create`", dir.display()))?; + let _: WalletFile = serde_json::from_str( + &std::fs::read_to_string(store.contract_dir().join(WALLET_FILE)) + .with_context(|| format!("{} is a contract, not a wallet", dir.display()))?, + )?; + Ok(store.load_config()?.contract_id) +} + fn address(opts: &WalletOpts) -> Result<()> { - let wallet = Wallet::open(opts)?; + // Sharing an address only needs local wallet metadata, not a configured node. + let id = local_address(opts)?; if opts.output == "json" { - println!("{}", json!({ "address": wallet.id })); + println!("{}", json!({ "address": id })); } else { - println!("{}", wallet.id); + println!("{}", id); } Ok(()) } +#[cfg(test)] +mod address_tests { + use super::*; + + #[test] + fn address_does_not_require_a_remote() -> Result<()> { + let dir = tempfile::tempdir()?; + let store = ContractStore::init(dir.path(), "wallet-id".to_string())?; + std::fs::write( + store.contract_dir().join(WALLET_FILE), + serde_json::to_string(&WalletFile { + key: dir.path().join("owner.mod_passfile"), + })?, + )?; + let opts = WalletOpts { + dir: Some(dir.path().to_path_buf()), + remote: None, + output: "text".to_string(), + }; + assert_eq!(local_address(&opts)?, "wallet-id"); + assert!( + Wallet::open(&opts).is_err(), + "network commands still need a remote" + ); + Ok(()) + } +} + async fn balance(opts: &WalletOpts) -> Result<()> { let wallet = Wallet::open(opts)?; let account = wallet.account().await?;