Skip to content

Commit 0369874

Browse files
OttoAllmendingerllm-git
andcommitted
feat(wasm-utxo): add enum-based network selection for CLI
Refactor network handling to use an enum-based approach for improved type safety and better user experience. Replace string-based network arguments with structured enum types that explicitly list all supported networks. This change: - Adds NetworkArg enum for CLI commands that use network parameters - Updates address, psbt, and tx commands to use the new network type - Removes hard-coded string handling for network parsing - Simplifies interface by requiring explicit network parameter - Removes redundant internal parse functions Issue: BTC-0 Co-authored-by: llm-git <llm-git@ttll.de>
1 parent d759aa3 commit 0369874

12 files changed

Lines changed: 125 additions & 85 deletions

File tree

packages/wasm-utxo/cli/src/address.rs

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,39 @@ use clap::Subcommand;
33
use wasm_utxo::bitcoin::Script;
44
use wasm_utxo::{from_output_script_with_network, to_output_script_with_network, Network};
55

6+
use crate::network::NetworkArg;
7+
68
#[derive(Subcommand)]
79
pub enum AddressCommand {
810
/// Decode an address to its output script (hex)
911
Decode {
1012
/// The address to decode
1113
address: String,
12-
/// Network (bitcoin, testnet, litecoin, zcash, etc.)
13-
#[arg(short, long, default_value = "bitcoin")]
14-
network: String,
14+
/// Network (btc, tbtc, ltc, bch, zec, etc.)
15+
#[arg(short, long, value_enum)]
16+
network: NetworkArg,
1517
},
1618
/// Encode an output script (hex) to an address
1719
Encode {
1820
/// Output script as hex
1921
script: String,
20-
/// Network (bitcoin, testnet, litecoin, zcash, etc.)
21-
#[arg(short, long, default_value = "bitcoin")]
22-
network: String,
22+
/// Network (btc, tbtc, ltc, bch, zec, etc.)
23+
#[arg(short, long, value_enum)]
24+
network: NetworkArg,
2325
},
2426
}
2527

