diff --git a/framework/meta/src/cli/cli_args_standalone.rs b/framework/meta/src/cli/cli_args_standalone.rs index d670987338..59cb0a4d86 100644 --- a/framework/meta/src/cli/cli_args_standalone.rs +++ b/framework/meta/src/cli/cli_args_standalone.rs @@ -385,10 +385,10 @@ pub struct WalletNewArgs { #[derive(Default, Clone, PartialEq, Eq, Debug, Args)] pub struct WalletConvertArgs { #[arg(long = "in-format", verbatim_doc_comment)] - pub from: Option, + pub from: String, #[arg(long = "out-format", verbatim_doc_comment)] - pub to: Option, + pub to: String, #[arg(long = "infile", verbatim_doc_comment)] pub infile: Option, diff --git a/framework/meta/src/cmd/wallet.rs b/framework/meta/src/cmd/wallet.rs index b1fdddee9c..bdddf81b60 100644 --- a/framework/meta/src/cmd/wallet.rs +++ b/framework/meta/src/cmd/wallet.rs @@ -1,13 +1,14 @@ use base64; use core::str; +use multiversx_sc::types; use std::{ fs::{self, File}, - io::Write, + io::{self, Read, Write}, }; use crate::cli::{WalletAction, WalletArgs, WalletConvertArgs, WalletNewArgs}; use multiversx_sc_snippets::{hex, imports::Bech32Address}; -use multiversx_sdk::{data::address::Address, wallet::Wallet}; +use multiversx_sdk::{crypto::public_key::PublicKey, data::address::Address, wallet::Wallet}; pub fn wallet(args: &WalletArgs) { let command = args @@ -21,31 +22,37 @@ pub fn wallet(args: &WalletArgs) { } fn convert(convert_args: &WalletConvertArgs) { - let infile = convert_args - .infile - .as_ref() - .expect("input file is required"); + let infile = convert_args.infile.as_ref(); let outfile = convert_args.outfile.as_ref(); - let in_format = convert_args - .from - .as_ref() - .expect("input format is required"); - let out_format = convert_args.to.as_ref().expect("output format is required"); + let in_format = &convert_args.from; + let out_format = &convert_args.to; + + let mut in_address = String::new(); + let mut out_address: String = String::new(); + + match infile { + Some(file) => in_address = fs::read_to_string(file).unwrap(), + None => { + println!("Insert text below. Press 'Ctrl-D' (Linux / MacOS) or 'Ctrl-Z' (Windows) when done."); + _ = io::stdin().read_to_string(&mut in_address).unwrap() + }, + } - let in_address = fs::read_to_string(infile).unwrap(); - let mut out_addr: String = String::from(""); + in_address = in_address.replace('\n', ""); match (in_format.as_str(), out_format.as_str()) { ("address-bech32", "address-hex") => { - out_addr = Bech32Address::from_bech32_string(in_address).to_hex(); + out_address = Bech32Address::from_bech32_string(in_address).to_hex(); }, ("address-hex", "address-bech32") => { - // out_addr = Bech32Address::from(in_address).to_bech32_string(); - let bytes_from_hex: [u8; 64] = hex::decode(in_address).unwrap().try_into().unwrap(); - out_addr = Bech32Address::from_bech32_string( - str::from_utf8(&bytes_from_hex).unwrap().to_string(), - ) - .to_bech32_string(); + let bytes_from_hex = hex::decode(in_address).unwrap(); + let bytes_arr: [u8; 32] = bytes_from_hex.try_into().unwrap(); + + let addr = types::Address::from(&bytes_arr); + out_address = Bech32Address::from(addr).to_bech32_str().to_string(); + }, + ("", _) | (_, "") => { + println!("error: the following arguments are required: --in-format, --out-format"); }, _ => { println!("Unsupported conversion"); @@ -55,49 +62,51 @@ fn convert(convert_args: &WalletConvertArgs) { match outfile { Some(outfile) => { let mut file = File::create(outfile).unwrap(); - file.write_all(out_addr.as_bytes()).unwrap(); + out_address.push('\n'); + file.write_all(out_address.as_bytes()).unwrap(); }, None => { - println!("{}", out_addr); + println!("{}", out_address); }, } } fn new(new_args: &WalletNewArgs) { - let format = new_args - .wallet_format - .as_ref() - .expect("wallet format is required"); - let outfile = new_args.outfile.as_ref().expect("output file is required"); + let format = new_args.wallet_format.as_ref(); + let outfile = new_args.outfile.as_ref(); + let mnemonic = Wallet::generate_mnemonic(); + println!("Mnemonic: {}", mnemonic); - match format.as_str() { - "pem" => { - let mnemonic = Wallet::generate_mnemonic(); - let private_key = Wallet::get_private_key_from_mnemonic(mnemonic, 0u32, 0u32); - let pk_str: &str = &private_key.to_string(); - let wallet = Wallet::from_private_key(pk_str).unwrap(); - let address = wallet.address(); + let private_key = Wallet::get_private_key_from_mnemonic(mnemonic, 0u32, 0u32); + let public_key = PublicKey::from(&private_key); - println!("Wallet address: {}", address); + let public_key_str: &str = &public_key.to_string(); + let private_key_str: &str = &private_key.to_string(); - generate_pem(&address, pk_str, outfile); - }, - _ => { - println!("Unsupported wallet format"); - }, + let wallet = Wallet::from_private_key(private_key_str).unwrap(); + let address = wallet.address(); + + println!("Wallet address: {}", address); + + if let Some(f) = format { + match (f.as_str(), outfile) { + ("pem", Some(file)) => { + generate_pem(&address, private_key_str, public_key_str, file); + }, + ("pem", None) => { + println!("Output file is required for PEM format"); + }, + _ => {}, + } } } -fn generate_pem(address: &Address, private_key: &str, outfile: &String) { - println!("{private_key}"); - let private_key_hex_encoded = hex::encode(private_key.as_bytes()); - println!("HEX {private_key_hex_encoded}"); - // let priv_key_bytes = private_key_hex_encoded.as_bytes(); - let private_key_base64 = base64::encode(&private_key_hex_encoded.as_bytes()); - println!("B64 {private_key_base64}"); +fn generate_pem(address: &Address, private_key: &str, public_key: &str, outfile: &String) { + let concat_keys = format!("{}{}", private_key, public_key); + let concat_keys_b64 = base64::encode(concat_keys); // Split the base64 string into 64-character lines - let formatted_key = private_key_base64 + let formatted_key = concat_keys_b64 .as_bytes() .chunks(64) .map(|chunk| std::str::from_utf8(chunk).unwrap())