1use crate::{fetch::explorers::Explorers, types::CliLockedChain};
2pub use base64::prelude::BASE64_STANDARD as B64;
3use cw_orch::{
4 daemon::networks::SUPPORTED_NETWORKS as NETWORKS,
5 environment::{ChainInfo, ChainKind},
6};
7use ibc_chain_registry::fetchable::Fetchable;
8use inquire::{error::InquireResult, InquireError, Select};
9
10pub fn get_cw_cli_exec_path() -> String {
11 std::env::args().next().unwrap()
12}
13
14pub fn select_chain() -> color_eyre::eyre::Result<Option<CliLockedChain>> {
15 let chain_ids: Vec<_> = NETWORKS
16 .iter()
17 .map(|network| {
18 format!(
19 "{} {}({})",
20 network.network_info.chain_name.to_uppercase(),
21 network.kind.to_string().to_uppercase(),
22 network.chain_id
23 )
24 })
25 .collect();
26 let selected = Select::new("Select chain", chain_ids).raw_prompt()?;
27 let locked_chain = CliLockedChain::new(selected.index);
28 Ok(Some(locked_chain))
29}
30
31pub fn select_signer() -> color_eyre::eyre::Result<Option<String>> {
32 let entries_set_result = crate::types::keys::read_entries();
33 let signer_id = match entries_set_result {
34 Ok(entries_set) if !entries_set.entries.is_empty() => {
36 let options = entries_set.entries.into_iter().collect();
37 Select::new("Select signer id", options)
38 .with_help_message("Use CLI mode to add signer from previous version")
39 .prompt()?
40 }
41 _ => inquire::Text::new("Signer id").prompt()?,
43 };
44 Ok(Some(signer_id))
45}
46
47pub fn parse_coins() -> InquireResult<cosmwasm_std::Coins> {
48 let mut coins = cosmwasm_std::Coins::default();
49 loop {
50 let coin = inquire::Text::new("Add coin to transaction")
51 .with_help_message("Leave empty to stop adding coins")
52 .with_placeholder("0ucoin")
53 .prompt()?;
54 if !coin.is_empty() {
55 match coin.parse() {
56 Ok(c) => coins
57 .add(c)
58 .map_err(|e| InquireError::Custom(Box::new(e)))?,
59 Err(e) => {
60 println!("Failed to add coin: {e}")
61 }
62 }
63 } else {
64 break;
65 }
66 }
67 println!("attached coins: {coins}");
68 Ok(coins)
69}
70
71#[derive(Clone, Copy, strum::EnumIter, strum::EnumString, derive_more::Display)]
72pub enum ExpirationType {
73 AtHeight,
74 AtTime,
75 Never,
76}
77
78impl ExpirationType {
79 const VARIANTS: &'static [ExpirationType] = &[Self::AtHeight, Self::AtTime, Self::Never];
80}
81
82pub fn parse_expiration() -> InquireResult<cw_utils::Expiration> {
83 let locked = inquire::Select::new("Choose expiration type", ExpirationType::VARIANTS.to_vec())
84 .prompt()?;
85
86 let expiration = match locked {
87 ExpirationType::AtHeight => {
88 let block_height = inquire::CustomType::<u64>::new("Input block height").prompt()?;
89 cw_utils::Expiration::AtHeight(block_height)
90 }
91 ExpirationType::AtTime => {
92 let timestamp_nanos =
93 inquire::CustomType::<u64>::new("Input timestamp in nanos").prompt()?;
94 let timestamp = cosmwasm_std::Timestamp::from_nanos(timestamp_nanos);
95 cw_utils::Expiration::AtTime(timestamp)
96 }
97 ExpirationType::Never => cw_utils::Expiration::Never {},
98 };
99 Ok(expiration)
100}
101
102pub async fn show_addr_explorer(chain_info: ChainInfo, addr: &str) -> color_eyre::eyre::Result<()> {
103 if let ChainKind::Mainnet = chain_info.kind {
104 let Explorers { explorers } =
105 Explorers::fetch(chain_info.network_info.chain_name.to_owned(), None).await?;
106 for explorer in explorers {
107 if let Some(tx_page) = explorer.account_page {
108 let url = tx_page.replace("${accountAddress}", addr);
109 println!("Explorer: {url}");
110 break;
111 }
112 }
113 }
114 Ok(())
115}