From 7ea7e0bda084904188c3d4944942ea2cdd1c839f Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Sun, 5 May 2024 19:35:45 +0100 Subject: [PATCH] feat: js bindings --- Cargo.toml | 14 +- bindings/cdk-js/Cargo.toml | 23 +++ bindings/cdk-js/src/error.rs | 12 ++ bindings/cdk-js/src/lib.rs | 11 ++ bindings/cdk-js/src/nuts/mod.rs | 24 +++ .../cdk-js/src/nuts/nut00/blind_signature.rs | 42 +++++ .../cdk-js/src/nuts/nut00/blinded_message.rs | 71 ++++++++ .../cdk-js/src/nuts/nut00/currency_unit.rs | 32 ++++ bindings/cdk-js/src/nuts/nut00/mint_proofs.rs | 22 +++ bindings/cdk-js/src/nuts/nut00/mod.rs | 17 ++ .../cdk-js/src/nuts/nut00/payment_method.rs | 24 +++ bindings/cdk-js/src/nuts/nut00/premint.rs | 40 +++++ bindings/cdk-js/src/nuts/nut00/proof.rs | 76 +++++++++ bindings/cdk-js/src/nuts/nut00/token.rs | 22 +++ bindings/cdk-js/src/nuts/nut00/witness.rs | 28 ++++ bindings/cdk-js/src/nuts/nut01/keys.rs | 51 ++++++ bindings/cdk-js/src/nuts/nut01/mod.rs | 7 + bindings/cdk-js/src/nuts/nut01/public_key.rs | 41 +++++ bindings/cdk-js/src/nuts/nut01/secret_key.rs | 31 ++++ bindings/cdk-js/src/nuts/nut02/id.rs | 42 +++++ bindings/cdk-js/src/nuts/nut02/keyset.rs | 117 +++++++++++++ bindings/cdk-js/src/nuts/nut02/mod.rs | 4 + bindings/cdk-js/src/nuts/nut03.rs | 104 ++++++++++++ bindings/cdk-js/src/nuts/nut04.rs | 155 ++++++++++++++++++ bindings/cdk-js/src/nuts/nut05.rs | 115 +++++++++++++ bindings/cdk-js/src/nuts/nut06.rs | 142 ++++++++++++++++ bindings/cdk-js/src/nuts/nut07.rs | 85 ++++++++++ bindings/cdk-js/src/nuts/nut09.rs | 40 +++++ bindings/cdk-js/src/nuts/nut10.rs | 64 ++++++++ bindings/cdk-js/src/nuts/nut11.rs | 40 +++++ bindings/cdk-js/src/nuts/nut12.rs | 99 +++++++++++ bindings/cdk-js/src/nuts/nut14.rs | 22 +++ bindings/cdk-js/src/types/amount.rs | 48 ++++++ bindings/cdk-js/src/types/melt_quote.rs | 22 +++ bindings/cdk-js/src/types/melted.rs | 22 +++ bindings/cdk-js/src/types/mint_quote.rs | 22 +++ bindings/cdk-js/src/types/mod.rs | 11 ++ bindings/cdk-js/src/types/secret.rs | 44 +++++ bindings/cdk-js/src/wallet.rs | 150 +++++++++++++++++ bindings/uniffi-bindgen/Cargo.toml | 12 ++ bindings/uniffi-bindgen/src/main.rs | 3 + crates/cdk/src/nuts/mod.rs | 11 +- crates/cdk/src/wallet.rs | 2 - flake.nix | 2 +- 44 files changed, 1954 insertions(+), 12 deletions(-) create mode 100644 bindings/cdk-js/Cargo.toml create mode 100644 bindings/cdk-js/src/error.rs create mode 100644 bindings/cdk-js/src/lib.rs create mode 100644 bindings/cdk-js/src/nuts/mod.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/blind_signature.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/blinded_message.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/currency_unit.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/mint_proofs.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/mod.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/payment_method.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/premint.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/proof.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/token.rs create mode 100644 bindings/cdk-js/src/nuts/nut00/witness.rs create mode 100644 bindings/cdk-js/src/nuts/nut01/keys.rs create mode 100644 bindings/cdk-js/src/nuts/nut01/mod.rs create mode 100644 bindings/cdk-js/src/nuts/nut01/public_key.rs create mode 100644 bindings/cdk-js/src/nuts/nut01/secret_key.rs create mode 100644 bindings/cdk-js/src/nuts/nut02/id.rs create mode 100644 bindings/cdk-js/src/nuts/nut02/keyset.rs create mode 100644 bindings/cdk-js/src/nuts/nut02/mod.rs create mode 100644 bindings/cdk-js/src/nuts/nut03.rs create mode 100644 bindings/cdk-js/src/nuts/nut04.rs create mode 100644 bindings/cdk-js/src/nuts/nut05.rs create mode 100644 bindings/cdk-js/src/nuts/nut06.rs create mode 100644 bindings/cdk-js/src/nuts/nut07.rs create mode 100644 bindings/cdk-js/src/nuts/nut09.rs create mode 100644 bindings/cdk-js/src/nuts/nut10.rs create mode 100644 bindings/cdk-js/src/nuts/nut11.rs create mode 100644 bindings/cdk-js/src/nuts/nut12.rs create mode 100644 bindings/cdk-js/src/nuts/nut14.rs create mode 100644 bindings/cdk-js/src/types/amount.rs create mode 100644 bindings/cdk-js/src/types/melt_quote.rs create mode 100644 bindings/cdk-js/src/types/melted.rs create mode 100644 bindings/cdk-js/src/types/mint_quote.rs create mode 100644 bindings/cdk-js/src/types/mod.rs create mode 100644 bindings/cdk-js/src/types/secret.rs create mode 100644 bindings/cdk-js/src/wallet.rs create mode 100644 bindings/uniffi-bindgen/Cargo.toml create mode 100644 bindings/uniffi-bindgen/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 61bfdc86..b3130b47 100644 --- a/Cargo.toml +++ b/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] diff --git a/bindings/cdk-js/Cargo.toml b/bindings/cdk-js/Cargo.toml new file mode 100644 index 00000000..85ecd313 --- /dev/null +++ b/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" diff --git a/bindings/cdk-js/src/error.rs b/bindings/cdk-js/src/error.rs new file mode 100644 index 00000000..d4e1cb0d --- /dev/null +++ b/bindings/cdk-js/src/error.rs @@ -0,0 +1,12 @@ +use wasm_bindgen::JsValue; + +pub type Result = std::result::Result; + +/// Helper to replace the `E` to `Error` to `napi::Error` conversion. +#[inline] +pub fn into_err(error: E) -> JsValue +where + E: std::fmt::Display, +{ + JsValue::from_str(&error.to_string()) +} diff --git a/bindings/cdk-js/src/lib.rs b/bindings/cdk-js/src/lib.rs new file mode 100644 index 00000000..4f39ec59 --- /dev/null +++ b/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(); +} diff --git a/bindings/cdk-js/src/nuts/mod.rs b/bindings/cdk-js/src/nuts/mod.rs new file mode 100644 index 00000000..7fdc1a3e --- /dev/null +++ b/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; diff --git a/bindings/cdk-js/src/nuts/nut00/blind_signature.rs b/bindings/cdk-js/src/nuts/nut00/blind_signature.rs new file mode 100644 index 00000000..c361303c --- /dev/null +++ b/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, + ) -> Self { + Self { + inner: BlindSignature { + keyset_id: *keyset_id.deref(), + amount: *amount.deref(), + c: c.deref().clone(), + dleq: dleq.map(|b| b.deref().clone()), + }, + } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/blinded_message.rs b/bindings/cdk-js/src/nuts/nut00/blinded_message.rs new file mode 100644 index 00000000..60f6ad27 --- /dev/null +++ b/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 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, + ) -> 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 { + self.inner.witness.clone().map(|w| w.into()) + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/currency_unit.rs b/bindings/cdk-js/src/nuts/nut00/currency_unit.rs new file mode 100644 index 00000000..56141d25 --- /dev/null +++ b/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 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 for CurrencyUnit { + fn from(inner: JsCurrencyUnit) -> CurrencyUnit { + match inner { + JsCurrencyUnit::Sat => CurrencyUnit::Sat, + JsCurrencyUnit::Msat => CurrencyUnit::Msat, + JsCurrencyUnit::Usd => CurrencyUnit::Usd, + } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/mint_proofs.rs b/bindings/cdk-js/src/nuts/nut00/mint_proofs.rs new file mode 100644 index 00000000..1dda5065 --- /dev/null +++ b/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 for JsMintProofs { + fn from(inner: MintProofs) -> JsMintProofs { + JsMintProofs { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/mod.rs b/bindings/cdk-js/src/nuts/nut00/mod.rs new file mode 100644 index 00000000..6c027c60 --- /dev/null +++ b/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; diff --git a/bindings/cdk-js/src/nuts/nut00/payment_method.rs b/bindings/cdk-js/src/nuts/nut00/payment_method.rs new file mode 100644 index 00000000..be7105ed --- /dev/null +++ b/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 for JsPaymentMethod { + fn from(inner: PaymentMethod) -> JsPaymentMethod { + match inner { + PaymentMethod::Bolt11 => JsPaymentMethod::Bolt11, + PaymentMethod::Custom(_) => todo!(), + } + } +} + +impl From for PaymentMethod { + fn from(inner: JsPaymentMethod) -> PaymentMethod { + match inner { + JsPaymentMethod::Bolt11 => PaymentMethod::Bolt11, + } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/premint.rs b/bindings/cdk-js/src/nuts/nut00/premint.rs new file mode 100644 index 00000000..9e8f7a82 --- /dev/null +++ b/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 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 for JsPreMintSecrets { + fn from(inner: PreMintSecrets) -> JsPreMintSecrets { + JsPreMintSecrets { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/proof.rs b/bindings/cdk-js/src/nuts/nut00/proof.rs new file mode 100644 index 00000000..d5d148ac --- /dev/null +++ b/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 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, + dleq: Option, + ) -> 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() + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/token.rs b/bindings/cdk-js/src/nuts/nut00/token.rs new file mode 100644 index 00000000..83a810b1 --- /dev/null +++ b/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 for JsToken { + fn from(inner: Token) -> JsToken { + JsToken { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut00/witness.rs b/bindings/cdk-js/src/nuts/nut00/witness.rs new file mode 100644 index 00000000..1aa26546 --- /dev/null +++ b/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 for JsWitness { + fn from(inner: Witness) -> JsWitness { + match inner { + Witness::P2PKWitness(_) => JsWitness::JsP2PKWitness, + Witness::HTLCWitness(_) => JsWitness::JsHTLCWitness, + } + } +} diff --git a/bindings/cdk-js/src/nuts/nut01/keys.rs b/bindings/cdk-js/src/nuts/nut01/keys.rs new file mode 100644 index 00000000..e44db08f --- /dev/null +++ b/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 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 { + 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 { + 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 { + self.inner.amount_key(*amount.deref()).map(|k| k.into()) + } +} diff --git a/bindings/cdk-js/src/nuts/nut01/mod.rs b/bindings/cdk-js/src/nuts/nut01/mod.rs new file mode 100644 index 00000000..888a7f89 --- /dev/null +++ b/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; diff --git a/bindings/cdk-js/src/nuts/nut01/public_key.rs b/bindings/cdk-js/src/nuts/nut01/public_key.rs new file mode 100644 index 00000000..7fb3440a --- /dev/null +++ b/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 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 { + 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() + } +} diff --git a/bindings/cdk-js/src/nuts/nut01/secret_key.rs b/bindings/cdk-js/src/nuts/nut01/secret_key.rs new file mode 100644 index 00000000..6bd7180c --- /dev/null +++ b/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 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() + } +} diff --git a/bindings/cdk-js/src/nuts/nut02/id.rs b/bindings/cdk-js/src/nuts/nut02/id.rs new file mode 100644 index 00000000..d0044ae2 --- /dev/null +++ b/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 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 { + 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() + } +} diff --git a/bindings/cdk-js/src/nuts/nut02/keyset.rs b/bindings/cdk-js/src/nuts/nut02/keyset.rs new file mode 100644 index 00000000..47f74f0d --- /dev/null +++ b/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 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 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 { + 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 { + 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 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 { + 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 { + serde_wasm_bindgen::to_value(&self.inner.keysets).map_err(into_err) + } +} diff --git a/bindings/cdk-js/src/nuts/nut02/mod.rs b/bindings/cdk-js/src/nuts/nut02/mod.rs new file mode 100644 index 00000000..e88193dc --- /dev/null +++ b/bindings/cdk-js/src/nuts/nut02/mod.rs @@ -0,0 +1,4 @@ +pub mod id; +pub mod keyset; + +pub use id::JsId; diff --git a/bindings/cdk-js/src/nuts/nut03.rs b/bindings/cdk-js/src/nuts/nut03.rs new file mode 100644 index 00000000..993dba9e --- /dev/null +++ b/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 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 { + 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 { + serde_wasm_bindgen::to_value(&self.inner.inputs).map_err(into_err) + } + + /// Get Outputs + #[wasm_bindgen(getter)] + pub fn outputs(&self) -> Result { + 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 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 { + 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 { + 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() + } +} diff --git a/bindings/cdk-js/src/nuts/nut04.rs b/bindings/cdk-js/src/nuts/nut04.rs new file mode 100644 index 00000000..7a1f27b8 --- /dev/null +++ b/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 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 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 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 { + 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 { + 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 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 { + 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 { + 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 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 for JsSettings { + fn from(inner: Settings) -> JsSettings { + JsSettings { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut05.rs b/bindings/cdk-js/src/nuts/nut05.rs new file mode 100644 index 00000000..88fffe17 --- /dev/null +++ b/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 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 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 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 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 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 for JsSettings { + fn from(inner: NUT05Settings) -> JsSettings { + JsSettings { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut06.rs b/bindings/cdk-js/src/nuts/nut06.rs new file mode 100644 index 00000000..9e8759f5 --- /dev/null +++ b/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 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 { + 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 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, + pubkey: Option, + version: Option, + description: Option, + description_long: Option, + contact: JsValue, + nuts: JsValue, + motd: Option, + ) -> Result { + 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 { + self.inner.name.clone() + } + + /// Get Pubkey + #[wasm_bindgen(getter)] + pub fn pubkey(&self) -> Option { + self.inner.pubkey.clone().map(|p| p.into()) + } + + /// Get Version + #[wasm_bindgen(getter)] + pub fn version(&self) -> Option { + self.inner.version.clone().map(|v| v.into()) + } + + /// Get description + #[wasm_bindgen(getter)] + pub fn description(&self) -> Option { + self.inner.description.clone() + } + + /// Get description long + #[wasm_bindgen(getter)] + pub fn description_long(&self) -> Option { + self.inner.description_long.clone() + } + + /// Get contact + #[wasm_bindgen(getter)] + pub fn contact(&self) -> Result { + serde_wasm_bindgen::to_value(&self.inner.contact).map_err(into_err) + } + + /// Get supported nuts + #[wasm_bindgen(getter)] + pub fn nuts(&self) -> Result { + serde_wasm_bindgen::to_value(&self.inner.nuts).map_err(into_err) + } + + /// Get motd + #[wasm_bindgen(getter)] + pub fn motd(&self) -> Option { + self.inner.motd.clone() + } +} diff --git a/bindings/cdk-js/src/nuts/nut07.rs b/bindings/cdk-js/src/nuts/nut07.rs new file mode 100644 index 00000000..0268e21b --- /dev/null +++ b/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 for JsState { + fn from(inner: State) -> JsState { + match inner { + State::Spent => JsState::Spent, + State::Unspent => JsState::Unspent, + State::Pending => JsState::Pending, + } + } +} + +impl From 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 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 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 for JsCheckStateResponse { + fn from(inner: CheckStateResponse) -> JsCheckStateResponse { + JsCheckStateResponse { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut09.rs b/bindings/cdk-js/src/nuts/nut09.rs new file mode 100644 index 00000000..ead4690b --- /dev/null +++ b/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 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 for JsRestoreResponse { + fn from(inner: RestoreResponse) -> JsRestoreResponse { + JsRestoreResponse { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut10.rs b/bindings/cdk-js/src/nuts/nut10.rs new file mode 100644 index 00000000..1c276f95 --- /dev/null +++ b/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 for JsKind { + fn from(inner: Kind) -> JsKind { + match inner { + Kind::P2PK => JsKind::P2PK, + Kind::HTLC => JsKind::HTLC, + } + } +} + +impl From 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 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 for JsNut10Secret { + fn from(inner: Nut10Secret) -> JsNut10Secret { + JsNut10Secret { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut11.rs b/bindings/cdk-js/src/nuts/nut11.rs new file mode 100644 index 00000000..e7c7f7d7 --- /dev/null +++ b/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 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 for JsConditions { + fn from(inner: Conditions) -> JsConditions { + JsConditions { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut12.rs b/bindings/cdk-js/src/nuts/nut12.rs new file mode 100644 index 00000000..22961437 --- /dev/null +++ b/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 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 for JsProofDleq { + fn from(inner: ProofDleq) -> JsProofDleq { + JsProofDleq { inner } + } +} diff --git a/bindings/cdk-js/src/nuts/nut14.rs b/bindings/cdk-js/src/nuts/nut14.rs new file mode 100644 index 00000000..d659bb0d --- /dev/null +++ b/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 for JsHTLCWitness { + fn from(inner: HTLCWitness) -> JsHTLCWitness { + JsHTLCWitness { inner } + } +} diff --git a/bindings/cdk-js/src/types/amount.rs b/bindings/cdk-js/src/types/amount.rs new file mode 100644 index 00000000..a6523341 --- /dev/null +++ b/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 for JsAmount { + fn from(inner: Amount) -> JsAmount { + JsAmount { inner } + } +} + +impl From 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 { + serde_wasm_bindgen::to_value(&self.inner.split()).map_err(into_err) + } +} diff --git a/bindings/cdk-js/src/types/melt_quote.rs b/bindings/cdk-js/src/types/melt_quote.rs new file mode 100644 index 00000000..6ac1b1e3 --- /dev/null +++ b/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 for JsMeltQuote { + fn from(inner: MeltQuote) -> JsMeltQuote { + JsMeltQuote { inner } + } +} diff --git a/bindings/cdk-js/src/types/melted.rs b/bindings/cdk-js/src/types/melted.rs new file mode 100644 index 00000000..3b9cb8ac --- /dev/null +++ b/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 for JsMelted { + fn from(inner: Melted) -> JsMelted { + JsMelted { inner } + } +} diff --git a/bindings/cdk-js/src/types/mint_quote.rs b/bindings/cdk-js/src/types/mint_quote.rs new file mode 100644 index 00000000..643ed2b6 --- /dev/null +++ b/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 for JsMintQuote { + fn from(inner: MintQuote) -> JsMintQuote { + JsMintQuote { inner } + } +} diff --git a/bindings/cdk-js/src/types/mod.rs b/bindings/cdk-js/src/types/mod.rs new file mode 100644 index 00000000..e27ce7ea --- /dev/null +++ b/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; diff --git a/bindings/cdk-js/src/types/secret.rs b/bindings/cdk-js/src/types/secret.rs new file mode 100644 index 00000000..683a6578 --- /dev/null +++ b/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 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 { + self.inner.as_bytes().to_vec() + } +} diff --git a/bindings/cdk-js/src/wallet.rs b/bindings/cdk-js/src/wallet.rs new file mode 100644 index 00000000..05eda059 --- /dev/null +++ b/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 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 { + 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> { + 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 { + 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 { + let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?; + + Ok(self + .inner + .mint(mint_url, "e_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 { + 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 { + let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?; + + let melted = self + .inner + .melt(&mint_url, "e_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> = serde_wasm_bindgen::from_value(signing_keys)?; + let preimages: Option> = serde_wasm_bindgen::from_value(preimages)?; + + self.inner + .receive(&encoded_token, signing_keys, preimages) + .await + .map_err(into_err)?; + + Ok(()) + } +} diff --git a/bindings/uniffi-bindgen/Cargo.toml b/bindings/uniffi-bindgen/Cargo.toml new file mode 100644 index 00000000..eed466f6 --- /dev/null +++ b/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"] } diff --git a/bindings/uniffi-bindgen/src/main.rs b/bindings/uniffi-bindgen/src/main.rs new file mode 100644 index 00000000..f6cff6cf --- /dev/null +++ b/bindings/uniffi-bindgen/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/crates/cdk/src/nuts/mod.rs b/crates/cdk/src/nuts/mod.rs index 88661628..50115be7 100644 --- a/crates/cdk/src/nuts/mod.rs +++ b/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; diff --git a/crates/cdk/src/wallet.rs b/crates/cdk/src/wallet.rs index 59d2d5a5..23b201fe 100644 --- a/crates/cdk/src/wallet.rs +++ b/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) } diff --git a/flake.nix b/flake.nix index dfbd4f53..d8ecc0e8 100644 --- a/flake.nix +++ b/flake.nix @@ -54,7 +54,7 @@ devShells = flakeboxLib.mkShells { toolchain = toolchainNative; packages = [ ]; - nativeBuildInputs = with pkgs; [ ]; + nativeBuildInputs = with pkgs; [ wasm-pack ]; }; }); }