Ver código fonte

feat: js bindings

thesimplekid 10 meses atrás
pai
commit
7ea7e0bda0
44 arquivos alterados com 1954 adições e 12 exclusões
  1. 9 5
      Cargo.toml
  2. 23 0
      bindings/cdk-js/Cargo.toml
  3. 12 0
      bindings/cdk-js/src/error.rs
  4. 11 0
      bindings/cdk-js/src/lib.rs
  5. 24 0
      bindings/cdk-js/src/nuts/mod.rs
  6. 42 0
      bindings/cdk-js/src/nuts/nut00/blind_signature.rs
  7. 71 0
      bindings/cdk-js/src/nuts/nut00/blinded_message.rs
  8. 32 0
      bindings/cdk-js/src/nuts/nut00/currency_unit.rs
  9. 22 0
      bindings/cdk-js/src/nuts/nut00/mint_proofs.rs
  10. 17 0
      bindings/cdk-js/src/nuts/nut00/mod.rs
  11. 24 0
      bindings/cdk-js/src/nuts/nut00/payment_method.rs
  12. 40 0
      bindings/cdk-js/src/nuts/nut00/premint.rs
  13. 76 0
      bindings/cdk-js/src/nuts/nut00/proof.rs
  14. 22 0
      bindings/cdk-js/src/nuts/nut00/token.rs
  15. 28 0
      bindings/cdk-js/src/nuts/nut00/witness.rs
  16. 51 0
      bindings/cdk-js/src/nuts/nut01/keys.rs
  17. 7 0
      bindings/cdk-js/src/nuts/nut01/mod.rs
  18. 41 0
      bindings/cdk-js/src/nuts/nut01/public_key.rs
  19. 31 0
      bindings/cdk-js/src/nuts/nut01/secret_key.rs
  20. 42 0
      bindings/cdk-js/src/nuts/nut02/id.rs
  21. 117 0
      bindings/cdk-js/src/nuts/nut02/keyset.rs
  22. 4 0
      bindings/cdk-js/src/nuts/nut02/mod.rs
  23. 104 0
      bindings/cdk-js/src/nuts/nut03.rs
  24. 155 0
      bindings/cdk-js/src/nuts/nut04.rs
  25. 115 0
      bindings/cdk-js/src/nuts/nut05.rs
  26. 142 0
      bindings/cdk-js/src/nuts/nut06.rs
  27. 85 0
      bindings/cdk-js/src/nuts/nut07.rs
  28. 40 0
      bindings/cdk-js/src/nuts/nut09.rs
  29. 64 0
      bindings/cdk-js/src/nuts/nut10.rs
  30. 40 0
      bindings/cdk-js/src/nuts/nut11.rs
  31. 99 0
      bindings/cdk-js/src/nuts/nut12.rs
  32. 22 0
      bindings/cdk-js/src/nuts/nut14.rs
  33. 48 0
      bindings/cdk-js/src/types/amount.rs
  34. 22 0
      bindings/cdk-js/src/types/melt_quote.rs
  35. 22 0
      bindings/cdk-js/src/types/melted.rs
  36. 22 0
      bindings/cdk-js/src/types/mint_quote.rs
  37. 11 0
      bindings/cdk-js/src/types/mod.rs
  38. 44 0
      bindings/cdk-js/src/types/secret.rs
  39. 150 0
      bindings/cdk-js/src/wallet.rs
  40. 12 0
      bindings/uniffi-bindgen/Cargo.toml
  41. 3 0
      bindings/uniffi-bindgen/src/main.rs
  42. 7 4
      crates/cdk/src/nuts/mod.rs
  43. 0 2
      crates/cdk/src/wallet.rs
  44. 1 1
      flake.nix

+ 9 - 5
Cargo.toml

