Skip to content

Commit

Permalink
Merge pull request #27 from BitGo/BTC-1348.psbt.splitfiles
Browse files Browse the repository at this point in the history
refactor: split miniscript and descriptor into separate files
  • Loading branch information
OttoAllmendinger authored Aug 13, 2024
2 parents 5c8682b + 119332e commit 164c351
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 260 deletions.
108 changes: 108 additions & 0 deletions packages/wasm-miniscript/src/descriptor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use std::str::FromStr;
use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
use miniscript::bitcoin::ScriptBuf;
use miniscript::bitcoin::secp256k1::Secp256k1;
use miniscript::descriptor::KeyMap;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::{JsError, JsValue};
use crate::try_into_js_value::TryIntoJsValue;

enum WrapDescriptorEnum {
Derivable(Descriptor<DescriptorPublicKey>, KeyMap),
Definite(Descriptor<DefiniteDescriptorKey>),
String(Descriptor<String>),
}

#[wasm_bindgen]
pub struct WrapDescriptor(WrapDescriptorEnum);

#[wasm_bindgen]
impl WrapDescriptor {
pub fn node(&self) -> Result<JsValue, JsError> {
Ok(match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.try_to_js_value()?,
WrapDescriptorEnum::Definite(desc) => desc.try_to_js_value()?,
WrapDescriptorEnum::String(desc) => desc.try_to_js_value()?,
})
}

#[wasm_bindgen(js_name = toString)]
pub fn to_string(&self) -> String {
match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.to_string(),
WrapDescriptorEnum::Definite(desc) => desc.to_string(),
WrapDescriptorEnum::String(desc) => desc.to_string(),
}
}

#[wasm_bindgen(js_name = hasWildcard)]
pub fn has_wildcard(&self) -> bool {
match &self.0 {
WrapDescriptorEnum::Derivable(desc, _) => desc.has_wildcard(),
WrapDescriptorEnum::Definite(_) => false,
WrapDescriptorEnum::String(_) => false,
}
}

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

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

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

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

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

#[wasm_bindgen]
pub fn descriptor_from_string(descriptor: &str, pk_type: &str) -> Result<WrapDescriptor, JsError> {
match pk_type {
"derivable" => {
let secp = Secp256k1::new();
let (desc, keys) = Descriptor::parse_descriptor(&secp, descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::Derivable(desc, keys)))
}
"definite" => {
let desc = Descriptor::<DefiniteDescriptorKey>::from_str(descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc)))
}
"string" => {
let desc = Descriptor::<String>::from_str(descriptor)?;
Ok(WrapDescriptor(WrapDescriptorEnum::String(desc)))
}
_ => Err(JsError::new("Invalid descriptor type")),
}
}
36 changes: 36 additions & 0 deletions packages/wasm-miniscript/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use wasm_bindgen::JsValue;
use std::fmt;
use miniscript::bitcoin;

#[derive(Debug, Clone)]
enum WrapError {
Miniscript(String),
Bitcoin(String),
}

impl std::error::Error for WrapError {}

impl fmt::Display for WrapError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
WrapError::Miniscript(e) => write!(f, "Miniscript error: {}", e),
WrapError::Bitcoin(e) => write!(f, "Bitcoin error: {}", e),
}
}
}

impl From<miniscript::Error> for WrapError {
fn from(e: miniscript::Error) -> Self {
WrapError::Miniscript(e.to_string())
}
}

impl From<bitcoin::consensus::encode::Error> for WrapError {
fn from(e: bitcoin::consensus::encode::Error) -> Self {
WrapError::Bitcoin(e.to_string())
}
}

pub fn wrap_err<T, E: std::fmt::Debug>(r: Result<T, E>) -> Result<T, JsValue> {
r.map_err(|e| JsValue::from_str(&format!("{:?}", e)))
}
Loading

0 comments on commit 164c351

Please sign in to comment.