Skip to content

Commit 04652b3

Browse files
OttoAllmendingerllm-git
andcommitted
feat(wasm-utxo): isolate WASM bindings into separate module
Move all WASM-specific code into a dedicated module to improve organization and separation of concerns. The core functionality remains unchanged, but the binding layer is now cleanly separated from the implementation. This refactoring: - Creates a new `wasm` module to contain all bindings - Moves JS/WASM interface code out of core implementation files - Maintains backward compatibility with existing JS API Issue: BTC-2652 Co-authored-by: llm-git <[email protected]>
1 parent 614d0d5 commit 04652b3

File tree

18 files changed

+407
-346
lines changed

18 files changed

+407
-346
lines changed

packages/wasm-utxo/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ This project is the successor of the Javascript `utxo-lib` package.
55
It provides WASM bindings for the `rust-bitcoin` and `rust-miniscript` crates
66
that help verify and co-sign transactions built by the BitGo Wallet Platform API.
77

8+
## Documentation
9+
10+
- **[`src/wasm-bindgen.md`](src/wasm-bindgen.md)** - Guide for creating WASM bindings using the namespace pattern
11+
- **[`js/README.md`](js/README.md)** - TypeScript wrapper layer architecture and best practices
12+
813
## Status
914

1015
This project is under active development.

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

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use super::{
1414
};
1515
use crate::bitcoin::Script;
1616
use crate::networks::Network;
17+
use miniscript::bitcoin::WitnessVersion;
1718

1819
/// Get codecs for decoding addresses for a given network.
1920
/// Returns multiple codecs to try in order (Base58Check, Bech32, CashAddr, etc.)
@@ -302,41 +303,6 @@ pub fn from_output_script_with_coin_and_format(
302303
from_output_script_with_network_and_format(script, network, format)
303304
}
304305

305-
use miniscript::bitcoin::WitnessVersion;
306-
// WASM bindings
307-
use wasm_bindgen::prelude::*;
308-
309-
#[wasm_bindgen]
310-
pub struct AddressNamespace;
311-
312-
#[wasm_bindgen]
313-
impl AddressNamespace {
314-
#[wasm_bindgen]
315-
pub fn to_output_script_with_coin(
316-
address: &str,
317-
coin: &str,
318-
) -> std::result::Result<Vec<u8>, JsValue> {
319-
to_output_script_with_coin(address, coin)
320-
.map(|script| script.to_bytes())
321-
.map_err(|e| JsValue::from_str(&e.to_string()))
322-
}
323-
324-
#[wasm_bindgen]
325-
pub fn from_output_script_with_coin(
326-
script: &[u8],
327-
coin: &str,
328-
format: Option<String>,
329-
) -> std::result::Result<String, JsValue> {
330-
let script_obj = Script::from_bytes(script);
331-
let format_str = format.as_deref();
332-
let address_format = AddressFormat::from_optional_str(format_str)
333-
.map_err(|e| JsValue::from_str(&e.to_string()))?;
334-
335-
from_output_script_with_coin_and_format(script_obj, coin, address_format)
336-
.map_err(|e| JsValue::from_str(&e.to_string()))
337-
}
338-
}
339-
340306
#[cfg(test)]
341307
mod tests {
342308
use super::*;

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

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/// Helper structs for compatibility with npm @bitgo/utxo-lib
22
/// Long-term we should not use the `Network` objects from @bitgo/utxo-lib any longer,
33
/// but for now we need to keep this compatibility layer.
4-
use wasm_bindgen::JsValue;
5-
64
use crate::address::networks::{AddressFormat, OutputScriptSupport};
75
use crate::address::{bech32, cashaddr, Base58CheckCodec};
86
use crate::bitcoin::{Script, ScriptBuf};
@@ -30,12 +28,6 @@ pub struct UtxolibNetwork {
3028
}
3129

3230
impl UtxolibNetwork {
33-
/// Parse a UtxolibNetwork object from a JavaScript value
34-
pub fn from_js_value(js_network: &JsValue) -> Result<Self> {
35-
use crate::try_from_js_value::TryFromJsValue;
36-
UtxolibNetwork::try_from_js_value(js_network)
37-
.map_err(|e| AddressError::InvalidAddress(e.to_string()))
38-
}
3931
pub fn output_script_support(&self) -> OutputScriptSupport {
4032
let segwit = self.bech32.is_some();
4133

@@ -140,64 +132,3 @@ pub fn to_output_script_with_network(address: &str, network: &UtxolibNetwork) ->
140132
address
141133
)))
142134
}
143-
144-
// WASM bindings for utxolib-compatible address functions
145-
use wasm_bindgen::prelude::*;
146-
147-
#[wasm_bindgen]
148-
pub struct UtxolibCompatNamespace;
149-
150-
#[wasm_bindgen]
151-
impl UtxolibCompatNamespace {
152-
/// Convert output script to address string
153-
///
154-
/// # Arguments
155-
/// * `script` - The output script as a byte array
156-
/// * `network` - The UtxolibNetwork object from JavaScript
157-
/// * `format` - Optional address format: "default" or "cashaddr" (only applicable for Bitcoin Cash and eCash)
158-
#[wasm_bindgen]
159-
pub fn from_output_script(
160-
script: &[u8],
161-
network: JsValue,
162-
format: Option<String>,
163-
) -> std::result::Result<String, JsValue> {
164-
let network = UtxolibNetwork::from_js_value(&network)
165-
.map_err(|e| JsValue::from_str(&e.to_string()))?;
166-
167-
let script_obj = Script::from_bytes(script);
168-
169-
let format_str = format.as_deref();
170-
let address_format = AddressFormat::from_optional_str(format_str)
171-
.map_err(|e| JsValue::from_str(&e.to_string()))?;
172-
173-
from_output_script_with_network(script_obj, &network, address_format)
174-
.map_err(|e| JsValue::from_str(&e.to_string()))
175-
}
176-
177-
/// Convert address string to output script
178-
///
179-
/// # Arguments
180-
/// * `address` - The address string
181-
/// * `network` - The UtxolibNetwork object from JavaScript
182-
/// * `format` - Optional address format (currently unused for decoding as all formats are accepted)
183-
#[wasm_bindgen]
184-
pub fn to_output_script(
185-
address: &str,
186-
network: JsValue,
187-
format: Option<String>,
188-
) -> std::result::Result<Vec<u8>, JsValue> {
189-
let network = UtxolibNetwork::from_js_value(&network)
190-
.map_err(|e| JsValue::from_str(&e.to_string()))?;
191-
192-
// Validate format parameter even though we don't use it for decoding
193-
if let Some(fmt) = format {
194-
let format_str = Some(fmt.as_str());
195-
AddressFormat::from_optional_str(format_str)
196-
.map_err(|e| JsValue::from_str(&e.to_string()))?;
197-
}
198-
199-
to_output_script_with_network(address, &network)
200-
.map(|script| script.to_bytes())
201-
.map_err(|e| JsValue::from_str(&e.to_string()))
202-
}
203-
}
Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/// This module contains code for the BitGo Fixed Script Wallets.
22
/// These are not based on descriptors.
3-
mod bip32interface;
43
mod wallet_keys;
54

