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
61 changes: 27 additions & 34 deletions packages/wasm-utxo/src/descriptor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::WasmMiniscriptError;
use crate::error::WasmUtxoError;
use crate::try_into_js_value::TryIntoJsValue;
use miniscript::bitcoin::secp256k1::{Secp256k1, Signing};
use miniscript::bitcoin::ScriptBuf;
Expand All @@ -19,7 +19,7 @@ pub struct WrapDescriptor(pub(crate) WrapDescriptorEnum);

#[wasm_bindgen]
impl WrapDescriptor {
pub fn node(&self) -> Result<JsValue, WasmMiniscriptError> {
pub fn node(&self) -> Result<JsValue, WasmUtxoError> {
Ok(match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.try_to_js_value()?,
WrapDescriptorEnum::Definite(desc) => desc.try_to_js_value()?,
Expand All @@ -43,20 +43,20 @@ impl WrapDescriptor {
}

#[wasm_bindgen(js_name = atDerivationIndex)]
pub fn at_derivation_index(&self, index: u32) -> Result<WrapDescriptor, WasmMiniscriptError> {
pub fn at_derivation_index(&self, index: u32) -> Result<WrapDescriptor, WasmUtxoError> {
match &self.0 {
WrapDescriptorEnum::Derivable(desc, _keys) => {
let d = desc.at_derivation_index(index)?;
Ok(WrapDescriptor(WrapDescriptorEnum::Definite(d)))
}
_ => Err(WasmMiniscriptError::new(
_ => Err(WasmUtxoError::new(
"Cannot derive from a definite descriptor",
)),
}
}

#[wasm_bindgen(js_name = descType)]
pub fn desc_type(&self) -> Result<JsValue, WasmMiniscriptError> {
pub fn desc_type(&self) -> Result<JsValue, WasmUtxoError> {
(match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.desc_type(),
WrapDescriptorEnum::Definite(desc) => desc.desc_type(),
Expand All @@ -66,38 +66,36 @@ impl WrapDescriptor {
}

#[wasm_bindgen(js_name = scriptPubkey)]
pub fn script_pubkey(&self) -> Result<Vec<u8>, WasmMiniscriptError> {
pub fn script_pubkey(&self) -> Result<Vec<u8>, WasmUtxoError> {
match &self.0 {
WrapDescriptorEnum::Definite(desc) => Ok(desc.script_pubkey().to_bytes()),
_ => Err(WasmMiniscriptError::new(
"Cannot encode a derivable descriptor",
)),
_ => Err(WasmUtxoError::new("Cannot encode a derivable descriptor")),
}
}

fn explicit_script(&self) -> Result<ScriptBuf, WasmMiniscriptError> {
fn explicit_script(&self) -> Result<ScriptBuf, WasmUtxoError> {
match &self.0 {
WrapDescriptorEnum::Definite(desc) => Ok(desc.explicit_script()?),
WrapDescriptorEnum::Derivable(_, _) => Err(WasmMiniscriptError::new(
"Cannot encode a derivable descriptor",
)),
WrapDescriptorEnum::String(_) => Err(WasmMiniscriptError::new(
"Cannot encode a string descriptor",
)),
WrapDescriptorEnum::Derivable(_, _) => {
Err(WasmUtxoError::new("Cannot encode a derivable descriptor"))
}
WrapDescriptorEnum::String(_) => {
Err(WasmUtxoError::new("Cannot encode a string descriptor"))
}
}
}

pub fn encode(&self) -> Result<Vec<u8>, WasmMiniscriptError> {
pub fn encode(&self) -> Result<Vec<u8>, WasmUtxoError> {
Ok(self.explicit_script()?.to_bytes())
}

#[wasm_bindgen(js_name = toAsmString)]
pub fn to_asm_string(&self) -> Result<String, WasmMiniscriptError> {
pub fn to_asm_string(&self) -> Result<String, WasmUtxoError> {
Ok(self.explicit_script()?.to_asm_string())
}

#[wasm_bindgen(js_name = maxWeightToSatisfy)]
pub fn max_weight_to_satisfy(&self) -> Result<u32, WasmMiniscriptError> {
pub fn max_weight_to_satisfy(&self) -> Result<u32, WasmUtxoError> {
let weight = (match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.max_weight_to_satisfy(),
WrapDescriptorEnum::Definite(desc) => desc.max_weight_to_satisfy(),
Expand All @@ -106,18 +104,18 @@ impl WrapDescriptor {
weight
.to_wu()
.try_into()
.map_err(|_| WasmMiniscriptError::new("Weight exceeds u32"))
.map_err(|_| WasmUtxoError::new("Weight exceeds u32"))
}

fn from_string_derivable<C: Signing>(
secp: &Secp256k1<C>,
descriptor: &str,
) -> Result<WrapDescriptor, WasmMiniscriptError> {
) -> Result<WrapDescriptor, WasmUtxoError> {
let (desc, keys) = Descriptor::parse_descriptor(secp, descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::Derivable(desc, keys)))
}

fn from_string_definite(descriptor: &str) -> Result<WrapDescriptor, WasmMiniscriptError> {
fn from_string_definite(descriptor: &str) -> Result<WrapDescriptor, WasmUtxoError> {
let desc = Descriptor::<DefiniteDescriptorKey>::from_str(descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc)))
}
Expand All @@ -135,7 +133,7 @@ impl WrapDescriptor {
/// - "string": For descriptors with string placeholders
///
/// # Returns
/// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
/// * `Result<WrapDescriptor, WasmUtxoError>` - The parsed descriptor or an error
///
/// # Example
/// ```
Expand All @@ -145,18 +143,15 @@ impl WrapDescriptor {
/// );
/// ```
#[wasm_bindgen(js_name = fromString, skip_typescript)]
pub fn from_string(
descriptor: &str,
pk_type: &str,
) -> Result<WrapDescriptor, WasmMiniscriptError> {
pub fn from_string(descriptor: &str, pk_type: &str) -> Result<WrapDescriptor, WasmUtxoError> {
match pk_type {
"derivable" => WrapDescriptor::from_string_derivable(&Secp256k1::new(), descriptor),
"definite" => WrapDescriptor::from_string_definite(descriptor),
"string" => {
let desc = Descriptor::<String>::from_str(descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::String(desc)))
}
_ => Err(WasmMiniscriptError::new("Invalid descriptor type")),
_ => Err(WasmUtxoError::new("Invalid descriptor type")),
}
}

Expand All @@ -168,7 +163,7 @@ impl WrapDescriptor {
/// * `descriptor` - A string containing the descriptor to parse
///
/// # Returns
/// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
/// * `Result<WrapDescriptor, WasmUtxoError>` - The parsed descriptor or an error
///
/// # Example
/// ```
Expand All @@ -183,12 +178,10 @@ impl WrapDescriptor {
/// );
/// ```
#[wasm_bindgen(js_name = fromStringDetectType, skip_typescript)]
pub fn from_string_detect_type(
descriptor: &str,
) -> Result<WrapDescriptor, WasmMiniscriptError> {
pub fn from_string_detect_type(descriptor: &str) -> Result<WrapDescriptor, WasmUtxoError> {
let secp = Secp256k1::new();
let (descriptor, _key_map) = Descriptor::parse_descriptor(&secp, descriptor)
.map_err(|_| WasmMiniscriptError::new("Invalid descriptor"))?;
.map_err(|_| WasmUtxoError::new("Invalid descriptor"))?;
if descriptor.has_wildcard() {
WrapDescriptor::from_string_derivable(&secp, &descriptor.to_string())
} else {
Expand All @@ -208,7 +201,7 @@ impl fmt::Display for WrapDescriptor {
}

impl FromStr for WrapDescriptor {
type Err = WasmMiniscriptError;
type Err = WasmUtxoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
WrapDescriptor::from_string_detect_type(s)
}
Expand Down
34 changes: 17 additions & 17 deletions packages/wasm-utxo/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
use core::fmt;

#[derive(Debug, Clone)]
pub enum WasmMiniscriptError {
pub enum WasmUtxoError {
StringError(String),
}

impl std::error::Error for WasmMiniscriptError {}
impl fmt::Display for WasmMiniscriptError {
impl std::error::Error for WasmUtxoError {}
impl fmt::Display for WasmUtxoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
WasmMiniscriptError::StringError(s) => write!(f, "{}", s),
WasmUtxoError::StringError(s) => write!(f, "{}", s),
}
}
}

impl From<&str> for WasmMiniscriptError {
impl From<&str> for WasmUtxoError {
fn from(s: &str) -> Self {
WasmMiniscriptError::StringError(s.to_string())
WasmUtxoError::StringError(s.to_string())
}
}

impl From<String> for WasmMiniscriptError {
impl From<String> for WasmUtxoError {
fn from(s: String) -> Self {
WasmMiniscriptError::StringError(s)
WasmUtxoError::StringError(s)
}
}

impl From<miniscript::Error> for WasmMiniscriptError {
impl From<miniscript::Error> for WasmUtxoError {
fn from(err: miniscript::Error) -> Self {
WasmMiniscriptError::StringError(err.to_string())
WasmUtxoError::StringError(err.to_string())
}
}

impl From<miniscript::descriptor::ConversionError> for WasmMiniscriptError {
impl From<miniscript::descriptor::ConversionError> for WasmUtxoError {
fn from(err: miniscript::descriptor::ConversionError) -> Self {
WasmMiniscriptError::StringError(err.to_string())
WasmUtxoError::StringError(err.to_string())
}
}

impl WasmMiniscriptError {
pub fn new(s: &str) -> WasmMiniscriptError {
WasmMiniscriptError::StringError(s.to_string())
impl WasmUtxoError {
pub fn new(s: &str) -> WasmUtxoError {
WasmUtxoError::StringError(s.to_string())
}
}

impl From<crate::address::AddressError> for WasmMiniscriptError {
impl From<crate::address::AddressError> for WasmUtxoError {
fn from(err: crate::address::AddressError) -> Self {
WasmMiniscriptError::StringError(err.to_string())
WasmUtxoError::StringError(err.to_string())
}
}
21 changes: 10 additions & 11 deletions packages/wasm-utxo/src/fixed_script_wallet/bip32interface.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::str::FromStr;

use crate::bitcoin::bip32::Xpub;
use crate::error::WasmMiniscriptError;
use crate::error::WasmUtxoError;
use crate::try_from_js_value::{get_buffer_field, get_field, get_nested_field};
use wasm_bindgen::JsValue;

fn try_xpub_from_bip32_properties(bip32_key: &JsValue) -> Result<Xpub, WasmMiniscriptError> {
fn try_xpub_from_bip32_properties(bip32_key: &JsValue) -> Result<Xpub, WasmUtxoError> {
// Extract properties using helper functions
let version: u32 = get_nested_field(bip32_key, "network.bip32.public")?;
let depth: u8 = get_field(bip32_key, "depth")?;
Expand All @@ -24,33 +24,32 @@ fn try_xpub_from_bip32_properties(bip32_key: &JsValue) -> Result<Xpub, WasmMinis
data.extend_from_slice(&public_key_bytes); // 33 bytes: public key

// Use the Xpub::decode method which properly handles network detection and constructs the Xpub
Xpub::decode(&data)
.map_err(|e| WasmMiniscriptError::new(&format!("Failed to decode xpub: {}", e)))
Xpub::decode(&data).map_err(|e| WasmUtxoError::new(&format!("Failed to decode xpub: {}", e)))
}

fn xpub_from_base58_method(bip32_key: &JsValue) -> Result<Xpub, WasmMiniscriptError> {
fn xpub_from_base58_method(bip32_key: &JsValue) -> Result<Xpub, WasmUtxoError> {
// Fallback: Call toBase58() method on BIP32Interface
let to_base58 = js_sys::Reflect::get(bip32_key, &JsValue::from_str("toBase58"))
.map_err(|_| WasmMiniscriptError::new("Failed to get 'toBase58' method"))?;
.map_err(|_| WasmUtxoError::new("Failed to get 'toBase58' method"))?;

if !to_base58.is_function() {
return Err(WasmMiniscriptError::new("'toBase58' is not a function"));
return Err(WasmUtxoError::new("'toBase58' is not a function"));
}

let to_base58_fn = js_sys::Function::from(to_base58);
let xpub_str = to_base58_fn
.call0(bip32_key)
.map_err(|_| WasmMiniscriptError::new("Failed to call 'toBase58'"))?;
.map_err(|_| WasmUtxoError::new("Failed to call 'toBase58'"))?;

let xpub_string = xpub_str
.as_string()
.ok_or_else(|| WasmMiniscriptError::new("'toBase58' did not return a string"))?;
.ok_or_else(|| WasmUtxoError::new("'toBase58' did not return a string"))?;

Xpub::from_str(&xpub_string)
.map_err(|e| WasmMiniscriptError::new(&format!("Failed to parse xpub: {}", e)))
.map_err(|e| WasmUtxoError::new(&format!("Failed to parse xpub: {}", e)))
}

pub fn xpub_from_bip32interface(bip32_key: &JsValue) -> Result<Xpub, WasmMiniscriptError> {
pub fn xpub_from_bip32interface(bip32_key: &JsValue) -> Result<Xpub, WasmUtxoError> {
// Try to construct from properties first, fall back to toBase58() if that fails
try_xpub_from_bip32_properties(bip32_key).or_else(|_| xpub_from_base58_method(bip32_key))
}
14 changes: 7 additions & 7 deletions packages/wasm-utxo/src/fixed_script_wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use wallet_scripts::*;
use wasm_bindgen::prelude::*;

use crate::address::networks::AddressFormat;
use crate::error::WasmMiniscriptError;
use crate::error::WasmUtxoError;
use crate::try_from_js_value::TryFromJsValue;
use crate::utxolib_compat::UtxolibNetwork;

Expand All @@ -28,10 +28,10 @@ impl FixedScriptWalletNamespace {
chain: u32,
index: u32,
network: JsValue,
) -> Result<Vec<u8>, WasmMiniscriptError> {
) -> Result<Vec<u8>, WasmUtxoError> {
let network = UtxolibNetwork::try_from_js_value(&network)?;
let chain = Chain::try_from(chain)
.map_err(|e| WasmMiniscriptError::new(&format!("Invalid chain: {}", e)))?;
.map_err(|e| WasmUtxoError::new(&format!("Invalid chain: {}", e)))?;

let wallet_keys = RootWalletKeys::from_jsvalue(&keys)?;
let scripts = WalletScripts::from_wallet_keys(
Expand All @@ -50,11 +50,11 @@ impl FixedScriptWalletNamespace {
index: u32,
network: JsValue,
address_format: Option<String>,
) -> Result<String, WasmMiniscriptError> {
) -> Result<String, WasmUtxoError> {
let network = UtxolibNetwork::try_from_js_value(&network)?;
let wallet_keys = RootWalletKeys::from_jsvalue(&keys)?;
let chain = Chain::try_from(chain)
.map_err(|e| WasmMiniscriptError::new(&format!("Invalid chain: {}", e)))?;
.map_err(|e| WasmUtxoError::new(&format!("Invalid chain: {}", e)))?;
let scripts = WalletScripts::from_wallet_keys(
&wallet_keys,
chain,
Expand All @@ -63,13 +63,13 @@ impl FixedScriptWalletNamespace {
)?;
let script = scripts.output_script();
let address_format = AddressFormat::from_optional_str(address_format.as_deref())
.map_err(|e| WasmMiniscriptError::new(&format!("Invalid address format: {}", e)))?;
.map_err(|e| WasmUtxoError::new(&format!("Invalid address format: {}", e)))?;
let address = crate::address::utxolib_compat::from_output_script_with_network(
&script,
&network,
address_format,
)
.map_err(|e| WasmMiniscriptError::new(&format!("Failed to generate address: {}", e)))?;
.map_err(|e| WasmUtxoError::new(&format!("Failed to generate address: {}", e)))?;
Ok(address.to_string())
}
}
Loading