2628
pub fn handle_command(command: AddressCommand) -> Result<()> {
2729
match command {
2830
AddressCommand::Decode { address, network } => {
29-
let network = parse_network(&network)?;
31+
let network: Network = network.into();
3032
let script = to_output_script_with_network(&address, network)
3133
.context("Failed to decode address")?;
3234
println!("{}", hex::encode(script.as_bytes()));
3335
Ok(())
3436
}
3537
AddressCommand::Encode { script, network } => {
36-
let network = parse_network(&network)?;
38+
let network: Network = network.into();
3739
let script_bytes =
3840
hex::decode(&script).context("Invalid hex string for output script")?;
3941
let script_obj = Script::from_bytes(&script_bytes);
@@ -44,32 +46,3 @@ pub fn handle_command(command: AddressCommand) -> Result<()> {
4446
}
4547
}
4648
}
47-
48-
fn parse_network(network: &str) -> Result<Network> {
49-
// Try utxolib name first (e.g., "bitcoin", "testnet", "bitcoincash")
50-
if let Some(net) = Network::from_utxolib_name(network) {
51-
return Ok(net);
52-
}
53-
54-
// Try coin name (e.g., "btc", "ltc", "bch")
55-
if let Some(net) = Network::from_coin_name(network) {
56-
return Ok(net);
57-
}
58-
59-
// Try common aliases
60-
let normalized = network.to_lowercase();
61-
match normalized.as_str() {
62-
"test" | "testnet3" => Ok(Network::BitcoinTestnet3),
63-
"signet" => Ok(Network::BitcoinPublicSignet),
64-
"ltctest" => Ok(Network::LitecoinTestnet),
65-
"bchtest" => Ok(Network::BitcoinCashTestnet),
66-
"bsvtest" => Ok(Network::BitcoinSVTestnet),
67-
"btgtest" => Ok(Network::BitcoinGoldTestnet),
68-
"dashtest" => Ok(Network::DashTestnet),
69-
"zectest" => Ok(Network::ZcashTestnet),
70-
"dogetest" => Ok(Network::DogecoinTestnet),
71-
"xec" => Ok(Network::Ecash),
72-
"xectest" => Ok(Network::EcashTestnet),
73-
_ => anyhow::bail!("Unknown network: {}", network),
74-
}
75-
}

packages/wasm-utxo/cli/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use clap::{Parser, Subcommand};
44
mod address;
55
mod format;
66
mod input;
7+
mod network;
78
mod psbt;
89
mod tx;
910

11+
pub use network::NetworkArg;
12+
1013
#[cfg(test)]
1114
mod parse_tests;
1215
#[cfg(test)]
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//! Network argument type for CLI commands
2+
3+
use clap::ValueEnum;
4+
use wasm_utxo::Network;
5+
6+
/// CLI argument type for network selection
7+
#[derive(Debug, Clone, Copy, ValueEnum)]
8+
pub enum NetworkArg {
9+
Btc,
10+
Tbtc,
11+
Tbtc4,
12+
Ltc,
13+
Tltc,
14+
Bch,
15+
Tbch,
16+
Bcha,
17+
Tbcha,
18+
Btg,
19+
Tbtg,
20+
Bsv,
21+
Tbsv,
22+
Dash,
23+
Tdash,
24+
Doge,
25+
Tdoge,
26+
Zec,
27+
Tzec,
28+
}
29+
30+
impl From<NetworkArg> for Network {
31+
fn from(arg: NetworkArg) -> Self {
32+
match arg {
33+
NetworkArg::Btc => Network::Bitcoin,
34+
NetworkArg::Tbtc => Network::BitcoinTestnet3,
35+
NetworkArg::Tbtc4 => Network::BitcoinTestnet4,
36+
NetworkArg::Ltc => Network::Litecoin,
37+
NetworkArg::Tltc => Network::LitecoinTestnet,
38+
NetworkArg::Bch => Network::BitcoinCash,
39+
NetworkArg::Tbch => Network::BitcoinCashTestnet,
40+
NetworkArg::Bcha => Network::Ecash,
41+
NetworkArg::Tbcha => Network::EcashTestnet,
42+
NetworkArg::Btg => Network::BitcoinGold,
43+
NetworkArg::Tbtg => Network::BitcoinGoldTestnet,
44+
NetworkArg::Bsv => Network::BitcoinSV,
45+
NetworkArg::Tbsv => Network::BitcoinSVTestnet,
46+
NetworkArg::Dash => Network::Dash,
47+
NetworkArg::Tdash => Network::DashTestnet,
48+
NetworkArg::Doge => Network::Dogecoin,
49+
NetworkArg::Tdoge => Network::DogecoinTestnet,
50+
NetworkArg::Zec => Network::Zcash,
51+
NetworkArg::Tzec => Network::ZcashTestnet,
52+
}
53+
}
54+
}

packages/wasm-utxo/cli/src/parse_tests.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
mod tests {
88
use crate::format::fixtures::assert_tree_matches_fixture;
99
use crate::test_utils::{load_psbt_bytes, load_tx_bytes, SignatureState, TxFormat};
10-
use wasm_utxo::parse_node::{parse_psbt_bytes_internal, parse_psbt_bytes_raw, parse_tx_bytes_internal};
1110
use wasm_utxo::Network;
11+
use wasm_utxo::parse_node::{
12+
parse_psbt_bytes_raw_with_network, parse_psbt_bytes_with_network,
13+
parse_tx_bytes_with_network,
14+
};
1215

1316
#[test]
1417
fn test_parse_psbt_bitcoin_fullsigned() -> Result<(), Box<dyn std::error::Error>> {
@@ -18,7 +21,7 @@ mod tests {
1821
TxFormat::Psbt,
1922
)?;
2023

21-
let node = parse_psbt_bytes_internal(&psbt_bytes)?;
24+
let node = parse_psbt_bytes_with_network(&psbt_bytes, Network::Bitcoin)?;
2225

2326
assert_tree_matches_fixture(&node, "psbt_bitcoin_fullsigned")?;
2427
Ok(())
@@ -32,7 +35,7 @@ mod tests {
3235
TxFormat::PsbtLite,
3336
)?;
3437

35-
let node = parse_tx_bytes_internal(&tx_bytes)?;
38+
let node = parse_tx_bytes_with_network(&tx_bytes, Network::Bitcoin)?;
3639

3740
assert_tree_matches_fixture(&node, "tx_bitcoin_fullsigned")?;
3841
Ok(())
@@ -43,7 +46,7 @@ mod tests {
4346
let psbt_bytes =
4447
load_psbt_bytes(Network::Bitcoin, SignatureState::Fullsigned, TxFormat::Psbt)?;
4548

46-
let node = parse_psbt_bytes_raw(&psbt_bytes)?;
49+
let node = parse_psbt_bytes_raw_with_network(&psbt_bytes, Network::Bitcoin)?;
4750

4851
assert_tree_matches_fixture(&node, "psbt_raw_bitcoin_fullsigned")?;
4952
Ok(())

packages/wasm-utxo/cli/src/psbt/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::Result;
22
use clap::Subcommand;
33

4+
use crate::network::NetworkArg;
5+
46
mod parse;
57

68
#[derive(Subcommand)]
@@ -9,6 +11,9 @@ pub enum PsbtCommand {
911
Parse {
1012
/// Path to the PSBT file (use '-' to read from stdin)
1113
path: std::path::PathBuf,
14+
/// Network for address formatting
15+
#[arg(long, short, value_enum)]
16+
network: NetworkArg,
1217
/// Disable colored output
1318
#[arg(long)]
1419
no_color: bool,
@@ -24,6 +29,7 @@ pub fn handle_command(command: PsbtCommand) -> Result<()> {
2429
path,
2530
no_color,
2631
raw,
27-
} => parse::handle_parse_command(path, no_color, raw),
32+
network,
33+
} => parse::handle_parse_command(path, no_color, raw, network.into()),
2834
}
2935
}

packages/wasm-utxo/cli/src/psbt/parse.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@ use std::path::PathBuf;
33

44
use crate::format::{render_tree_with_scheme, ColorScheme};
55
use crate::input::{decode_input, read_input_bytes};
6-
use wasm_utxo::parse_node::{parse_psbt_bytes_internal, parse_psbt_bytes_raw};
6+
use wasm_utxo::parse_node::{parse_psbt_bytes_raw_with_network, parse_psbt_bytes_with_network};
7+
use wasm_utxo::Network;
78

8-
pub fn handle_parse_command(path: PathBuf, no_color: bool, raw: bool) -> Result<()> {
9+
pub fn handle_parse_command(
10+
path: PathBuf,
11+
no_color: bool,
12+
raw: bool,
13+
network: Network,
14+
) -> Result<()> {
915
// Read from file or stdin
1016
let raw_bytes = read_input_bytes(&path, "PSBT")?;
1117

1218
// Decode input (auto-detect hex, base64, or raw bytes)
1319
let bytes = decode_input(&raw_bytes)?;
1420

1521
let node = if raw {
16-
parse_psbt_bytes_raw(&bytes)
22+
parse_psbt_bytes_raw_with_network(&bytes, network)
1723
.map_err(|e| anyhow::anyhow!("Failed to parse PSBT (raw): {}", e))?
1824
} else {
19-
parse_psbt_bytes_internal(&bytes)
25+
parse_psbt_bytes_with_network(&bytes, network)
2026
.map_err(|e| anyhow::anyhow!("Failed to parse PSBT: {}", e))?
2127
};
2228

packages/wasm-utxo/cli/src/tx/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::Result;
22
use clap::Subcommand;
33

4+
use crate::network::NetworkArg;
5+
46
mod parse;
57

68
#[derive(Subcommand)]
@@ -9,6 +11,9 @@ pub enum TxCommand {
911
Parse {
1012
/// Path to the transaction file (use '-' to read from stdin)
1113
path: std::path::PathBuf,
14+
/// Network for address formatting
15+
#[arg(long, short, value_enum)]
16+
network: NetworkArg,
1217
/// Disable colored output
1318
#[arg(long)]
1419
no_color: bool,
@@ -17,6 +22,10 @@ pub enum TxCommand {
1722

1823
pub fn handle_command(command: TxCommand) -> Result<()> {
1924
match command {
20-
TxCommand::Parse { path, no_color } => parse::handle_parse_command(path, no_color),
25+
TxCommand::Parse {
26+
path,
27+
no_color,
28+
network,
29+
} => parse::handle_parse_command(path, no_color, network.into()),
2130
}
2231
}

packages/wasm-utxo/cli/src/tx/parse.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ use std::path::PathBuf;
33

44
use crate::format::{render_tree_with_scheme, ColorScheme};
55
use crate::input::{decode_input, read_input_bytes};
6-
use wasm_utxo::parse_node::parse_tx_bytes_internal;
6+
use wasm_utxo::Network;
7+
use wasm_utxo::parse_node::parse_tx_bytes_with_network;
78

8-
pub fn handle_parse_command(path: PathBuf, no_color: bool) -> Result<()> {
9+
pub fn handle_parse_command(path: PathBuf, no_color: bool, network: Network) -> Result<()> {
910
// Read from file or stdin
1011
let raw_bytes = read_input_bytes(&path, "transaction")?;
1112

1213
// Decode input (auto-detect hex, base64, or raw bytes)
1314
let bytes = decode_input(&raw_bytes)?;
1415

15-
let node = parse_tx_bytes_internal(&bytes)
16+
let node = parse_tx_bytes_with_network(&bytes, network)
1617
.map_err(|e| anyhow::anyhow!("Failed to parse transaction: {}", e))?;
1718

1819
let color_scheme = if no_color {

packages/wasm-utxo/js/parseNode.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export interface Node {
8686
* @returns A Node tree representing the parsed PSBT structure
8787
* @throws If the PSBT bytes are invalid or network is unknown
8888
*/
89-
export function parsePsbtToNode(psbtBytes: Uint8Array, network: CoinName = "btc"): Node {
89+
export function parsePsbtToNode(psbtBytes: Uint8Array, network: CoinName): Node {
9090
const json = wasmParsePsbtToJson(psbtBytes, network);
9191
return JSON.parse(json) as Node;
9292
}
@@ -99,7 +99,7 @@ export function parsePsbtToNode(psbtBytes: Uint8Array, network: CoinName = "btc"
9999
* @returns A Node tree representing the parsed transaction structure
100100
* @throws If the transaction bytes are invalid or network is unknown
101101
*/
102-
export function parseTxToNode(txBytes: Uint8Array, network: CoinName = "btc"): Node {
102+
export function parseTxToNode(txBytes: Uint8Array, network: CoinName): Node {
103103
const json = wasmParseTxToJson(txBytes, network);
104104
return JSON.parse(json) as Node;
105105
}
@@ -162,7 +162,7 @@ export function tryParseTx(
162162
* @returns A Node tree representing the raw PSBT key-value structure
163163
* @throws If the PSBT bytes are invalid or network is unknown
164164
*/
165-
export function parsePsbtRawToNode(psbtBytes: Uint8Array, network: CoinName = "btc"): Node {
165+
export function parsePsbtRawToNode(psbtBytes: Uint8Array, network: CoinName): Node {
166166
const json = wasmParsePsbtRawToJson(psbtBytes, network);
167167
return JSON.parse(json) as Node;
168168
}

packages/wasm-utxo/src/parse_node/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod psbt_raw;
44

55
pub use node::{Buffer, Node, Primitive};
66
pub use psbt::{
7-
parse_psbt_bytes_internal, parse_psbt_bytes_with_network, parse_tx_bytes_internal,
8-
parse_tx_bytes_with_network, psbt_to_node, tx_to_node, zcash_psbt_to_node, zcash_tx_to_node,
7+
parse_psbt_bytes_with_network, parse_tx_bytes_with_network, psbt_to_node, tx_to_node,
8+
zcash_psbt_to_node, zcash_tx_to_node,
99
};
10-
pub use psbt_raw::{parse_psbt_bytes_raw, parse_psbt_bytes_raw_with_network};
10+
pub use psbt_raw::parse_psbt_bytes_raw_with_network;

0 commit comments

Comments
 (0)