65
pub mod wallet_scripts;
@@ -10,66 +9,3 @@ pub mod test_utils;
109

1110
pub use wallet_keys::*;
1211
pub use wallet_scripts::*;
13-
use wasm_bindgen::prelude::*;
14-
15-
use crate::address::networks::AddressFormat;
16-
use crate::error::WasmUtxoError;
17-
use crate::try_from_js_value::TryFromJsValue;
18-
use crate::utxolib_compat::UtxolibNetwork;
19-
20-
#[wasm_bindgen]
21-
pub struct FixedScriptWalletNamespace;
22-
23-
#[wasm_bindgen]
24-
impl FixedScriptWalletNamespace {
25-
#[wasm_bindgen]
26-
pub fn output_script(
27-
keys: JsValue,
28-
chain: u32,
29-
index: u32,
30-
network: JsValue,
31-
) -> Result<Vec<u8>, WasmUtxoError> {
32-
let network = UtxolibNetwork::try_from_js_value(&network)?;
33-
let chain = Chain::try_from(chain)
34-
.map_err(|e| WasmUtxoError::new(&format!("Invalid chain: {}", e)))?;
35-
36-
let wallet_keys = RootWalletKeys::from_jsvalue(&keys)?;
37-
let scripts = WalletScripts::from_wallet_keys(
38-
&wallet_keys,
39-
chain,
40-
index,
41-
&network.output_script_support(),
42-
)?;
43-
Ok(scripts.output_script().to_bytes())
44-
}
45-
46-
#[wasm_bindgen]
47-
pub fn address(
48-
keys: JsValue,
49-
chain: u32,
50-
index: u32,
51-
network: JsValue,
52-
address_format: Option<String>,
53-
) -> Result<String, WasmUtxoError> {
54-
let network = UtxolibNetwork::try_from_js_value(&network)?;
55-
let wallet_keys = RootWalletKeys::from_jsvalue(&keys)?;
56-
let chain = Chain::try_from(chain)
57-
.map_err(|e| WasmUtxoError::new(&format!("Invalid chain: {}", e)))?;
58-
let scripts = WalletScripts::from_wallet_keys(
59-
&wallet_keys,
60-
chain,
61-
index,
62-
&network.output_script_support(),
63-
)?;
64-
let script = scripts.output_script();
65-
let address_format = AddressFormat::from_optional_str(address_format.as_deref())
66-
.map_err(|e| WasmUtxoError::new(&format!("Invalid address format: {}", e)))?;
67-
let address = crate::address::utxolib_compat::from_output_script_with_network(
68-
&script,
69-
&network,
70-
address_format,
71-
)
72-
.map_err(|e| WasmUtxoError::new(&format!("Failed to generate address: {}", e)))?;
73-
Ok(address.to_string())
74-
}
75-
}

0 commit comments

Comments
 (0)