stellar_registry_cli/commands/
install.rs

1use clap::Parser;
2
3use stellar_cli::{
4    commands::contract::{fetch, invoke},
5    config,
6};
7use stellar_strkey::Contract;
8
9use crate::contract::NetworkContract;
10
11#[derive(Parser, Debug, Clone)]
12pub struct Cmd {
13    /// Name of deployed contract
14    pub contract_name: String,
15
16    #[command(flatten)]
17    pub config: config::Args,
18}
19
20#[derive(thiserror::Error, Debug)]
21pub enum Error {
22    #[error(transparent)]
23    Fetch(#[from] fetch::Error),
24    #[error(transparent)]
25    Invoke(#[from] invoke::Error),
26    #[error(transparent)]
27    Io(#[from] std::io::Error),
28    #[error(transparent)]
29    Strkey(#[from] stellar_strkey::DecodeError),
30    #[error(transparent)]
31    LocatorConfig(#[from] stellar_cli::config::locator::Error),
32    #[error(transparent)]
33    Config(#[from] stellar_cli::config::Error),
34}
35
36impl Cmd {
37    pub async fn run(&self) -> Result<(), Error> {
38        // Use the network config from flattened args
39        let network = self.config.get_network()?;
40        let network_passphrase = network.network_passphrase;
41
42        let contract = self.get_contract_id().await?;
43
44        // Only create alias mapping, don't fetch wasm here
45        self.config.locator.save_contract_id(
46            &network_passphrase,
47            &contract,
48            &self.contract_name,
49        )?;
50
51        eprintln!(
52            "✅ Successfully registered contract alias '{}'",
53            self.contract_name
54        );
55        eprintln!("Contract ID: {:?}", contract.to_string());
56
57        Ok(())
58    }
59
60    pub async fn get_contract_id(&self) -> Result<Contract, Error> {
61        if self.contract_name == "registry" {
62            return Ok(self.config.contract_id()?);
63        }
64        // Prepare the arguments for invoke_registry
65        let slop = vec!["fetch_contract_id", "--contract-name", &self.contract_name];
66        // Use this.config directly
67        eprintln!("Fetching contract ID via registry...");
68        let raw = self.config.invoke_registry(&slop, None, true).await?;
69
70        let contract_id = raw.trim_matches('"').to_string();
71        Ok(contract_id.parse()?)
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    #[cfg(feature = "integration-tests")]
78    #[tokio::test]
79    async fn test_run() {
80        use super::*;
81        use std::env;
82        use stellar_cli::config::{locator, network};
83        use stellar_scaffold_test::RegistryTest;
84        // Create test environment
85        let registry = RegistryTest::new().await;
86        let test_env = registry.clone().env;
87
88        // Set environment variables for testnet configuration
89        env::set_var("STELLAR_RPC_URL", "http://localhost:8000/soroban/rpc");
90        env::set_var("STELLAR_ACCOUNT", "alice");
91        env::set_var(
92            "STELLAR_NETWORK_PASSPHRASE",
93            "Standalone Network ; February 2017",
94        );
95        env::set_var("STELLAR_REGISTRY_CONTRACT_ID", &registry.registry_address);
96
97        // Path to the hello world contract WASM
98        let wasm_path = test_env
99            .cwd
100            .join("target/stellar/soroban_hello_world_contract.wasm");
101
102        // First publish the contract
103        registry
104            .clone()
105            .registry_cli("publish")
106            .arg("--wasm")
107            .arg(&wasm_path)
108            .assert()
109            .success();
110
111        // Then deploy it
112        registry
113            .registry_cli("deploy")
114            .arg("--contract-name")
115            .arg("hello")
116            .arg("--wasm-name")
117            .arg("soroban-hello-world-contract")
118            .assert()
119            .success();
120
121        // Create test command for install
122        let cmd = Cmd {
123            contract_name: "hello".to_owned(),
124            config: config::Args {
125                locator: locator::Args {
126                    global: false,
127                    config_dir: Some(test_env.cwd.to_str().unwrap().into()),
128                },
129                network: network::Args {
130                    rpc_url: Some("http://localhost:8000/soroban/rpc".to_string()),
131                    network_passphrase: Some("Standalone Network ; February 2017".to_string()),
132                    ..Default::default()
133                },
134                ..Default::default()
135            },
136        };
137
138        // Run the install command
139        cmd.run().await.unwrap();
140        assert!(test_env.cwd.join(".stellar").exists());
141    }
142}