1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{fetch::explorers::Explorers, types::CliLockedChain};
pub use base64::prelude::BASE64_STANDARD as B64;
use cw_orch::daemon::{networks::SUPPORTED_NETWORKS as NETWORKS, Fetchable};
use inquire::{error::InquireResult, InquireError, Select};

pub fn get_cw_cli_exec_path() -> String {
    std::env::args().next().unwrap()
}

pub fn select_chain() -> color_eyre::eyre::Result<Option<CliLockedChain>> {
    let chain_ids: Vec<_> = NETWORKS
        .iter()
        .map(|network| {
            format!(
                "{} {}({})",
                network.network_info.id.to_uppercase(),
                network.kind.to_string().to_uppercase(),
                network.chain_id
            )
        })
        .collect();
    let selected = Select::new("Select chain", chain_ids).raw_prompt()?;
    let locked_chain = CliLockedChain::new(selected.index);
    Ok(Some(locked_chain))
}

pub fn select_signer() -> color_eyre::eyre::Result<Option<String>> {
    let entries_set_result = crate::types::keys::read_entries();
    let signer_id = match entries_set_result {
        // We have a file access and it has at least one signer
        Ok(entries_set) if !entries_set.entries.is_empty() => {
            let options = entries_set.entries.into_iter().collect();
            Select::new("Select signer id", options)
                .with_help_message("Use CLI mode to add signer from previous version")
                .prompt()?
        }
        // We don't have access or it's empty
        _ => inquire::Text::new("Signer id").prompt()?,
    };
    Ok(Some(signer_id))
}

pub fn parse_coins() -> InquireResult<cosmwasm_std::Coins> {
    let mut coins = cosmwasm_std::Coins::default();
    loop {
        let coin = inquire::Text::new("Add coin to transaction")
            .with_help_message("Leave empty to stop adding coins")
            .with_placeholder("0ucoin")
            .prompt()?;
        if !coin.is_empty() {
            match coin.parse() {
                Ok(c) => coins
                    .add(c)
                    .map_err(|e| InquireError::Custom(Box::new(e)))?,
                Err(e) => {
                    println!("Failed to add coin: {e}")
                }
            }
        } else {
            break;
        }
    }
    println!("attached coins: {coins}");
    Ok(coins)
}

#[derive(Clone, Copy, strum::EnumIter, strum::EnumString, derive_more::Display)]
pub enum ExpirationType {
    AtHeight,
    AtTime,
    Never,
}

impl ExpirationType {
    const VARIANTS: &'static [ExpirationType] = &[Self::AtHeight, Self::AtTime, Self::Never];
}

pub fn parse_expiration() -> InquireResult<cw_utils::Expiration> {
    let locked = inquire::Select::new("Choose expiration type", ExpirationType::VARIANTS.to_vec())
        .prompt()?;

    let expiration = match locked {
        ExpirationType::AtHeight => {
            let block_height = inquire::CustomType::<u64>::new("Input block height").prompt()?;
            cw_utils::Expiration::AtHeight(block_height)
        }
        ExpirationType::AtTime => {
            let timestamp_nanos =
                inquire::CustomType::<u64>::new("Input timestamp in nanos").prompt()?;
            let timestamp = cosmwasm_std::Timestamp::from_nanos(timestamp_nanos);
            cw_utils::Expiration::AtTime(timestamp)
        }
        ExpirationType::Never => cw_utils::Expiration::Never {},
    };
    Ok(expiration)
}

pub async fn show_addr_explorer(chain_name: String, addr: &str) -> color_eyre::eyre::Result<()> {
    let Explorers { explorers } = Explorers::fetch(chain_name, None).await?;
    for explorer in explorers {
        if let Some(tx_page) = explorer.account_page {
            let url = tx_page.replace("${accountAddress}", addr);
            println!("Explorer: {url}");
            break;
        }
    }
    Ok(())
}