layer_climb_cli/command/
wallet.rsuse anyhow::Result;
use bip39::Mnemonic;
use clap::Subcommand;
use layer_climb::{prelude::*, proto::abci::TxResponse};
use rand::Rng;
#[derive(Debug, Clone, Subcommand)]
pub enum WalletCommand {
Create,
Show,
Balance {
#[arg(long)]
address: String,
#[arg(long)]
denom: Option<String>,
},
AllBalances {
#[arg(long)]
address: String,
},
Transfer {
#[arg(long)]
to: String,
#[arg(long)]
amount: u128,
#[arg(long)]
denom: Option<String>,
},
}
impl WalletCommand {
pub async fn run(
&self,
client: impl Into<AnyClient>,
rng: &mut impl Rng,
log: impl Fn(WalletLog),
) -> Result<()> {
let client = client.into();
match self {
WalletCommand::Create => {
let (addr, mnemonic) =
create_wallet(client.as_querier().chain_config.clone(), rng).await?;
log(WalletLog::Create { addr, mnemonic });
}
WalletCommand::Show => {
let balances = client
.as_querier()
.all_balances(client.as_signing().addr.clone(), None)
.await?;
if balances.is_empty() {
log(WalletLog::Show {
addr: client.as_signing().addr.clone(),
balances: vec![],
});
} else {
log(WalletLog::Show {
addr: client.as_signing().addr.clone(),
balances: balances.clone(),
});
}
}
WalletCommand::Balance { address, denom } => {
let addr = client.as_querier().chain_config.parse_address(address)?;
let balance = client
.as_querier()
.balance(addr.clone(), denom.clone())
.await?;
let denom = denom
.clone()
.unwrap_or_else(|| client.as_querier().chain_config.gas_denom.clone());
log(WalletLog::Balance {
addr,
balance: new_coin(balance.unwrap_or_default(), denom),
});
}
WalletCommand::AllBalances { address } => {
let addr = client.as_querier().chain_config.parse_address(address)?;
let balances = client.as_querier().all_balances(addr.clone(), None).await?;
log(WalletLog::AllBalances { addr, balances });
}
WalletCommand::Transfer { to, amount, denom } => {
let to = client.as_querier().chain_config.parse_address(to)?;
let tx_resp = client
.as_signing()
.transfer(*amount, &to, denom.as_deref(), None)
.await?;
log(WalletLog::Transfer {
to,
amount: *amount,
denom: denom
.clone()
.unwrap_or_else(|| client.as_querier().chain_config.gas_denom.clone()),
tx_resp: Box::new(tx_resp),
});
}
}
Ok(())
}
}
pub enum WalletLog {
Create {
addr: Address,
mnemonic: Mnemonic,
},
Show {
addr: Address,
balances: Vec<Coin>,
},
Balance {
addr: Address,
balance: Coin,
},
AllBalances {
addr: Address,
balances: Vec<Coin>,
},
Transfer {
to: Address,
amount: u128,
denom: String,
tx_resp: Box<TxResponse>,
},
}
pub async fn create_wallet(
chain_config: ChainConfig,
rng: &mut impl Rng,
) -> Result<(Address, Mnemonic)> {
let entropy: [u8; 32] = rng.random();
let mnemonic = Mnemonic::from_entropy(&entropy)?;
let signer = KeySigner::new_mnemonic_iter(mnemonic.words(), None)?;
let addr = chain_config.address_from_pub_key(&signer.public_key().await?)?;
Ok((addr, mnemonic))
}