diff --git a/crates/cdk/src/nuts/mod.rs b/crates/cdk/src/nuts/mod.rs index 7e59e7c9b..6a2425fe6 100644 --- a/crates/cdk/src/nuts/mod.rs +++ b/crates/cdk/src/nuts/mod.rs @@ -13,6 +13,8 @@ pub mod nut11; pub mod nut12; #[cfg(feature = "nut13")] pub mod nut13; +pub mod nut17; +pub mod nut18; #[cfg(feature = "wallet")] pub use nut00::wallet::{PreMint, PreMintSecrets, Token}; @@ -24,7 +26,8 @@ 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, }; pub use nut05::{ MeltBolt11Request, MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, diff --git a/crates/cdk/src/nuts/nut00.rs b/crates/cdk/src/nuts/nut00.rs index 5a73c095e..ad6cd51b0 100644 --- a/crates/cdk/src/nuts/nut00.rs +++ b/crates/cdk/src/nuts/nut00.rs @@ -112,6 +112,7 @@ impl fmt::Display for CurrencyUnit { pub enum PaymentMethod { #[default] Bolt11, + BtcOnChain, Custom(String), } @@ -121,6 +122,7 @@ impl FromStr for PaymentMethod { fn from_str(s: &str) -> Result { match s { "bolt11" => Ok(Self::Bolt11), + "btconchain" => Ok(Self::BtcOnChain), _ => Ok(Self::Custom(s.to_string())), } } @@ -130,6 +132,7 @@ impl fmt::Display for PaymentMethod { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PaymentMethod::Bolt11 => write!(f, "bolt11"), + PaymentMethod::BtcOnChain => write!(f, "btconchain"), PaymentMethod::Custom(unit) => write!(f, "{}", unit), } } diff --git a/crates/cdk/src/nuts/nut17.rs b/crates/cdk/src/nuts/nut17.rs new file mode 100644 index 000000000..6ac4281df --- /dev/null +++ b/crates/cdk/src/nuts/nut17.rs @@ -0,0 +1,74 @@ +//! NUT-17: Minting tokens Onchain +//! +//! + +use serde::{Deserialize, Serialize}; + +use super::{BlindSignature, BlindedMessage, CurrencyUnit, MintMethodSettings}; +use crate::types::MintQuote; +use crate::Amount; + +/// Mint quote request [NUT-17] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MintQuoteBtcOnchainRequest { + /// Amount + pub amount: Amount, + /// Unit wallet would like to pay with + pub unit: CurrencyUnit, +} + +/// Mint quote response [NUT-17] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MintQuoteBtcOnchainResponse { + /// Quote Id + pub quote: String, + /// Payment request to fulfill + pub address: String, + /// Whether the the request has been paid + pub paid: bool, + /// Unix timestamp until the quote is valid + pub expiry: u64, +} + +impl From for MintQuoteBtcOnchainResponse { + fn from(mint_quote: MintQuote) -> MintQuoteBtcOnchainResponse { + MintQuoteBtcOnchainResponse { + quote: mint_quote.id, + address: mint_quote.request, + paid: mint_quote.paid, + expiry: mint_quote.expiry, + } + } +} + +/// Mint request [NUT-17] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MintBtcOnchainRequest { + /// Quote id + pub quote: String, + /// Outputs + pub outputs: Vec, +} + +impl MintBtcOnchainRequest { + pub fn total_amount(&self) -> Amount { + self.outputs + .iter() + .map(|BlindedMessage { amount, .. }| *amount) + .sum() + } +} + +/// Mint response [NUT-17] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MintBtcOnchainResponse { + /// Blind Signatures + pub signatures: Vec, +} + +/// Mint Settings +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Settings { + methods: Vec, + disabled: bool, +} diff --git a/crates/cdk/src/nuts/nut18.rs b/crates/cdk/src/nuts/nut18.rs new file mode 100644 index 000000000..a6e4b4847 --- /dev/null +++ b/crates/cdk/src/nuts/nut18.rs @@ -0,0 +1,68 @@ +//! NUT-18: Melting Tokens Onchain +//! +//! + +use serde::{Deserialize, Serialize}; + +use super::nut05::MeltMethodSettings; +use super::CurrencyUnit; +use crate::nuts::Proofs; +use crate::{Amount, Bolt11Invoice}; + +/// Melt quote request [NUT-18] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeltQuoteBtcOnchainRequest { + /// Amount to be paid + pub amount: Amount, + /// Bitcoin onchain address to be paid + pub address: Bolt11Invoice, + /// Unit wallet would like to pay with + pub unit: CurrencyUnit, +} + +/// Melt quote response [NUT-18] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeltQuoteBtcOnchainResponse { + /// Quote Id + pub quote: String, + /// Description + pub description: String, + /// The amount that needs to be provided + pub amount: u64, + /// The fee that is required + pub fee: u64, + /// Whether the the request has been paid + pub paid: bool, + /// Unix timestamp until the quote is valid + pub expiry: u64, +} + +/// Melt BTC on chain Request [NUT-18] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeltBtcOnchianRequest { + /// Quote ID + pub quote: String, + /// Proofs + pub inputs: Proofs, +} + +impl MeltBtcOnchianRequest { + pub fn proofs_amount(&self) -> Amount { + self.inputs.iter().map(|proof| proof.amount).sum() + } +} + +/// Melt Response [NUT-18] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct MeltBtcOnChainResponse { + /// Indicate if payment was successful + pub paid: bool, + // TXID + pub txid: Option, +} + +/// Melt Settings +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Settings { + methods: Vec, +}