123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- //! Types for `cashu-rs`
- use std::collections::HashMap;
- use bitcoin::Amount;
- use lightning_invoice::Invoice;
- use rand::Rng;
- use secp256k1::{PublicKey, SecretKey};
- use serde::{Deserialize, Deserializer, Serialize, Serializer};
- use crate::{dhke::blind_message, error::Error, utils::split_amount};
- /// Blinded Message [NUT-00]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct BlindedMessage {
- /// Amount in satoshi
- #[serde(with = "bitcoin::amount::serde::as_sat")]
- pub amount: Amount,
- /// encrypted secret message (B_)
- #[serde(rename = "B_")]
- pub b: PublicKey,
- }
- /// Blinded Messages [NUT-00]
- #[derive(Debug, Default, Clone, PartialEq, Eq)]
- pub struct BlindedMessages {
- /// Blinded messages
- pub blinded_messages: Vec<BlindedMessage>,
- /// Secrets
- pub secrets: Vec<Vec<u8>>,
- /// Rs
- pub rs: Vec<SecretKey>,
- /// Amounts
- pub amounts: Vec<Amount>,
- }
- impl BlindedMessages {
- pub fn random(amount: Amount) -> Result<Self, Error> {
- let mut blinded_messages = BlindedMessages::default();
- let mut rng = rand::thread_rng();
- for amount in split_amount(amount) {
- let bytes: [u8; 32] = rng.gen();
- let (blinded, r) = blind_message(&bytes, None)?;
- let blinded_message = BlindedMessage { amount, b: blinded };
- blinded_messages.secrets.push(bytes.to_vec());
- blinded_messages.blinded_messages.push(blinded_message);
- blinded_messages.rs.push(r);
- blinded_messages.amounts.push(amount);
- }
- Ok(blinded_messages)
- }
- }
- /// Promise (BlindedSignature) [NIP-00]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct Promise {
- pub id: String,
- #[serde(with = "bitcoin::amount::serde::as_sat")]
- pub amount: Amount,
- /// blinded signature (C_) on the secret message `B_` of [BlindedMessage]
- #[serde(rename = "C_")]
- pub c: String,
- }
- /// Proofs [NUT-00]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct Proof {
- /// Amount in satoshi
- #[serde(with = "bitcoin::amount::serde::as_sat")]
- pub amount: Amount,
- /// Secret message
- pub secret: String,
- /// Unblinded signature
- #[serde(rename = "C")]
- pub c: String,
- /// `Keyset id`
- pub id: Option<String>,
- /// P2SHScript that specifies the spending condition for this Proof
- pub script: Option<String>,
- }
- /// Mint Keys [NIP-01]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MintKeys(pub HashMap<u64, String>);
- /// Mint Keysets [NIP-02]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MintKeySets {
- /// set of public keys that the mint generates
- pub keysets: Vec<String>,
- }
- /// Mint request response [NUT-03]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct RequestMintResponse {
- /// Bolt11 payment request
- pub pr: Invoice,
- /// Hash of Invoice
- pub hash: String,
- }
- /// Post Mint Request [NIP-04]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MintRequest {
- pub outputs: Vec<BlindedMessage>,
- }
- /// Post Mint Response [NUT-05]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct PostMintResponse {
- pub promises: Vec<Promise>,
- }
- /// Check Fees Response [NUT-05]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct CheckFeesResponse {
- /// Expected Mac Fee in satoshis
- #[serde(with = "bitcoin::amount::serde::as_sat")]
- pub fee: Amount,
- }
- /// Check Fees request [NUT-05]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct CheckFeesRequest {
- /// Lighting Invoice
- pub pr: Invoice,
- }
- /// Melt Request [NUT-05]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MeltRequest {
- pub proofs: Vec<Proof>,
- /// bollt11
- pub pr: Invoice,
- /// Blinded Message that can be used to return change [NUT-08]
- /// Amount feild of blindedMessages `SHOULD` be set to zero
- pub outputs: Option<Vec<BlindedMessage>>,
- }
- /// Melt Response [NUT-05]
- /// Lightning fee return [NUT-08] if change is defined
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MeltResposne {
- pub paid: bool,
- pub preimage: String,
- pub change: Option<Promise>,
- }
- /// Split Request [NUT-06]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct SplitRequest {
- #[serde(with = "bitcoin::amount::serde::as_sat")]
- pub amount: Amount,
- pub proofs: Vec<Proof>,
- pub outputs: Vec<BlindedMessage>,
- }
- /// Split Response [NUT-06]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct SplitResponse {
- /// Promises to keep
- pub fst: Vec<BlindedMessage>,
- /// Promises to send
- pub snd: Vec<BlindedMessage>,
- }
- /// Check spendabale request [NUT-07]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct CheckSpendableRequest {
- pub proofs: Vec<Proof>,
- }
- /// Check Spendable Response [NUT-07]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct CheckSpendableResponse {
- /// booleans indicating whether the provided Proof is still spendable.
- /// In same order as provided proofs
- pub spendable: Vec<bool>,
- }
- /// Mint Version
- #[derive(Debug, Clone, PartialEq, Eq)]
- pub struct MintVersion {
- name: String,
- version: String,
- }
- impl Serialize for MintVersion {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- let combined = format!("{}/{}", self.name, self.version);
- serializer.serialize_str(&combined)
- }
- }
- impl<'de> Deserialize<'de> for MintVersion {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- let combined = String::deserialize(deserializer)?;
- let parts: Vec<&str> = combined.split('/').collect();
- if parts.len() != 2 {
- return Err(serde::de::Error::custom("Invalid input string"));
- }
- Ok(MintVersion {
- name: parts[0].to_string(),
- version: parts[1].to_string(),
- })
- }
- }
- /// Mint Info [NIP-09]
- #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
- pub struct MintInfo {
- /// name of the mint and should be recognizable
- pub name: String,
- /// hex pubkey of the mint
- pub pubkey: String,
- /// implementation name and the version running
- pub version: MintVersion,
- /// short description of the mint
- pub description: String,
- /// long description
- pub description_long: String,
- /// contact methods to reach the mint operator
- pub contact: HashMap<String, String>,
- /// shows which NUTs the mint supports
- pub nuts: Vec<String>,
- /// message of the day that the wallet must display to the user
- pub motd: String,
- }
|