Skip to content

Commit fcd71bd

Browse files
feat(wasm-utxo-cli): add address from-descriptor subcommand
Print the address for a descriptor (WIF/hex/xpub-based), which may embed a private key (e.g. pkh(<wif>)) via wasm-utxo's script_pubkey_from_descriptor. General utility for deriving addresses from descriptors on the command line, not tied to any particular coin or script type. Refs: T1-3672
1 parent 4020a73 commit fcd71bd

3 files changed

Lines changed: 60 additions & 2 deletions

File tree

packages/wasm-utxo/cli/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,29 @@ wasm-utxo-cli address encode 0014e8df018c7e326cc253faac7e46cdc51e68542c42
6868
# Output: bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
6969
```
7070

71+
#### Derive an address from a descriptor
72+
73+
```bash
74+
wasm-utxo-cli address from-descriptor <DESCRIPTOR> --network <NETWORK>
75+
```
76+
77+
The descriptor may name a plain public key or embed a private key directly (e.g. a WIF) —
78+
either way, the resulting address is derived from the corresponding public key. Works for any
79+
network, not just Bitcoin.
80+
81+
**Examples:**
82+
83+
```bash
84+
# BTC: derive a P2PKH address from a public key
85+
wasm-utxo-cli address from-descriptor "pkh(039ab0771c5f88913208a26f81ab8223e98d25176e4648a5a2bb8ff79cf1c5198b)" --network btc
86+
# Output: 1GwwqAWsJzDHMZ9ceJqrJDfch4gsro4c3x
87+
88+
# Zcash: derive a t-address directly from a WIF private key (e.g. for zebrad's miner_address on
89+
# regtest — Zcash regtest reuses testnet address prefixes, so pass --network tzec)
90+
wasm-utxo-cli address from-descriptor "pkh(KzEGYtKcbhYwUWcZygbsqmF31f3iV7HC3iUQug7MBecwCz9hm1Tv)" --network tzec
91+
# Output: tmRfJALRQfyWP6SPxFTxiHhSHYhxn7rwkLv
92+
```
93+
7194
### PSBT Operations
7295

7396
#### Parse and inspect a PSBT

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use anyhow::{Context, Result};
1+
use anyhow::{anyhow, Context, Result};
22
use clap::Subcommand;
33
use wasm_utxo::bitcoin::Script;
4-
use wasm_utxo::{from_output_script_with_network, to_output_script_with_network, Network};
4+
use wasm_utxo::{
5+
from_output_script_with_network, script_pubkey_from_descriptor, to_output_script_with_network,
6+
Network,
7+
};
58

69
use crate::network::NetworkArg;
710

@@ -23,6 +26,15 @@ pub enum AddressCommand {
2326
#[arg(short, long, value_enum)]
2427
network: NetworkArg,
2528
},
29+
/// Print the address for a descriptor, which may embed a private key (e.g. `pkh(<wif>)`,
30+
/// `wpkh(<wif>)`)
31+
FromDescriptor {
32+
/// Descriptor, e.g. `pkh(<privkey>)`
33+
descriptor: String,
34+
/// Network (btc, tbtc, ltc, bch, zec, tzec, etc.)
35+
#[arg(short, long, value_enum)]
36+
network: NetworkArg,
37+
},
2638
}
2739

2840
pub fn handle_command(command: AddressCommand) -> Result<()> {
@@ -44,5 +56,16 @@ pub fn handle_command(command: AddressCommand) -> Result<()> {
4456
println!("{}", address);
4557
Ok(())
4658
}
59+
AddressCommand::FromDescriptor {
60+
descriptor,
61+
network,
62+
} => {
63+
let network: Network = network.into();
64+
let script = script_pubkey_from_descriptor(&descriptor).map_err(|e| anyhow!(e))?;
65+
let address = from_output_script_with_network(&script, network)
66+
.context("Failed to encode address")?;
67+
println!("{}", address);
68+
Ok(())
69+
}
4770
}
4871
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ use base64::Engine;
33
use std::fs;
44
use std::io::{self, Read};
55
use std::path::PathBuf;
6+
use std::str::FromStr;
7+
use wasm_utxo::bitcoin::network::Network as BitcoinNetwork;
8+
use wasm_utxo::bitcoin::PrivateKey;
9+
10+
/// Parse a private key given as WIF or raw hex bytes.
11+
pub fn parse_private_key(s: &str) -> Result<PrivateKey> {
12+
if let Ok(pk) = PrivateKey::from_str(s) {
13+
return Ok(pk);
14+
}
15+
let bytes = hex::decode(s).context("private key must be WIF or hex")?;
16+
PrivateKey::from_slice(&bytes, BitcoinNetwork::Bitcoin).context("invalid private key bytes")
17+
}
618

719
/// Decode input bytes, attempting to interpret as base64, hex, or raw bytes
820
pub fn decode_input(raw_bytes: &[u8]) -> Result<Vec<u8>> {

0 commit comments

Comments
 (0)