|
|
@@ -4,25 +4,25 @@ use std::fs;
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
use clap::{Parser, Subcommand};
|
|
|
-use crown::utils::bytes::Byts;
|
|
|
use getrandom::getrandom;
|
|
|
-use sword::jets::cold::Nounable;
|
|
|
-use sword::noun::{Atom, Cell, IndirectAtom, Noun, D, SIG, T};
|
|
|
+use nockapp::utils::bytes::Byts;
|
|
|
+use nockapp::{system_data_dir, CrownError, NockApp, NockAppError, ToBytesExt};
|
|
|
+use nockvm::jets::cold::Nounable;
|
|
|
+use nockvm::noun::{Atom, Cell, IndirectAtom, Noun, D, SIG, T};
|
|
|
+use tokio::fs as tokio_fs;
|
|
|
use tokio::net::UnixStream;
|
|
|
use tracing::{error, info};
|
|
|
use zkvm_jetpack::hot::produce_prover_hot_state;
|
|
|
|
|
|
mod error;
|
|
|
|
|
|
-use crown::kernel::boot::{self, Cli as BootCli};
|
|
|
-use crown::nockapp::driver::*;
|
|
|
-use crown::nockapp::wire::{Wire, WireRepr};
|
|
|
-use crown::nockapp::{NockApp, NockAppError};
|
|
|
-use crown::noun::slab::NounSlab;
|
|
|
-use crown::noun::IntoNoun;
|
|
|
-use crown::utils::make_tas;
|
|
|
-use crown::{exit_driver, file_driver, markdown_driver, one_punch_driver, CrownError, ToBytesExt};
|
|
|
use kernels::wallet::KERNEL;
|
|
|
+use nockapp::driver::*;
|
|
|
+use nockapp::kernel::boot::{self, Cli as BootCli};
|
|
|
+use nockapp::noun::slab::NounSlab;
|
|
|
+use nockapp::utils::make_tas;
|
|
|
+use nockapp::wire::{Wire, WireRepr};
|
|
|
+use nockapp::{exit_driver, file_driver, markdown_driver, one_punch_driver};
|
|
|
|
|
|
#[derive(Parser, Debug, Clone)]
|
|
|
#[command(author, version, about, long_about = None)]
|
|
|
@@ -69,9 +69,6 @@ type CommandNoun<T> = Result<(T, Operation), NockAppError>;
|
|
|
|
|
|
#[derive(Subcommand, Debug, Clone)]
|
|
|
pub enum Commands {
|
|
|
- /// Display the current wallet balance
|
|
|
- Balance,
|
|
|
-
|
|
|
/// Generate a new key pair
|
|
|
Keygen,
|
|
|
|
|
|
@@ -104,13 +101,6 @@ pub enum Commands {
|
|
|
index: Option<u64>,
|
|
|
},
|
|
|
|
|
|
- /// Show the balance of a specific address at a given block
|
|
|
- ShowBalance {
|
|
|
- /// Block to show balance at
|
|
|
- #[arg(short, long)]
|
|
|
- block: String,
|
|
|
- },
|
|
|
-
|
|
|
/// Generate a master private key from a seed phrase
|
|
|
GenMasterPrivkey {
|
|
|
/// Seed phrase to generate master private key
|
|
|
@@ -189,17 +179,24 @@ pub enum Commands {
|
|
|
|
|
|
/// Lists all public keys in the wallet
|
|
|
ListPubkeys,
|
|
|
+
|
|
|
+ /// Show the seed phrase for the current master key
|
|
|
+ ShowSeedphrase,
|
|
|
+
|
|
|
+ /// Show the master public key
|
|
|
+ ShowMasterPubkey,
|
|
|
+
|
|
|
+ /// Show the master private key
|
|
|
+ ShowMasterPrivkey,
|
|
|
}
|
|
|
|
|
|
impl Commands {
|
|
|
fn as_wire_tag(&self) -> &'static str {
|
|
|
match self {
|
|
|
- Commands::Balance => "balance",
|
|
|
Commands::Keygen => "keygen",
|
|
|
Commands::DeriveChild { .. } => "derive-child",
|
|
|
Commands::ImportKeys { .. } => "import-keys",
|
|
|
Commands::SignTx { .. } => "sign-tx",
|
|
|
- Commands::ShowBalance { .. } => "show-balance",
|
|
|
Commands::GenMasterPrivkey { .. } => "gen-master-privkey",
|
|
|
Commands::GenMasterPubkey { .. } => "gen-master-pubkey",
|
|
|
Commands::Scan { .. } => "scan",
|
|
|
@@ -210,6 +207,9 @@ impl Commands {
|
|
|
Commands::UpdateBalance => "update-balance",
|
|
|
Commands::ImportMasterPubkey { .. } => "import-master-pubkey",
|
|
|
Commands::ListPubkeys => "list-pubkeys",
|
|
|
+ Commands::ShowSeedphrase => "show-seedphrase",
|
|
|
+ Commands::ShowMasterPubkey => "show-master-pubkey",
|
|
|
+ Commands::ShowMasterPrivkey => "show-master-privkey",
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -307,11 +307,6 @@ impl Wallet {
|
|
|
Ok((slab.clone(), operation))
|
|
|
}
|
|
|
|
|
|
- /// Retrieves the wallet balance.
|
|
|
- fn wallet_balance() -> CommandNoun<NounSlab> {
|
|
|
- Self::wallet("balance", &[], Operation::Peek, &mut NounSlab::new())
|
|
|
- }
|
|
|
-
|
|
|
/// Generates a new key pair.
|
|
|
///
|
|
|
/// # Arguments
|
|
|
@@ -389,17 +384,6 @@ impl Wallet {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- /// Shows the balance of a specific address at a given block.
|
|
|
- ///
|
|
|
- /// # Arguments
|
|
|
- ///
|
|
|
- /// * `block` - The block hash or height to show the balance at.
|
|
|
- fn balance_at_block(block: &str) -> CommandNoun<NounSlab> {
|
|
|
- let mut slab = NounSlab::new();
|
|
|
- let block_noun = IntoNoun::into_noun(block);
|
|
|
- Self::wallet("show-balance", &[block_noun], Operation::Poke, &mut slab)
|
|
|
- }
|
|
|
-
|
|
|
/// Generates a master private key from a seed phrase.
|
|
|
///
|
|
|
/// # Arguments
|
|
|
@@ -707,6 +691,36 @@ impl Wallet {
|
|
|
&mut slab,
|
|
|
)
|
|
|
}
|
|
|
+
|
|
|
+ /// Shows the seed phrase for the current master key.
|
|
|
+ fn show_seedphrase() -> CommandNoun<NounSlab> {
|
|
|
+ let mut slab = NounSlab::new();
|
|
|
+ Self::wallet("show-seedphrase", &[], Operation::Poke, &mut slab)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Shows the master public key.
|
|
|
+ fn show_master_pubkey() -> CommandNoun<NounSlab> {
|
|
|
+ let mut slab = NounSlab::new();
|
|
|
+ Self::wallet("show-master-pubkey", &[], Operation::Poke, &mut slab)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Shows the master private key.
|
|
|
+ fn show_master_privkey() -> CommandNoun<NounSlab> {
|
|
|
+ let mut slab = NounSlab::new();
|
|
|
+ Self::wallet("show-master-privkey", &[], Operation::Poke, &mut slab)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub async fn wallet_data_dir() -> Result<PathBuf, NockAppError> {
|
|
|
+ let wallet_data_dir = system_data_dir().join("wallet");
|
|
|
+ if !wallet_data_dir.exists() {
|
|
|
+ tokio_fs::create_dir_all(&wallet_data_dir)
|
|
|
+ .await
|
|
|
+ .map_err(|e| {
|
|
|
+ CrownError::Unknown(format!("Failed to create wallet data directory: {}", e))
|
|
|
+ })?;
|
|
|
+ }
|
|
|
+ Ok(wallet_data_dir)
|
|
|
}
|
|
|
|
|
|
#[tokio::main]
|
|
|
@@ -715,13 +729,14 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
boot::init_default_tracing(&cli.boot.clone()); // Init tracing early
|
|
|
|
|
|
let prover_hot_state = produce_prover_hot_state();
|
|
|
+ let data_dir = wallet_data_dir().await?;
|
|
|
|
|
|
let kernel = boot::setup(
|
|
|
KERNEL,
|
|
|
Some(cli.boot.clone()),
|
|
|
prover_hot_state.as_slice(),
|
|
|
"wallet",
|
|
|
- None,
|
|
|
+ Some(data_dir),
|
|
|
)
|
|
|
.await
|
|
|
.map_err(|e| CrownError::Unknown(format!("Kernel setup failed: {}", e)))?;
|
|
|
@@ -740,6 +755,9 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
| Commands::GenMasterPubkey { .. }
|
|
|
| Commands::ImportMasterPubkey { .. }
|
|
|
| Commands::ListPubkeys
|
|
|
+ | Commands::ShowSeedphrase
|
|
|
+ | Commands::ShowMasterPubkey
|
|
|
+ | Commands::ShowMasterPrivkey
|
|
|
| Commands::SimpleSpend { .. } => false,
|
|
|
|
|
|
// All other commands DO need sync
|
|
|
@@ -756,7 +774,6 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
|
|
|
// Generate the command noun and operation
|
|
|
let poke = match &cli.command {
|
|
|
- Commands::Balance => Wallet::wallet_balance(),
|
|
|
Commands::Keygen => {
|
|
|
let mut entropy = [0u8; 32];
|
|
|
let mut salt = [0u8; 16];
|
|
|
@@ -779,7 +796,6 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
Wallet::derive_child(key_type, *index)
|
|
|
}
|
|
|
Commands::SignTx { draft, index } => Wallet::sign_tx(draft, *index),
|
|
|
- Commands::ShowBalance { block } => Wallet::balance_at_block(block),
|
|
|
Commands::ImportKeys { input } => Wallet::import_keys(input),
|
|
|
Commands::GenMasterPrivkey { seedphrase } => Wallet::gen_master_privkey(seedphrase),
|
|
|
Commands::GenMasterPubkey { master_privkey } => Wallet::gen_master_pubkey(master_privkey),
|
|
|
@@ -809,6 +825,9 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
Commands::UpdateBalance => Wallet::update_balance(),
|
|
|
Commands::ImportMasterPubkey { key, knot } => Wallet::import_master_pubkey(key, knot),
|
|
|
Commands::ListPubkeys => Wallet::list_pubkeys(),
|
|
|
+ Commands::ShowSeedphrase => Wallet::show_seedphrase(),
|
|
|
+ Commands::ShowMasterPubkey => Wallet::show_master_pubkey(),
|
|
|
+ Commands::ShowMasterPrivkey => Wallet::show_master_privkey(),
|
|
|
}?;
|
|
|
|
|
|
// If this command requires sync and we have a socket, wrap it with sync-run
|
|
|
@@ -830,7 +849,7 @@ async fn main() -> Result<(), NockAppError> {
|
|
|
info!("Connected to nockchain NPC socket at {:?}", socket_path);
|
|
|
wallet
|
|
|
.app
|
|
|
- .add_io_driver(crown::npc_client_driver(stream))
|
|
|
+ .add_io_driver(nockapp::npc_client_driver(stream))
|
|
|
.await;
|
|
|
}
|
|
|
Err(e) => {
|
|
|
@@ -870,9 +889,9 @@ pub fn from_bytes(stack: &mut NounSlab, bytes: &[u8]) -> Atom {
|
|
|
mod tests {
|
|
|
use std::sync::Once;
|
|
|
|
|
|
- use crown::kernel::boot::{self, Cli as BootCli};
|
|
|
- use crown::nockapp::wire::SystemWire;
|
|
|
- use crown::{exit_driver, Bytes};
|
|
|
+ use nockapp::kernel::boot::{self, Cli as BootCli};
|
|
|
+ use nockapp::wire::SystemWire;
|
|
|
+ use nockapp::{exit_driver, Bytes};
|
|
|
use tokio::sync::mpsc;
|
|
|
|
|
|
use super::*;
|
|
|
@@ -915,10 +934,10 @@ mod tests {
|
|
|
|
|
|
println!("keygen result: {:?}", keygen_result);
|
|
|
assert!(
|
|
|
- keygen_result.len() == 1,
|
|
|
- "Expected keygen result to be a list of 1 noun slab"
|
|
|
+ keygen_result.len() == 2,
|
|
|
+ "Expected keygen result to be a list of 2 noun slabs - markdown and exit"
|
|
|
);
|
|
|
- let exit_cause = unsafe { keygen_result[0].root() };
|
|
|
+ let exit_cause = unsafe { keygen_result[1].root() };
|
|
|
let code = exit_cause.as_cell()?.tail();
|
|
|
assert!(unsafe { code.raw_equals(&D(0)) }, "Expected exit code 0");
|
|
|
|
|
|
@@ -1030,24 +1049,6 @@ mod tests {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- #[tokio::test]
|
|
|
- #[cfg_attr(miri, ignore)]
|
|
|
- async fn test_show_balance() -> Result<(), NockAppError> {
|
|
|
- init_tracing();
|
|
|
- let cli = BootCli::parse_from(&[""]);
|
|
|
- let nockapp = boot::setup(KERNEL, Some(cli.clone()), &[], "wallet", None)
|
|
|
- .await
|
|
|
- .map_err(|e| CrownError::Unknown(e.to_string()))?;
|
|
|
- let mut wallet = Wallet::new(nockapp);
|
|
|
- let block = "block123";
|
|
|
- let (noun, op) = Wallet::balance_at_block(block)?;
|
|
|
- let wire = WalletWire::Command(Commands::Balance {}).to_wire();
|
|
|
- let balance_result = wallet.app.poke(wire, noun.clone()).await?;
|
|
|
- println!("balance_result: {:?}", balance_result);
|
|
|
- // Verify balance
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
// Tests for Cold Side Commands
|
|
|
#[tokio::test]
|
|
|
#[cfg_attr(miri, ignore)]
|