Skip to main content

soroban_cli/commands/keys/
fund.rs

1use crate::{commands::global, config::network, print::Print};
2
3use super::public_key;
4
5#[derive(thiserror::Error, Debug)]
6pub enum Error {
7    #[error(transparent)]
8    Address(#[from] public_key::Error),
9    #[error(transparent)]
10    Network(#[from] network::Error),
11}
12
13#[derive(Debug, clap::Parser, Clone)]
14#[group(skip)]
15pub struct Cmd {
16    #[command(flatten)]
17    pub network: network::Args,
18    /// Address to fund
19    #[command(flatten)]
20    pub address: public_key::Cmd,
21}
22
23impl Cmd {
24    pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
25        let print = Print::new(global_args.quiet);
26        let addr = self.address.public_key().await?;
27        let network = self.network.get(&self.address.locator)?;
28        let label = self
29            .address
30            .name
31            .as_ref()
32            .map_or_else(|| format!("{addr}"), ToString::to_string);
33        network.fund_address(&addr).await?;
34        print.checkln(format!(
35            "Account {} funded on {:?}",
36            label, network.network_passphrase
37        ));
38        Ok(())
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use clap::Parser;
46
47    const PUBLIC_KEY: &str = "GAKSH6AD2IPJQELTHIOWDAPYX74YELUOWJLI2L4RIPIPZH6YQIFNUSDC";
48
49    #[test]
50    fn ledger_flag_parses_without_name() {
51        let cmd = Cmd::try_parse_from(["fund", "--ledger"]).expect("--ledger alone parses");
52        assert!(cmd.address.ledger);
53        assert!(cmd.address.name.is_none());
54    }
55
56    #[test]
57    fn ledger_flag_with_hd_path_parses() {
58        let cmd = Cmd::try_parse_from(["fund", "--ledger", "--hd-path", "5"]).unwrap();
59        assert!(cmd.address.ledger);
60        assert_eq!(cmd.address.hd_path, Some(5));
61    }
62
63    #[test]
64    fn ledger_flag_conflicts_with_name() {
65        let err = Cmd::try_parse_from(["fund", PUBLIC_KEY, "--ledger"])
66            .expect_err("--ledger + name must conflict");
67        assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
68    }
69
70    #[test]
71    fn missing_name_without_ledger_is_rejected() {
72        let err = Cmd::try_parse_from(["fund"]).expect_err("name is required without --ledger");
73        assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument);
74    }
75}