@@ -1,5 +1,7 @@
 [workspace]
 members = [
+    "bindings/cdk-js",
+    "bindings/uniffi-bindgen",
     "crates/cdk",
     "crates/cdk-redb",
     "crates/cdk-rexie",
@@ -22,13 +24,15 @@ license-file = "LICENSE"
 keywords = ["bitcoin", "e-cash", "cashu"]
 
 [workspace.dependencies]
-tokio = { version = "1.32", default-features = false }
-cdk = { path = "./crates/cdk", default-features = false }
-thiserror = "1.0.50"
 async-trait = "0.1.74"
+cdk = { path = "./crates/cdk", default-features = false }
+cdk-rexie = { path = "./crates/cdk-rexie", default-features = false }
+tokio = { version = "1.32", default-features = false }
+thiserror = "1"
 tracing = { version = "0.1", default-features = false }
-serde = { version = "1.0.160", default-features = false, features = ["derive"]}
-serde_json = "1.0.96"
+serde = { version = "1", default-features = false, features = ["derive"] }
+serde_json = "1"
+uniffi = { version = "0.27.1", default-features = false }
 
 [profile]
 

+ 23 - 0
bindings/cdk-js/Cargo.toml

@@ -0,0 +1,23 @@
+[package]
+name = "cdk-js"
+version = "0.1.0"
+edition = "2021"
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[lib]
+crate-type = ["lib", "cdylib"]
+
+[dependencies]
+cdk = { workspace = true, features = ["wallet"] }
+cdk-rexie = { workspace = true, features = ["wallet"] }
+console_error_panic_hook = "0.1"
+js-sys = "0.3"
+serde-wasm-bindgen = "0.6"
+serde_json.workspace = true
+serde.workspace = true
+wasm-bindgen = { version = "0.2.92", features = ["serde-serialize"] }
+wasm-bindgen-futures = "0.4.41"

+ 12 - 0
bindings/cdk-js/src/error.rs

@@ -0,0 +1,12 @@
+use wasm_bindgen::JsValue;
+
+pub type Result<T, E = JsValue> = std::result::Result<T, E>;
+
+/// Helper to replace the `E` to `Error` to `napi::Error` conversion.
+#[inline]
+pub fn into_err<E>(error: E) -> JsValue
+where
+    E: std::fmt::Display,
+{
+    JsValue::from_str(&error.to_string())
+}

+ 11 - 0
bindings/cdk-js/src/lib.rs

@@ -0,0 +1,11 @@
+use wasm_bindgen::prelude::*;
+
+pub mod error;
+pub mod nuts;
+pub mod types;
+pub mod wallet;
+
+#[wasm_bindgen(start)]
+pub fn start() {
+    console_error_panic_hook::set_once();
+}

+ 24 - 0
bindings/cdk-js/src/nuts/mod.rs

@@ -0,0 +1,24 @@
+pub mod nut00;
+pub mod nut01;
+pub mod nut02;
+pub mod nut03;
+pub mod nut04;
+pub mod nut05;
+pub mod nut06;
+pub mod nut07;
+pub mod nut09;
+pub mod nut10;
+pub mod nut11;
+pub mod nut12;
+pub mod nut14;
+
+pub use nut00::*;
+pub use nut01::{JsKeys, JsPublicKey, JsSecretKey};
+pub use nut02::JsId;
+pub use nut03::{JsSwapRequest, JsSwapResponse};
+pub use nut06::{JsMintInfo, JsMintVersion};
+pub use nut07::*;
+pub use nut09::{JsRestoreRequest, JsRestoreResponse};
+pub use nut11::JsP2PKWitness;
+pub use nut12::{JsBlindSignatureDleq, JsProofDleq};
+pub use nut14::JsHTLCWitness;

+ 42 - 0
bindings/cdk-js/src/nuts/nut00/blind_signature.rs

@@ -0,0 +1,42 @@
+use std::ops::Deref;
+
+use cdk::nuts::BlindSignature;
+use wasm_bindgen::prelude::*;
+
+use crate::nuts::nut01::JsPublicKey;
+use crate::nuts::nut02::JsId;
+use crate::nuts::JsBlindSignatureDleq;
+use crate::types::JsAmount;
+
+#[wasm_bindgen(js_name = BlindSignature)]
+pub struct JsBlindSignature {
+    inner: BlindSignature,
+}
+
+impl Deref for JsBlindSignature {
+    type Target = BlindSignature;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+#[wasm_bindgen(js_class = BlindSignature)]
+impl JsBlindSignature {
+    #[allow(clippy::new_without_default)]
+    #[wasm_bindgen(constructor)]
+    pub fn new(
+        keyset_id: JsId,
+        amount: JsAmount,
+        c: JsPublicKey,
+        dleq: Option<JsBlindSignatureDleq>,
+    ) -> Self {
+        Self {
+            inner: BlindSignature {
+                keyset_id: *keyset_id.deref(),
+                amount: *amount.deref(),
+                c: c.deref().clone(),
+                dleq: dleq.map(|b| b.deref().clone()),
+            },
+        }
+    }
+}

+ 71 - 0
bindings/cdk-js/src/nuts/nut00/blinded_message.rs

@@ -0,0 +1,71 @@
+use std::ops::Deref;
+
+use cdk::nuts::BlindedMessage;
+use wasm_bindgen::prelude::*;
+
+use super::JsWitness;
+use crate::nuts::{JsId, JsPublicKey};
+use crate::types::JsAmount;
+
+#[wasm_bindgen(js_name = BlindedMessage)]
+pub struct JsBlindedMessage {
+    inner: BlindedMessage,
+}
+
+impl Deref for JsBlindedMessage {
+    type Target = BlindedMessage;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<BlindedMessage> for JsBlindedMessage {
+    fn from(inner: BlindedMessage) -> JsBlindedMessage {
+        JsBlindedMessage { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = BlindedMessage)]
+impl JsBlindedMessage {
+    #[allow(clippy::new_without_default)]
+    #[wasm_bindgen(constructor)]
+    pub fn new(
+        keyset_id: JsId,
+        amount: JsAmount,
+        blinded_secret: JsPublicKey,
+        witness: Option<JsWitness>,
+    ) -> Self {
+        Self {
+            inner: BlindedMessage {
+                keyset_id: *keyset_id.deref(),
+                amount: *amount.deref(),
+                blinded_secret: blinded_secret.deref().clone(),
+                witness: witness.map(|w| w.deref().clone()),
+            },
+        }
+    }
+
+    /// Keyset Id
+    #[wasm_bindgen(getter)]
+    pub fn keyset_id(&self) -> JsId {
+        self.keyset_id.into()
+    }
+
+    /// Amount
+    #[wasm_bindgen(getter)]
+    pub fn amount(&self) -> JsAmount {
+        self.inner.amount.into()
+    }
+
+    /// Blinded Secret
+    #[wasm_bindgen(getter)]
+    pub fn blinded_secret(&self) -> JsPublicKey {
+        self.inner.blinded_secret.clone().into()
+    }
+
+    /// Witness
+    #[wasm_bindgen(getter)]
+    pub fn witness(&self) -> Option<JsWitness> {
+        self.inner.witness.clone().map(|w| w.into())
+    }
+}

+ 32 - 0
bindings/cdk-js/src/nuts/nut00/currency_unit.rs

@@ -0,0 +1,32 @@
+use cdk::nuts::CurrencyUnit;
+use wasm_bindgen::prelude::*;
+
+// use crate::nuts::{JsHTLCWitness, JsP2PKWitness};
+
+#[wasm_bindgen(js_name = CurrencyUnit)]
+pub enum JsCurrencyUnit {
+    Sat,
+    Msat,
+    Usd,
+}
+
+impl From<CurrencyUnit> for JsCurrencyUnit {
+    fn from(inner: CurrencyUnit) -> JsCurrencyUnit {
+        match inner {
+            CurrencyUnit::Sat => JsCurrencyUnit::Sat,
+            CurrencyUnit::Msat => JsCurrencyUnit::Msat,
+            CurrencyUnit::Usd => JsCurrencyUnit::Usd,
+            CurrencyUnit::Custom(_) => todo!(),
+        }
+    }
+}
+
+impl From<JsCurrencyUnit> for CurrencyUnit {
+    fn from(inner: JsCurrencyUnit) -> CurrencyUnit {
+        match inner {
+            JsCurrencyUnit::Sat => CurrencyUnit::Sat,
+            JsCurrencyUnit::Msat => CurrencyUnit::Msat,
+            JsCurrencyUnit::Usd => CurrencyUnit::Usd,
+        }
+    }
+}

+ 22 - 0
bindings/cdk-js/src/nuts/nut00/mint_proofs.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::nuts::MintProofs;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = MintProofs)]
+pub struct JsMintProofs {
+    inner: MintProofs,
+}
+
+impl Deref for JsMintProofs {
+    type Target = MintProofs;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintProofs> for JsMintProofs {
+    fn from(inner: MintProofs) -> JsMintProofs {
+        JsMintProofs { inner }
+    }
+}

+ 17 - 0
bindings/cdk-js/src/nuts/nut00/mod.rs

@@ -0,0 +1,17 @@
+pub mod blind_signature;
+pub mod blinded_message;
+pub mod currency_unit;
+pub mod mint_proofs;
+pub mod payment_method;
+pub mod premint;
+pub mod proof;
+pub mod token;
+pub mod witness;
+
+pub use blinded_message::JsBlindedMessage;
+pub use currency_unit::JsCurrencyUnit;
+pub use payment_method::JsPaymentMethod;
+pub use premint::{JsPreMint, JsPreMintSecrets};
+pub use proof::JsProof;
+pub use token::JsToken;
+pub use witness::JsWitness;

+ 24 - 0
bindings/cdk-js/src/nuts/nut00/payment_method.rs

@@ -0,0 +1,24 @@
+use cdk::nuts::PaymentMethod;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = PaymentMethod)]
+pub enum JsPaymentMethod {
+    Bolt11,
+}
+
+impl From<PaymentMethod> for JsPaymentMethod {
+    fn from(inner: PaymentMethod) -> JsPaymentMethod {
+        match inner {
+            PaymentMethod::Bolt11 => JsPaymentMethod::Bolt11,
+            PaymentMethod::Custom(_) => todo!(),
+        }
+    }
+}
+
+impl From<JsPaymentMethod> for PaymentMethod {
+    fn from(inner: JsPaymentMethod) -> PaymentMethod {
+        match inner {
+            JsPaymentMethod::Bolt11 => PaymentMethod::Bolt11,
+        }
+    }
+}

+ 40 - 0
bindings/cdk-js/src/nuts/nut00/premint.rs

@@ -0,0 +1,40 @@
+use std::ops::Deref;
+
+use cdk::nuts::{PreMint, PreMintSecrets};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = PreMint)]
+pub struct JsPreMint {
+    inner: PreMint,
+}
+
+impl Deref for JsPreMint {
+    type Target = PreMint;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<PreMint> for JsPreMint {
+    fn from(inner: PreMint) -> JsPreMint {
+        JsPreMint { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = PreMintSecrets)]
+pub struct JsPreMintSecrets {
+    inner: PreMintSecrets,
+}
+
+impl Deref for JsPreMintSecrets {
+    type Target = PreMintSecrets;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<PreMintSecrets> for JsPreMintSecrets {
+    fn from(inner: PreMintSecrets) -> JsPreMintSecrets {
+        JsPreMintSecrets { inner }
+    }
+}

+ 76 - 0
bindings/cdk-js/src/nuts/nut00/proof.rs

@@ -0,0 +1,76 @@
+use std::ops::Deref;
+
+use cdk::nuts::Proof;
+use wasm_bindgen::prelude::*;
+
+use super::JsWitness;
+use crate::nuts::nut01::JsPublicKey;
+use crate::nuts::nut02::JsId;
+use crate::nuts::nut12::JsProofDleq;
+use crate::types::{JsAmount, JsSecret};
+
+#[wasm_bindgen(js_name = Proof)]
+pub struct JsProof {
+    inner: Proof,
+}
+
+impl Deref for JsProof {
+    type Target = Proof;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Proof> for JsProof {
+    fn from(inner: Proof) -> JsProof {
+        JsProof { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = Proof)]
+impl JsProof {
+    #[wasm_bindgen(constructor)]
+    pub fn new(
+        amount: JsAmount,
+        secret: JsSecret,
+        c: JsPublicKey,
+        keyset_id: JsId,
+        witness: Option<JsWitness>,
+        dleq: Option<JsProofDleq>,
+    ) -> Self {
+        Self {
+            inner: Proof {
+                amount: *amount.deref(),
+                secret: secret.deref().clone(),
+                c: c.deref().clone(),
+                keyset_id: *keyset_id.deref(),
+                witness: witness.map(|w| w.deref().clone()),
+                dleq: dleq.map(|d| d.deref().clone()),
+            },
+        }
+    }
+
+    /// Amount
+    #[wasm_bindgen(getter)]
+    pub fn amount(&self) -> JsAmount {
+        self.inner.amount.into()
+    }
+
+    /// Secret
+    #[wasm_bindgen(getter)]
+    pub fn secret(&self) -> JsSecret {
+        self.inner.secret.clone().into()
+    }
+
+    /// C
+    #[wasm_bindgen(getter)]
+    pub fn c(&self) -> JsPublicKey {
+        self.inner.c.clone().into()
+    }
+
+    /// Keyset Id
+    #[wasm_bindgen(getter)]
+    pub fn keyset_id(&self) -> JsId {
+        self.inner.keyset_id.into()
+    }
+}

+ 22 - 0
bindings/cdk-js/src/nuts/nut00/token.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::nuts::Token;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = Token)]
+pub struct JsToken {
+    inner: Token,
+}
+
+impl Deref for JsToken {
+    type Target = Token;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Token> for JsToken {
+    fn from(inner: Token) -> JsToken {
+        JsToken { inner }
+    }
+}

+ 28 - 0
bindings/cdk-js/src/nuts/nut00/witness.rs

@@ -0,0 +1,28 @@
+use std::ops::Deref;
+
+use cdk::nuts::Witness;
+use wasm_bindgen::prelude::*;
+
+// use crate::nuts::{JsHTLCWitness, JsP2PKWitness};
+
+#[wasm_bindgen(js_name = Witness)]
+pub enum JsWitness {
+    JsHTLCWitness,
+    JsP2PKWitness,
+}
+
+impl Deref for JsWitness {
+    type Target = Witness;
+    fn deref(&self) -> &Self::Target {
+        todo!()
+    }
+}
+
+impl From<Witness> for JsWitness {
+    fn from(inner: Witness) -> JsWitness {
+        match inner {
+            Witness::P2PKWitness(_) => JsWitness::JsP2PKWitness,
+            Witness::HTLCWitness(_) => JsWitness::JsHTLCWitness,
+        }
+    }
+}

+ 51 - 0
bindings/cdk-js/src/nuts/nut01/keys.rs

@@ -0,0 +1,51 @@
+use std::ops::Deref;
+
+use cdk::nuts::nut01::Keys;
+use wasm_bindgen::prelude::*;
+
+use super::JsPublicKey;
+use crate::error::{into_err, Result};
+use crate::types::JsAmount;
+
+#[wasm_bindgen(js_name = Keys)]
+pub struct JsKeys {
+    inner: Keys,
+}
+
+impl Deref for JsKeys {
+    type Target = Keys;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Keys> for JsKeys {
+    fn from(inner: Keys) -> JsKeys {
+        JsKeys { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = Keys)]
+impl JsKeys {
+    /// From Hex
+    #[wasm_bindgen(constructor)]
+    pub fn new(keys: JsValue) -> Result<JsKeys> {
+        let keys = serde_wasm_bindgen::from_value(keys).map_err(into_err)?;
+
+        Ok(JsKeys {
+            inner: Keys::new(keys),
+        })
+    }
+
+    /// Keys
+    #[wasm_bindgen(js_name = keys)]
+    pub fn keys(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.keys()).map_err(into_err)
+    }
+
+    /// Amount Key
+    #[wasm_bindgen(js_name = amountKey)]
+    pub fn amount_key(&self, amount: JsAmount) -> Option<JsPublicKey> {
+        self.inner.amount_key(*amount.deref()).map(|k| k.into())
+    }
+}

+ 7 - 0
bindings/cdk-js/src/nuts/nut01/mod.rs

@@ -0,0 +1,7 @@
+pub mod keys;
+pub mod public_key;
+pub mod secret_key;
+
+pub use keys::JsKeys;
+pub use public_key::JsPublicKey;
+pub use secret_key::JsSecretKey;

+ 41 - 0
bindings/cdk-js/src/nuts/nut01/public_key.rs

@@ -0,0 +1,41 @@
+use std::ops::Deref;
+
+use cdk::nuts::nut01::PublicKey;
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+
+#[wasm_bindgen(js_name = PublicKey)]
+pub struct JsPublicKey {
+    inner: PublicKey,
+}
+
+impl Deref for JsPublicKey {
+    type Target = PublicKey;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<PublicKey> for JsPublicKey {
+    fn from(inner: PublicKey) -> JsPublicKey {
+        JsPublicKey { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = PublicKey)]
+impl JsPublicKey {
+    /// From Hex
+    #[wasm_bindgen(js_name = fromHex)]
+    pub fn from_hex(hex: String) -> Result<JsPublicKey> {
+        Ok(Self {
+            inner: PublicKey::from_hex(hex).map_err(into_err)?,
+        })
+    }
+
+    /// To Hex
+    #[wasm_bindgen(js_name = toHex)]
+    pub fn to_hex(&self) -> String {
+        self.inner.to_hex()
+    }
+}

+ 31 - 0
bindings/cdk-js/src/nuts/nut01/secret_key.rs

@@ -0,0 +1,31 @@
+use std::ops::Deref;
+
+use cdk::nuts::nut01::SecretKey;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = SecretKey)]
+pub struct JsSecretKey {
+    inner: SecretKey,
+}
+
+impl Deref for JsSecretKey {
+    type Target = SecretKey;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SecretKey> for JsSecretKey {
+    fn from(inner: SecretKey) -> JsSecretKey {
+        JsSecretKey { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = SecretKey)]
+impl JsSecretKey {
+    /// To Hex
+    #[wasm_bindgen(js_name = toHex)]
+    pub fn to_hex(&self) -> String {
+        self.inner.to_secret_hex()
+    }
+}

+ 42 - 0
bindings/cdk-js/src/nuts/nut02/id.rs

@@ -0,0 +1,42 @@
+use std::ops::Deref;
+use std::str::FromStr;
+
+use cdk::nuts::Id;
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+
+#[wasm_bindgen(js_name = Id)]
+pub struct JsId {
+    inner: Id,
+}
+
+impl Deref for JsId {
+    type Target = Id;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Id> for JsId {
+    fn from(inner: Id) -> JsId {
+        JsId { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = Id)]
+impl JsId {
+    /// Try From Base 64 String
+    #[wasm_bindgen(js_name = tryFromBase64)]
+    pub fn try_from_base64(id: String) -> Result<JsId> {
+        Ok(JsId {
+            inner: Id::from_str(&id).map_err(into_err)?,
+        })
+    }
+
+    /// As String
+    #[wasm_bindgen(js_name = asString)]
+    pub fn as_string(&self) -> String {
+        self.inner.to_string()
+    }
+}

+ 117 - 0
bindings/cdk-js/src/nuts/nut02/keyset.rs

@@ -0,0 +1,117 @@
+use std::ops::Deref;
+
+use cdk::nuts::{CurrencyUnit, KeySet, KeysResponse, KeysetResponse};
+use wasm_bindgen::prelude::*;
+
+use super::JsId;
+use crate::error::{into_err, Result};
+use crate::nuts::JsKeys;
+
+#[wasm_bindgen(js_name = KeySet)]
+pub struct JsKeySet {
+    inner: KeySet,
+}
+
+impl Deref for JsKeySet {
+    type Target = KeySet;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<KeySet> for JsKeySet {
+    fn from(inner: KeySet) -> JsKeySet {
+        JsKeySet { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = KeyPair)]
+impl JsKeySet {
+    /// From Hex
+    #[wasm_bindgen(constructor)]
+    pub fn new(id: JsId, unit: String, keys: JsKeys) -> JsKeySet {
+        Self {
+            inner: KeySet {
+                id: *id.deref(),
+                unit: CurrencyUnit::from(&unit),
+                keys: keys.deref().clone(),
+            },
+        }
+    }
+
+    #[wasm_bindgen(getter)]
+    pub fn id(&self) -> JsId {
+        self.inner.id.into()
+    }
+
+    #[wasm_bindgen(getter)]
+    pub fn keys(&self) -> JsKeys {
+        self.inner.keys.clone().into()
+    }
+}
+
+#[wasm_bindgen(js_name = KeySetsResponse)]
+pub struct JsKeySetsResponse {
+    inner: KeysetResponse,
+}
+
+impl Deref for JsKeySetsResponse {
+    type Target = KeysetResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<KeysetResponse> for JsKeySetsResponse {
+    fn from(inner: KeysetResponse) -> JsKeySetsResponse {
+        JsKeySetsResponse { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = KeySetsResponse)]
+impl JsKeySetsResponse {
+    #[wasm_bindgen(constructor)]
+    pub fn new(keysets: JsValue) -> Result<JsKeySetsResponse> {
+        let response = serde_wasm_bindgen::from_value(keysets).map_err(into_err)?;
+        Ok(Self { inner: response })
+    }
+
+    /// Get KeySets
+    #[wasm_bindgen(getter)]
+    pub fn keys(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.keysets).map_err(into_err)
+    }
+}
+
+#[wasm_bindgen(js_name = KeysResponse)]
+pub struct JsKeysResponse {
+    inner: KeysResponse,
+}
+
+impl Deref for JsKeysResponse {
+    type Target = KeysResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<KeysResponse> for JsKeysResponse {
+    fn from(inner: KeysResponse) -> JsKeysResponse {
+        JsKeysResponse { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = KeysResponse)]
+impl JsKeysResponse {
+    #[wasm_bindgen(constructor)]
+    pub fn new(keysets: JsValue) -> Result<JsKeysResponse> {
+        let response = serde_wasm_bindgen::from_value(keysets).map_err(into_err)?;
+        Ok(Self { inner: response })
+    }
+
+    /// Get Keys
+    #[wasm_bindgen(getter)]
+    pub fn keysets(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.keysets).map_err(into_err)
+    }
+}

+ 4 - 0
bindings/cdk-js/src/nuts/nut02/mod.rs

@@ -0,0 +1,4 @@
+pub mod id;
+pub mod keyset;
+
+pub use id::JsId;

+ 104 - 0
bindings/cdk-js/src/nuts/nut03.rs

@@ -0,0 +1,104 @@
+use std::ops::Deref;
+
+use cdk::nuts::{SwapRequest, SwapResponse};
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+use crate::types::JsAmount;
+
+#[wasm_bindgen(js_name = SwapRequest)]
+pub struct JsSwapRequest {
+    inner: SwapRequest,
+}
+
+impl Deref for JsSwapRequest {
+    type Target = SwapRequest;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SwapRequest> for JsSwapRequest {
+    fn from(inner: SwapRequest) -> JsSwapRequest {
+        JsSwapRequest { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = SwapRequest)]
+impl JsSwapRequest {
+    #[wasm_bindgen(constructor)]
+    pub fn new(inputs: JsValue, outputs: JsValue) -> Result<JsSwapRequest> {
+        let inputs = serde_wasm_bindgen::from_value(inputs).map_err(into_err)?;
+        let outputs = serde_wasm_bindgen::from_value(outputs).map_err(into_err)?;
+
+        Ok(JsSwapRequest {
+            inner: SwapRequest { inputs, outputs },
+        })
+    }
+
+    /// Get Proofs
+    #[wasm_bindgen(getter)]
+    pub fn proofs(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.inputs).map_err(into_err)
+    }
+
+    /// Get Outputs
+    #[wasm_bindgen(getter)]
+    pub fn outputs(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.outputs).map_err(into_err)
+    }
+
+    /// Proofs Amount
+    #[wasm_bindgen(js_name = proofsAmount)]
+    pub fn proofs_amount(&self) -> JsAmount {
+        self.inner.input_amount().into()
+    }
+
+    /// Output Amount
+    #[wasm_bindgen(js_name = outputAmount)]
+    pub fn output_amount(&self) -> JsAmount {
+        self.inner.output_amount().into()
+    }
+}
+
+#[wasm_bindgen(js_name = SplitResponse)]
+pub struct JsSwapResponse {
+    inner: SwapResponse,
+}
+
+impl Deref for JsSwapResponse {
+    type Target = SwapResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SwapResponse> for JsSwapResponse {
+    fn from(inner: SwapResponse) -> JsSwapResponse {
+        JsSwapResponse { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = SplitResponse)]
+impl JsSwapResponse {
+    #[wasm_bindgen(constructor)]
+    pub fn new(signatures: JsValue) -> Result<JsSwapResponse> {
+        let signatures = serde_wasm_bindgen::from_value(signatures).map_err(into_err)?;
+
+        Ok(JsSwapResponse {
+            inner: SwapResponse { signatures },
+        })
+    }
+
+    /// Get Promises
+    #[wasm_bindgen(getter)]
+    pub fn signatures(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.signatures).map_err(into_err)
+    }
+
+    /// Promises Amount
+    #[wasm_bindgen(js_name = promisesAmount)]
+    pub fn promises_amount(&self) -> JsAmount {
+        self.inner.promises_amount().into()
+    }
+}

+ 155 - 0
bindings/cdk-js/src/nuts/nut04.rs

@@ -0,0 +1,155 @@
+use std::ops::Deref;
+
+use cdk::nuts::nut04::{MintBolt11Request, MintBolt11Response, MintMethodSettings, Settings};
+use cdk::nuts::{MintQuoteBolt11Request, MintQuoteBolt11Response};
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+use crate::types::JsAmount;
+
+#[wasm_bindgen(js_name = MintQuoteBolt11Request)]
+pub struct JsMintQuoteBolt11Request {
+    inner: MintQuoteBolt11Request,
+}
+
+impl Deref for JsMintQuoteBolt11Request {
+    type Target = MintQuoteBolt11Request;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintQuoteBolt11Request> for JsMintQuoteBolt11Request {
+    fn from(inner: MintQuoteBolt11Request) -> JsMintQuoteBolt11Request {
+        JsMintQuoteBolt11Request { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = MintQuoteBolt11Response)]
+pub struct JsMintQuoteBolt11Response {
+    inner: MintQuoteBolt11Response,
+}
+
+impl Deref for JsMintQuoteBolt11Response {
+    type Target = MintQuoteBolt11Response;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintQuoteBolt11Response> for JsMintQuoteBolt11Response {
+    fn from(inner: MintQuoteBolt11Response) -> JsMintQuoteBolt11Response {
+        JsMintQuoteBolt11Response { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = MintBolt11Request)]
+pub struct JsMintBolt11Request {
+    inner: MintBolt11Request,
+}
+
+impl Deref for JsMintBolt11Request {
+    type Target = MintBolt11Request;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintBolt11Request> for JsMintBolt11Request {
+    fn from(inner: MintBolt11Request) -> JsMintBolt11Request {
+        JsMintBolt11Request { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = MintBolt11Request)]
+impl JsMintBolt11Request {
+    /// Try From Base 64 String
+    #[wasm_bindgen(constructor)]
+    pub fn new(quote: String, outputs: JsValue) -> Result<JsMintBolt11Request> {
+        let outputs = serde_wasm_bindgen::from_value(outputs).map_err(into_err)?;
+        Ok(JsMintBolt11Request {
+            inner: MintBolt11Request { quote, outputs },
+        })
+    }
+
+    #[wasm_bindgen(getter)]
+    pub fn outputs(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.outputs).map_err(into_err)
+    }
+
+    #[wasm_bindgen(js_name = totalAmount)]
+    pub fn totoal_amount(&self) -> JsAmount {
+        self.inner.total_amount().into()
+    }
+}
+
+#[wasm_bindgen(js_name = PostMintResponse)]
+pub struct JsMintBolt11Response {
+    inner: MintBolt11Response,
+}
+
+impl Deref for JsMintBolt11Response {
+    type Target = MintBolt11Response;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintBolt11Response> for JsMintBolt11Response {
+    fn from(inner: MintBolt11Response) -> JsMintBolt11Response {
+        JsMintBolt11Response { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = PostMintResponse)]
+impl JsMintBolt11Response {
+    /// Try From Base 64 String
+    #[wasm_bindgen(constructor)]
+    pub fn new(signatures: JsValue) -> Result<JsMintBolt11Response> {
+        let signatures = serde_wasm_bindgen::from_value(signatures).map_err(into_err)?;
+        Ok(JsMintBolt11Response {
+            inner: MintBolt11Response { signatures },
+        })
+    }
+
+    #[wasm_bindgen(getter)]
+    pub fn signatures(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.signatures).map_err(into_err)
+    }
+}
+
+#[wasm_bindgen(js_name = MintMethodSettings)]
+pub struct JsMintMethodSettings {
+    inner: MintMethodSettings,
+}
+
+impl Deref for JsMintMethodSettings {
+    type Target = MintMethodSettings;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintMethodSettings> for JsMintMethodSettings {
+    fn from(inner: MintMethodSettings) -> JsMintMethodSettings {
+        JsMintMethodSettings { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = Settings)]
+pub struct JsSettings {
+    inner: Settings,
+}
+
+impl Deref for JsSettings {
+    type Target = Settings;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Settings> for JsSettings {
+    fn from(inner: Settings) -> JsSettings {
+        JsSettings { inner }
+    }
+}

+ 115 - 0
bindings/cdk-js/src/nuts/nut05.rs

@@ -0,0 +1,115 @@
+use std::ops::Deref;
+
+use cdk::nuts::{
+    MeltBolt11Request, MeltBolt11Response, MeltMethodSettings, MeltQuoteBolt11Request,
+    MeltQuoteBolt11Response, NUT05Settings,
+};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = MeltQuoteBolt11Request)]
+pub struct JsMeltQuoteBolt11Request {
+    inner: MeltQuoteBolt11Request,
+}
+
+impl Deref for JsMeltQuoteBolt11Request {
+    type Target = MeltQuoteBolt11Request;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltQuoteBolt11Request> for JsMeltQuoteBolt11Request {
+    fn from(inner: MeltQuoteBolt11Request) -> JsMeltQuoteBolt11Request {
+        JsMeltQuoteBolt11Request { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = MeltQuoteBolt11Response)]
+pub struct JsMeltQuoteBolt11Response {
+    inner: MeltQuoteBolt11Response,
+}
+
+impl Deref for JsMeltQuoteBolt11Response {
+    type Target = MeltQuoteBolt11Response;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltQuoteBolt11Response> for JsMeltQuoteBolt11Response {
+    fn from(inner: MeltQuoteBolt11Response) -> JsMeltQuoteBolt11Response {
+        JsMeltQuoteBolt11Response { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = MintBolt11Request)]
+pub struct JsMeltBolt11Request {
+    inner: MeltBolt11Request,
+}
+
+impl Deref for JsMeltBolt11Request {
+    type Target = MeltBolt11Request;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltBolt11Request> for JsMeltBolt11Request {
+    fn from(inner: MeltBolt11Request) -> JsMeltBolt11Request {
+        JsMeltBolt11Request { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = PostMeltResponse)]
+pub struct JsMeltBolt11Response {
+    inner: MeltBolt11Response,
+}
+
+impl Deref for JsMeltBolt11Response {
+    type Target = MeltBolt11Response;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltBolt11Response> for JsMeltBolt11Response {
+    fn from(inner: MeltBolt11Response) -> JsMeltBolt11Response {
+        JsMeltBolt11Response { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = MeltMethodSettings)]
+pub struct JsMeltMethodSettings {
+    inner: MeltMethodSettings,
+}
+
+impl Deref for JsMeltMethodSettings {
+    type Target = MeltMethodSettings;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltMethodSettings> for JsMeltMethodSettings {
+    fn from(inner: MeltMethodSettings) -> JsMeltMethodSettings {
+        JsMeltMethodSettings { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = Settings)]
+pub struct JsSettings {
+    inner: NUT05Settings,
+}
+
+impl Deref for JsSettings {
+    type Target = NUT05Settings;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<NUT05Settings> for JsSettings {
+    fn from(inner: NUT05Settings) -> JsSettings {
+        JsSettings { inner }
+    }
+}

+ 142 - 0
bindings/cdk-js/src/nuts/nut06.rs

@@ -0,0 +1,142 @@
+use std::ops::Deref;
+
+use cdk::nuts::nut06::{MintInfo, MintVersion};
+use wasm_bindgen::prelude::*;
+
+use super::nut01::JsPublicKey;
+use crate::error::{into_err, Result};
+
+#[wasm_bindgen(js_name = MintVersion)]
+pub struct JsMintVersion {
+    inner: MintVersion,
+}
+
+impl Deref for JsMintVersion {
+    type Target = MintVersion;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintVersion> for JsMintVersion {
+    fn from(inner: MintVersion) -> JsMintVersion {
+        JsMintVersion { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = MintVersion)]
+impl JsMintVersion {
+    #[wasm_bindgen(constructor)]
+    pub fn new(name: String, version: String) -> Result<JsMintVersion> {
+        Ok(JsMintVersion {
+            inner: MintVersion { name, version },
+        })
+    }
+
+    /// Get Name
+    #[wasm_bindgen(getter)]
+    pub fn name(&self) -> String {
+        self.inner.name.clone()
+    }
+
+    /// Get Version
+    #[wasm_bindgen(getter)]
+    pub fn version(&self) -> String {
+        self.inner.version.clone()
+    }
+}
+
+#[wasm_bindgen(js_name = MintInfo)]
+pub struct JsMintInfo {
+    inner: MintInfo,
+}
+
+impl Deref for JsMintInfo {
+    type Target = MintInfo;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintInfo> for JsMintInfo {
+    fn from(inner: MintInfo) -> JsMintInfo {
+        JsMintInfo { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = MintInfo)]
+impl JsMintInfo {
+    #[wasm_bindgen(constructor)]
+    #[allow(clippy::too_many_arguments)]
+    pub fn new(
+        name: Option<String>,
+        pubkey: Option<JsPublicKey>,
+        version: Option<JsMintVersion>,
+        description: Option<String>,
+        description_long: Option<String>,
+        contact: JsValue,
+        nuts: JsValue,
+        motd: Option<String>,
+    ) -> Result<JsMintInfo> {
+        Ok(JsMintInfo {
+            inner: MintInfo {
+                name,
+                pubkey: pubkey.map(|p| p.deref().clone()),
+                version: version.map(|v| v.deref().clone()),
+                description,
+                description_long,
+                contact: serde_wasm_bindgen::from_value(contact).map_err(into_err)?,
+                nuts: serde_wasm_bindgen::from_value(nuts).map_err(into_err)?,
+                motd,
+            },
+        })
+    }
+
+    /// Get Name
+    #[wasm_bindgen(getter)]
+    pub fn name(&self) -> Option<String> {
+        self.inner.name.clone()
+    }
+
+    /// Get Pubkey
+    #[wasm_bindgen(getter)]
+    pub fn pubkey(&self) -> Option<JsPublicKey> {
+        self.inner.pubkey.clone().map(|p| p.into())
+    }
+
+    /// Get Version
+    #[wasm_bindgen(getter)]
+    pub fn version(&self) -> Option<JsMintVersion> {
+        self.inner.version.clone().map(|v| v.into())
+    }
+
+    /// Get description
+    #[wasm_bindgen(getter)]
+    pub fn description(&self) -> Option<String> {
+        self.inner.description.clone()
+    }
+
+    /// Get description long
+    #[wasm_bindgen(getter)]
+    pub fn description_long(&self) -> Option<String> {
+        self.inner.description_long.clone()
+    }
+
+    /// Get contact
+    #[wasm_bindgen(getter)]
+    pub fn contact(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.contact).map_err(into_err)
+    }
+
+    /// Get supported nuts
+    #[wasm_bindgen(getter)]
+    pub fn nuts(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.nuts).map_err(into_err)
+    }
+
+    /// Get motd
+    #[wasm_bindgen(getter)]
+    pub fn motd(&self) -> Option<String> {
+        self.inner.motd.clone()
+    }
+}

+ 85 - 0
bindings/cdk-js/src/nuts/nut07.rs

@@ -0,0 +1,85 @@
+use std::ops::Deref;
+
+use cdk::nuts::{CheckStateRequest, CheckStateResponse, ProofState, State};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = State)]
+pub enum JsState {
+    Spent,
+    Unspent,
+    Pending,
+}
+
+impl From<State> for JsState {
+    fn from(inner: State) -> JsState {
+        match inner {
+            State::Spent => JsState::Spent,
+            State::Unspent => JsState::Unspent,
+            State::Pending => JsState::Pending,
+        }
+    }
+}
+
+impl From<JsState> for State {
+    fn from(inner: JsState) -> State {
+        match inner {
+            JsState::Spent => State::Spent,
+            JsState::Unspent => State::Unspent,
+            JsState::Pending => State::Pending,
+        }
+    }
+}
+
+#[wasm_bindgen(js_name = CheckStateRequest)]
+pub struct JsCheckStateRequest {
+    inner: CheckStateRequest,
+}
+
+impl Deref for JsCheckStateRequest {
+    type Target = CheckStateRequest;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<CheckStateRequest> for JsCheckStateRequest {
+    fn from(inner: CheckStateRequest) -> JsCheckStateRequest {
+        JsCheckStateRequest { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = ProofState)]
+pub struct JsProofState {
+    inner: ProofState,
+}
+
+impl Deref for JsProofState {
+    type Target = ProofState;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<ProofState> for JsProofState {
+    fn from(inner: ProofState) -> JsProofState {
+        JsProofState { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = CheckStateResponse)]
+pub struct JsCheckStateResponse {
+    inner: CheckStateResponse,
+}
+
+impl Deref for JsCheckStateResponse {
+    type Target = CheckStateResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<CheckStateResponse> for JsCheckStateResponse {
+    fn from(inner: CheckStateResponse) -> JsCheckStateResponse {
+        JsCheckStateResponse { inner }
+    }
+}

+ 40 - 0
bindings/cdk-js/src/nuts/nut09.rs

@@ -0,0 +1,40 @@
+use std::ops::Deref;
+
+use cdk::nuts::{RestoreRequest, RestoreResponse};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = RestoreRequest)]
+pub struct JsRestoreRequest {
+    inner: RestoreRequest,
+}
+
+impl Deref for JsRestoreRequest {
+    type Target = RestoreRequest;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<RestoreRequest> for JsRestoreRequest {
+    fn from(inner: RestoreRequest) -> JsRestoreRequest {
+        JsRestoreRequest { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = RestoreResponse)]
+pub struct JsRestoreResponse {
+    inner: RestoreResponse,
+}
+
+impl Deref for JsRestoreResponse {
+    type Target = RestoreResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<RestoreResponse> for JsRestoreResponse {
+    fn from(inner: RestoreResponse) -> JsRestoreResponse {
+        JsRestoreResponse { inner }
+    }
+}

+ 64 - 0
bindings/cdk-js/src/nuts/nut10.rs

@@ -0,0 +1,64 @@
+use std::ops::Deref;
+
+use cdk::nuts::{Kind, Nut10Secret, SecretData};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = Kind)]
+pub enum JsKind {
+    P2PK,
+    HTLC,
+}
+
+impl From<Kind> for JsKind {
+    fn from(inner: Kind) -> JsKind {
+        match inner {
+            Kind::P2PK => JsKind::P2PK,
+            Kind::HTLC => JsKind::HTLC,
+        }
+    }
+}
+
+impl From<JsKind> for Kind {
+    fn from(inner: JsKind) -> Kind {
+        match inner {
+            JsKind::P2PK => Kind::P2PK,
+            JsKind::HTLC => Kind::HTLC,
+        }
+    }
+}
+
+#[wasm_bindgen(js_name = SecretData)]
+pub struct JsSecretData {
+    inner: SecretData,
+}
+
+impl Deref for JsSecretData {
+    type Target = SecretData;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SecretData> for JsSecretData {
+    fn from(inner: SecretData) -> JsSecretData {
+        JsSecretData { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = Secret)]
+pub struct JsNut10Secret {
+    inner: Nut10Secret,
+}
+
+impl Deref for JsNut10Secret {
+    type Target = Nut10Secret;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Nut10Secret> for JsNut10Secret {
+    fn from(inner: Nut10Secret) -> JsNut10Secret {
+        JsNut10Secret { inner }
+    }
+}

+ 40 - 0
bindings/cdk-js/src/nuts/nut11.rs

@@ -0,0 +1,40 @@
+use std::ops::Deref;
+
+use cdk::nuts::{Conditions, P2PKWitness};
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = P2PKWitness)]
+pub struct JsP2PKWitness {
+    inner: P2PKWitness,
+}
+
+impl Deref for JsP2PKWitness {
+    type Target = P2PKWitness;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<P2PKWitness> for JsP2PKWitness {
+    fn from(inner: P2PKWitness) -> JsP2PKWitness {
+        JsP2PKWitness { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = Conditions)]
+pub struct JsConditions {
+    inner: Conditions,
+}
+
+impl Deref for JsConditions {
+    type Target = Conditions;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Conditions> for JsConditions {
+    fn from(inner: Conditions) -> JsConditions {
+        JsConditions { inner }
+    }
+}

+ 99 - 0
bindings/cdk-js/src/nuts/nut12.rs

@@ -0,0 +1,99 @@
+use std::ops::Deref;
+
+use cdk::nuts::{BlindSignatureDleq, ProofDleq};
+use wasm_bindgen::prelude::*;
+
+use crate::nuts::JsSecretKey;
+
+#[wasm_bindgen(js_name = BlindSignatureDleq)]
+pub struct JsBlindSignatureDleq {
+    inner: BlindSignatureDleq,
+}
+
+#[wasm_bindgen(js_class = BlindedSignatureDleq)]
+impl JsBlindSignatureDleq {
+    #[wasm_bindgen(constructor)]
+    pub fn new(e: JsSecretKey, s: JsSecretKey) -> Self {
+        Self {
+            inner: BlindSignatureDleq {
+                e: e.deref().clone(),
+                s: s.deref().clone(),
+            },
+        }
+    }
+
+    /// e
+    #[wasm_bindgen(getter)]
+    pub fn e(&self) -> JsSecretKey {
+        self.inner.e.clone().into()
+    }
+
+    /// s
+    #[wasm_bindgen(getter)]
+    pub fn s(&self) -> JsSecretKey {
+        self.inner.s.clone().into()
+    }
+}
+
+impl Deref for JsBlindSignatureDleq {
+    type Target = BlindSignatureDleq;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<BlindSignatureDleq> for JsBlindSignatureDleq {
+    fn from(inner: BlindSignatureDleq) -> JsBlindSignatureDleq {
+        JsBlindSignatureDleq { inner }
+    }
+}
+
+#[wasm_bindgen(js_name = ProofDleq)]
+pub struct JsProofDleq {
+    inner: ProofDleq,
+}
+
+#[wasm_bindgen(js_class = ProofDleq)]
+impl JsProofDleq {
+    #[wasm_bindgen(constructor)]
+    pub fn new(e: JsSecretKey, s: JsSecretKey, r: JsSecretKey) -> Self {
+        Self {
+            inner: ProofDleq {
+                e: e.deref().clone(),
+                s: s.deref().clone(),
+                r: r.deref().clone(),
+            },
+        }
+    }
+
+    /// e
+    #[wasm_bindgen(getter)]
+    pub fn e(&self) -> JsSecretKey {
+        self.inner.e.clone().into()
+    }
+
+    /// s
+    #[wasm_bindgen(getter)]
+    pub fn s(&self) -> JsSecretKey {
+        self.inner.s.clone().into()
+    }
+
+    /// r
+    #[wasm_bindgen(getter)]
+    pub fn r(&self) -> JsSecretKey {
+        self.inner.r.clone().into()
+    }
+}
+
+impl Deref for JsProofDleq {
+    type Target = ProofDleq;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<ProofDleq> for JsProofDleq {
+    fn from(inner: ProofDleq) -> JsProofDleq {
+        JsProofDleq { inner }
+    }
+}

+ 22 - 0
bindings/cdk-js/src/nuts/nut14.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::nuts::HTLCWitness;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = HTLCWitness)]
+pub struct JsHTLCWitness {
+    inner: HTLCWitness,
+}
+
+impl Deref for JsHTLCWitness {
+    type Target = HTLCWitness;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<HTLCWitness> for JsHTLCWitness {
+    fn from(inner: HTLCWitness) -> JsHTLCWitness {
+        JsHTLCWitness { inner }
+    }
+}

+ 48 - 0
bindings/cdk-js/src/types/amount.rs

@@ -0,0 +1,48 @@
+use std::ops::Deref;
+
+use cdk::Amount;
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+
+#[wasm_bindgen(js_name = Amount)]
+pub struct JsAmount {
+    inner: Amount,
+}
+
+impl Deref for JsAmount {
+    type Target = Amount;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Amount> for JsAmount {
+    fn from(inner: Amount) -> JsAmount {
+        JsAmount { inner }
+    }
+}
+
+impl From<u64> for JsAmount {
+    fn from(amount: u64) -> JsAmount {
+        JsAmount {
+            inner: Amount::from(amount),
+        }
+    }
+}
+
+#[wasm_bindgen(js_class = Amount)]
+impl JsAmount {
+    #[wasm_bindgen(constructor)]
+    pub fn new(sats: u32) -> Self {
+        Self {
+            inner: Amount::from(sats as u64),
+        }
+    }
+
+    /// Split amount returns sat vec of sats
+    #[wasm_bindgen(js_name = split)]
+    pub fn split(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.split()).map_err(into_err)
+    }
+}

+ 22 - 0
bindings/cdk-js/src/types/melt_quote.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::types::MeltQuote;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = MeltQuote)]
+pub struct JsMeltQuote {
+    inner: MeltQuote,
+}
+
+impl Deref for JsMeltQuote {
+    type Target = MeltQuote;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MeltQuote> for JsMeltQuote {
+    fn from(inner: MeltQuote) -> JsMeltQuote {
+        JsMeltQuote { inner }
+    }
+}

+ 22 - 0
bindings/cdk-js/src/types/melted.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::types::Melted;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = Melted)]
+pub struct JsMelted {
+    inner: Melted,
+}
+
+impl Deref for JsMelted {
+    type Target = Melted;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Melted> for JsMelted {
+    fn from(inner: Melted) -> JsMelted {
+        JsMelted { inner }
+    }
+}

+ 22 - 0
bindings/cdk-js/src/types/mint_quote.rs

@@ -0,0 +1,22 @@
+use std::ops::Deref;
+
+use cdk::types::MintQuote;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = MintQuote)]
+pub struct JsMintQuote {
+    inner: MintQuote,
+}
+
+impl Deref for JsMintQuote {
+    type Target = MintQuote;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<MintQuote> for JsMintQuote {
+    fn from(inner: MintQuote) -> JsMintQuote {
+        JsMintQuote { inner }
+    }
+}

+ 11 - 0
bindings/cdk-js/src/types/mod.rs

@@ -0,0 +1,11 @@
+pub mod amount;
+pub mod melt_quote;
+pub mod melted;
+pub mod mint_quote;
+pub mod secret;
+
+pub use amount::JsAmount;
+pub use melt_quote::JsMeltQuote;
+pub use melted::JsMelted;
+pub use mint_quote::JsMintQuote;
+pub use secret::JsSecret;

+ 44 - 0
bindings/cdk-js/src/types/secret.rs

@@ -0,0 +1,44 @@
+use std::ops::Deref;
+
+use cdk::secret::Secret;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen(js_name = Secret)]
+pub struct JsSecret {
+    inner: Secret,
+}
+
+impl Default for JsSecret {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Deref for JsSecret {
+    type Target = Secret;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Secret> for JsSecret {
+    fn from(inner: Secret) -> JsSecret {
+        JsSecret { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = Secret)]
+impl JsSecret {
+    #[wasm_bindgen(constructor)]
+    pub fn new() -> JsSecret {
+        Self {
+            inner: Secret::generate(),
+        }
+    }
+
+    /// As Bytes
+    #[wasm_bindgen(js_name = asBytes)]
+    pub fn as_bytes(&self) -> Vec<u8> {
+        self.inner.as_bytes().to_vec()
+    }
+}

+ 150 - 0
bindings/cdk-js/src/wallet.rs

@@ -0,0 +1,150 @@
+use std::ops::Deref;
+use std::str::FromStr;
+use std::sync::Arc;
+
+use cdk::nuts::SigningKey;
+use cdk::url::UncheckedUrl;
+use cdk::wallet::Wallet;
+use cdk::HttpClient;
+use cdk_rexie::RexieWalletDatabase;
+use wasm_bindgen::prelude::*;
+
+use crate::error::{into_err, Result};
+use crate::nuts::{JsCurrencyUnit, JsMintInfo};
+use crate::types::melt_quote::JsMeltQuote;
+use crate::types::{JsAmount, JsMelted, JsMintQuote};
+
+#[wasm_bindgen(js_name = Wallet)]
+pub struct JsWallet {
+    inner: Wallet,
+}
+
+impl Deref for JsWallet {
+    type Target = Wallet;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<Wallet> for JsWallet {
+    fn from(inner: Wallet) -> JsWallet {
+        JsWallet { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = Wallet)]
+impl JsWallet {
+    #[wasm_bindgen(constructor)]
+    pub async fn new() -> Self {
+        let client = HttpClient::new();
+        let db = RexieWalletDatabase::new().await.unwrap();
+
+        Wallet::new(client, Arc::new(db), None).await.into()
+    }
+
+    #[wasm_bindgen(js_name = mintBalances)]
+    pub async fn mint_balances(&self) -> Result<JsValue> {
+        let mint_balances = self.inner.mint_balances().await.map_err(into_err)?;
+
+        Ok(serde_wasm_bindgen::to_value(&mint_balances)?)
+    }
+
+    #[wasm_bindgen(js_name = addMint)]
+    pub async fn add_mint(&self, mint_url: String) -> Result<Option<JsMintInfo>> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+
+        Ok(self
+            .inner
+            .add_mint(mint_url)
+            .await
+            .map_err(into_err)?
+            .map(|i| i.into()))
+    }
+
+    #[wasm_bindgen(js_name = refreshMint)]
+    pub async fn refresh_mint_keys(&self, mint_url: String) -> Result<()> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+        self.inner
+            .refresh_mint_keys(&mint_url)
+            .await
+            .map_err(into_err)?;
+        Ok(())
+    }
+
+    #[wasm_bindgen(js_name = mintQuote)]
+    pub async fn mint_quote(
+        &mut self,
+        mint_url: String,
+        amount: JsAmount,
+        unit: JsCurrencyUnit,
+    ) -> Result<JsMintQuote> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+        let quote = self
+            .inner
+            .mint_quote(mint_url, *amount.deref(), unit.into())
+            .await
+            .map_err(into_err)?;
+
+        Ok(quote.into())
+    }
+
+    #[wasm_bindgen(js_name = mint)]
+    pub async fn mint(&mut self, mint_url: String, quote_id: String) -> Result<JsAmount> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+
+        Ok(self
+            .inner
+            .mint(mint_url, &quote_id)
+            .await
+            .map_err(into_err)?
+            .into())
+    }
+
+    #[wasm_bindgen(js_name = meltQuote)]
+    pub async fn melt_quote(
+        &mut self,
+        mint_url: String,
+        unit: JsCurrencyUnit,
+        request: String,
+    ) -> Result<JsMeltQuote> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+        let melt_quote = self
+            .inner
+            .melt_quote(mint_url, unit.into(), request)
+            .await
+            .map_err(into_err)?;
+
+        Ok(melt_quote.into())
+    }
+
+    #[wasm_bindgen(js_name = melt)]
+    pub async fn melt(&mut self, mint_url: String, quote_id: String) -> Result<JsMelted> {
+        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
+
+        let melted = self
+            .inner
+            .melt(&mint_url, &quote_id)
+            .await
+            .map_err(into_err)?;
+
+        Ok(melted.into())
+    }
+
+    #[wasm_bindgen(js_name = receive)]
+    pub async fn receive(
+        &mut self,
+        encoded_token: String,
+        signing_keys: JsValue,
+        preimages: JsValue,
+    ) -> Result<()> {
+        let signing_keys: Option<Vec<SigningKey>> = serde_wasm_bindgen::from_value(signing_keys)?;
+        let preimages: Option<Vec<String>> = serde_wasm_bindgen::from_value(preimages)?;
+
+        self.inner
+            .receive(&encoded_token, signing_keys, preimages)
+            .await
+            .map_err(into_err)?;
+
+        Ok(())
+    }
+}

+ 12 - 0
bindings/uniffi-bindgen/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "uniffi-bindgen"
+version = "0.1.0"
+edition = "2021"
+publish = false
+rust-version.workspace = true
+
+[dependencies]
+uniffi = { workspace = true, features = ["cli"] }
+
+[build-dependencies]
+uniffi = { workspace = true, features = ["build"] }

+ 3 - 0
bindings/uniffi-bindgen/src/main.rs

@@ -0,0 +1,3 @@
+fn main() {
+    uniffi::uniffi_bindgen_main()
+}

+ 7 - 4
crates/cdk/src/nuts/mod.rs

@@ -16,8 +16,8 @@ pub mod nut13;
 pub mod nut14;
 
 pub use nut00::{
-    BlindSignature, BlindedMessage, CurrencyUnit, PaymentMethod, PreMint, PreMintSecrets, Proof,
-    Proofs, Token,
+    BlindSignature, BlindedMessage, CurrencyUnit, MintProofs, PaymentMethod, PreMint,
+    PreMintSecrets, Proof, Proofs, Token, Witness,
 };
 pub use nut01::{Keys, KeysResponse, PublicKey, SecretKey};
 #[cfg(feature = "mint")]
@@ -27,10 +27,12 @@ pub use nut02::{Id, KeySet, KeySetInfo, KeysetResponse};
 pub use nut03::PreSwap;
 pub use nut03::{SwapRequest, SwapResponse};
 pub use nut04::{
-    MintBolt11Request, MintBolt11Response, MintQuoteBolt11Request, MintQuoteBolt11Response,
+    MintBolt11Request, MintBolt11Response, MintMethodSettings, MintQuoteBolt11Request,
+    MintQuoteBolt11Response, Settings as NUT04Settings,
 };
 pub use nut05::{
-    MeltBolt11Request, MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response,
+    MeltBolt11Request, MeltBolt11Response, MeltMethodSettings, MeltQuoteBolt11Request,
+    MeltQuoteBolt11Response, Settings as NUT05Settings,
 };
 pub use nut06::{MintInfo, MintVersion, Nuts};
 pub use nut07::{CheckStateRequest, CheckStateResponse, ProofState, State};
@@ -38,3 +40,4 @@ pub use nut09::{RestoreRequest, RestoreResponse};
 pub use nut10::{Kind, Secret as Nut10Secret, SecretData};
 pub use nut11::{Conditions, P2PKWitness, SigFlag, SigningKey, SpendingConditions, VerifyingKey};
 pub use nut12::{BlindSignatureDleq, ProofDleq};
+pub use nut14::HTLCWitness;

+ 0 - 2
crates/cdk/src/wallet.rs

@@ -276,8 +276,6 @@ impl Wallet {
             )
             .await?;
 
-        // Separate proofs in spent and unspent based on mint response
-
         Ok(spendable.states)
     }
 

+ 1 - 1
flake.nix

@@ -54,7 +54,7 @@
         devShells = flakeboxLib.mkShells {
           toolchain = toolchainNative;
           packages = [ ];
-          nativeBuildInputs = with pkgs; [ ];
+          nativeBuildInputs = with pkgs; [ wasm-pack ];
         };
       });
 }