use clap::{Args, Subcommand, ValueEnum};
use kobe::ton::{AddressFormat, DerivationStyle, Deriver};
use kobe::{DerivationStyle as _, DerivedAccount, Wallet};
use crate::commands::simple::SimpleArgs;
use crate::output::{self, AccountOutput, HdWalletOutput};
#[derive(Args, Debug)]
pub(crate) struct TonCommand {
#[command(subcommand)]
command: TonSubcommand,
}
#[derive(Subcommand, Debug)]
enum TonSubcommand {
New {
#[command(flatten)]
args: TonArgs,
},
Import {
#[arg(short, long)]
mnemonic: String,
#[command(flatten)]
args: TonArgs,
},
}
#[derive(Debug, Clone, Copy, Default, ValueEnum)]
enum CliDerivationStyle {
#[default]
#[value(alias = "tonkeeper")]
Standard,
#[value(name = "ledger-live", alias = "live")]
LedgerLive,
}
impl From<CliDerivationStyle> for DerivationStyle {
fn from(value: CliDerivationStyle) -> Self {
match value {
CliDerivationStyle::Standard => Self::Standard,
CliDerivationStyle::LedgerLive => Self::LedgerLive,
}
}
}
#[derive(Args, Debug, Clone)]
struct TonArgs {
#[arg(short, long)]
testnet: bool,
#[arg(short, long)]
bounceable: bool,
#[arg(long, default_value_t = 0, allow_hyphen_values = true)]
workchain: i8,
#[arg(short, long, value_enum, default_value_t = CliDerivationStyle::Standard)]
style: CliDerivationStyle,
#[command(flatten)]
common: SimpleArgs,
}
impl TonArgs {
#[inline]
const fn address_format(&self) -> AddressFormat {
AddressFormat::new(self.workchain, self.bounceable, self.testnet)
}
}
impl TonCommand {
pub(crate) fn execute(self, json: bool) -> Result<(), Box<dyn std::error::Error>> {
let (mnemonic, args) = match self.command {
TonSubcommand::New { args } => (None, args),
TonSubcommand::Import { mnemonic, args } => (Some(mnemonic), args),
};
let wallet = args.common.build_wallet(mnemonic.as_deref())?;
let format = args.address_format();
let style = DerivationStyle::from(args.style);
let deriver = Deriver::with_format(&wallet, format);
let accounts = deriver.derive_many_with(style, 0, args.common.count)?;
let out = build_hd(&wallet, format, style, &accounts);
output::render_hd_wallet(&out, json, args.common.qr)?;
Ok(())
}
}
fn build_hd(
wallet: &Wallet,
format: AddressFormat,
style: DerivationStyle,
accounts: &[DerivedAccount],
) -> HdWalletOutput {
HdWalletOutput {
chain: "ton",
network: Some(if format.testnet { "testnet" } else { "mainnet" }),
address_type: Some(if format.bounceable {
"bounceable"
} else {
"non-bounceable"
}),
mnemonic: wallet.mnemonic().to_owned(),
passphrase_protected: wallet.has_passphrase(),
derivation_style: Some(style.name()),
accounts: accounts
.iter()
.enumerate()
.map(|(i, a)| AccountOutput::from_derived(i, a))
.collect(),
}
}