Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/wasm-utxo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions packages/wasm-utxo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(feature, values("zebra-test"))',
] }

[features]
default = []
inspect = ["dep:num-bigint", "dep:serde", "dep:serde_json", "dep:hex"]

[dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
Expand All @@ -28,6 +32,10 @@ bech32 = "0.11"
musig2 = { version = "0.3.1", default-features = false, features = ["k256"] }
getrandom = { version = "0.2", features = ["js"] }
pastey = "0.1"
num-bigint = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
hex = { version = "0.4", optional = true }

[dev-dependencies]
base64 = "0.22.1"
Expand Down
30 changes: 30 additions & 0 deletions packages/wasm-utxo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,36 @@ Zcash support includes:
- **Height-Based API**: Preferred `createEmpty()` method automatically selects correct consensus rules
- **Parity Testing**: Validated against `zebra-chain` for accuracy across all network upgrades

## Inspect Feature

The `inspect` feature adds PSBT and transaction parsing into hierarchical node trees,
useful for building tree-view UIs and CLI formatters.

It is behind a Cargo feature flag because it pulls in extra dependencies (`serde`, `serde_json`,
`num-bigint`, `hex`) that are not needed for core wallet operations.

### Rust

```rust
// Cargo.toml
wasm-utxo = { path = ".", features = ["inspect"] }

// Usage
use wasm_utxo::inspect::{parse_psbt_bytes_with_network, parse_tx_bytes_with_network, Node};
```

### TypeScript

Available as a separate import path, not included in the main `@bitgo/wasm-utxo` entry:

```typescript
import { parsePsbtToNode, parseTxToNode, isInspectEnabled } from "@bitgo/wasm-utxo/inspect";
```

The published npm package includes stub implementations that return `isInspectEnabled() === false`
and throw runtime errors from the parse functions. To get a working build, compile the WASM with
`--features inspect` (see [`packages/webui/scripts/build-wasm.sh`](../webui/scripts/build-wasm.sh)).

## Building

### Mac
Expand Down
2 changes: 1 addition & 1 deletion packages/wasm-utxo/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name = "wasm-utxo-cli"
path = "src/main.rs"

[dependencies]
wasm-utxo = { path = ".." }
wasm-utxo = { path = "..", features = ["inspect"] }
clap = { version = "4.5", features = ["derive"] }
anyhow = "1.0"
hex = "0.4"
Expand Down
47 changes: 10 additions & 37 deletions packages/wasm-utxo/cli/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,39 @@ use clap::Subcommand;
use wasm_utxo::bitcoin::Script;
use wasm_utxo::{from_output_script_with_network, to_output_script_with_network, Network};

use crate::network::NetworkArg;

#[derive(Subcommand)]
pub enum AddressCommand {
/// Decode an address to its output script (hex)
Decode {
/// The address to decode
address: String,
/// Network (bitcoin, testnet, litecoin, zcash, etc.)
#[arg(short, long, default_value = "bitcoin")]
network: String,
/// Network (btc, tbtc, ltc, bch, zec, etc.)
#[arg(short, long, value_enum)]
network: NetworkArg,
},
/// Encode an output script (hex) to an address
Encode {
/// Output script as hex
script: String,
/// Network (bitcoin, testnet, litecoin, zcash, etc.)
#[arg(short, long, default_value = "bitcoin")]
network: String,
/// Network (btc, tbtc, ltc, bch, zec, etc.)
#[arg(short, long, value_enum)]
network: NetworkArg,
},
}

pub fn handle_command(command: AddressCommand) -> Result<()> {
match command {
AddressCommand::Decode { address, network } => {
let network = parse_network(&network)?;
let network: Network = network.into();
let script = to_output_script_with_network(&address, network)
.context("Failed to decode address")?;
println!("{}", hex::encode(script.as_bytes()));
Ok(())
}
AddressCommand::Encode { script, network } => {
let network = parse_network(&network)?;
let network: Network = network.into();
let script_bytes =
hex::decode(&script).context("Invalid hex string for output script")?;
let script_obj = Script::from_bytes(&script_bytes);
Expand All @@ -44,32 +46,3 @@ pub fn handle_command(command: AddressCommand) -> Result<()> {
}
}
}

fn parse_network(network: &str) -> Result<Network> {
// Try utxolib name first (e.g., "bitcoin", "testnet", "bitcoincash")
if let Some(net) = Network::from_utxolib_name(network) {
return Ok(net);
}

// Try coin name (e.g., "btc", "ltc", "bch")
if let Some(net) = Network::from_coin_name(network) {
return Ok(net);
}

// Try common aliases
let normalized = network.to_lowercase();
match normalized.as_str() {
"test" | "testnet3" => Ok(Network::BitcoinTestnet3),
"signet" => Ok(Network::BitcoinPublicSignet),
"ltctest" => Ok(Network::LitecoinTestnet),
"bchtest" => Ok(Network::BitcoinCashTestnet),
"bsvtest" => Ok(Network::BitcoinSVTestnet),
"btgtest" => Ok(Network::BitcoinGoldTestnet),
"dashtest" => Ok(Network::DashTestnet),
"zectest" => Ok(Network::ZcashTestnet),
"dogetest" => Ok(Network::DogecoinTestnet),
"xec" => Ok(Network::Ecash),
"xectest" => Ok(Network::EcashTestnet),
_ => anyhow::bail!("Unknown network: {}", network),
}
}
4 changes: 2 additions & 2 deletions packages/wasm-utxo/cli/src/format/fixtures.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#[cfg(test)]
use super::tree::{node_to_string_with_scheme, ColorScheme};
#[cfg(test)]
use crate::node::Node;
#[cfg(test)]
use std::env;
#[cfg(test)]
use std::fs;
#[cfg(test)]
use std::io::{self, Write};
#[cfg(test)]
use wasm_utxo::inspect::Node;

/// Ensure the generated tree output matches the fixture file
/// If the fixture doesn't exist, it will be created
Expand Down
2 changes: 1 addition & 1 deletion packages/wasm-utxo/cli/src/format/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::format::fixtures::assert_or_update_fixture;
use crate::node::{Node, Primitive};
use num_bigint::BigInt;
use wasm_utxo::inspect::{Node, Primitive};

#[test]
fn test_simple_tree() -> std::io::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion packages/wasm-utxo/cli/src/format/tree.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::node::{Node, Primitive};
use colored::*;
use ptree::print_tree;
#[cfg(test)]
use ptree::TreeBuilder;
use std::borrow::Cow;
use std::io;
use wasm_utxo::inspect::{Node, Primitive};

/// Defines how different parts of the tree should be styled
#[derive(Clone, Debug)]
Expand Down
7 changes: 5 additions & 2 deletions packages/wasm-utxo/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ use clap::{Parser, Subcommand};
mod address;
mod format;
mod input;
mod node;
mod parse;
mod network;
mod psbt;
mod tx;

pub use network::NetworkArg;

#[cfg(test)]
mod parse_tests;
#[cfg(test)]
pub mod test_utils;

Expand Down
54 changes: 54 additions & 0 deletions packages/wasm-utxo/cli/src/network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Network argument type for CLI commands

use clap::ValueEnum;
use wasm_utxo::Network;

/// CLI argument type for network selection
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum NetworkArg {
Btc,
Tbtc,
Tbtc4,
Ltc,
Tltc,
Bch,
Tbch,
Bcha,
Tbcha,
Btg,
Tbtg,
Bsv,
Tbsv,
Dash,
Tdash,
Doge,
Tdoge,
Zec,
Tzec,
}

impl From<NetworkArg> for Network {
fn from(arg: NetworkArg) -> Self {
match arg {
NetworkArg::Btc => Network::Bitcoin,
NetworkArg::Tbtc => Network::BitcoinTestnet3,
NetworkArg::Tbtc4 => Network::BitcoinTestnet4,
NetworkArg::Ltc => Network::Litecoin,
NetworkArg::Tltc => Network::LitecoinTestnet,
NetworkArg::Bch => Network::BitcoinCash,
NetworkArg::Tbch => Network::BitcoinCashTestnet,
NetworkArg::Bcha => Network::Ecash,
NetworkArg::Tbcha => Network::EcashTestnet,
NetworkArg::Btg => Network::BitcoinGold,
NetworkArg::Tbtg => Network::BitcoinGoldTestnet,
NetworkArg::Bsv => Network::BitcoinSV,
NetworkArg::Tbsv => Network::BitcoinSVTestnet,
NetworkArg::Dash => Network::Dash,
NetworkArg::Tdash => Network::DashTestnet,
NetworkArg::Doge => Network::Dogecoin,
NetworkArg::Tdoge => Network::DogecoinTestnet,
NetworkArg::Zec => Network::Zcash,
NetworkArg::Tzec => Network::ZcashTestnet,
}
}
}
5 changes: 0 additions & 5 deletions packages/wasm-utxo/cli/src/parse/mod.rs

This file was deleted.

Loading