Skip to main content

cashu/nuts/
nut07.rs

1//! NUT-07: Spendable Check
2//!
3//! <https://github.com/cashubtc/nuts/blob/main/07.md>
4
5use std::fmt;
6use std::str::FromStr;
7
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11use super::nut01::PublicKey;
12use super::Witness;
13
14/// NUT07 Error
15#[derive(Debug, Error, PartialEq, Eq)]
16pub enum Error {
17    /// Unknown State error
18    #[error("Unknown state")]
19    UnknownState,
20}
21
22/// State of Proof
23#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "UPPERCASE")]
25pub enum State {
26    /// Spent
27    Spent,
28    /// Unspent
29    Unspent,
30    /// Pending
31    ///
32    /// Currently being used in a transaction i.e. melt in progress
33    Pending,
34    /// Reserved
35    ///
36    /// Proof is reserved for future token creation
37    Reserved,
38    /// Pending spent (i.e., spent but not yet swapped by receiver)
39    PendingSpent,
40}
41
42impl fmt::Display for State {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        let s = match self {
45            Self::Spent => "SPENT",
46            Self::Unspent => "UNSPENT",
47            Self::Pending => "PENDING",
48            Self::Reserved => "RESERVED",
49            Self::PendingSpent => "PENDING_SPENT",
50        };
51
52        write!(f, "{s}")
53    }
54}
55
56impl FromStr for State {
57    type Err = Error;
58
59    fn from_str(state: &str) -> Result<Self, Self::Err> {
60        match state {
61            "SPENT" => Ok(Self::Spent),
62            "UNSPENT" => Ok(Self::Unspent),
63            "PENDING" => Ok(Self::Pending),
64            "RESERVED" => Ok(Self::Reserved),
65            "PENDING_SPENT" => Ok(Self::PendingSpent),
66            _ => Err(Error::UnknownState),
67        }
68    }
69}
70
71/// Check spendable request [NUT-07]
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct CheckStateRequest {
74    /// Y's of the proofs to check
75    #[serde(rename = "Ys")]
76    pub ys: Vec<PublicKey>,
77}
78
79/// Proof state [NUT-07]
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81pub struct ProofState {
82    /// Y of proof
83    #[serde(rename = "Y")]
84    pub y: PublicKey,
85    /// State of proof
86    pub state: State,
87    /// Witness data if it is supplied
88    pub witness: Option<Witness>,
89}
90
91impl From<(PublicKey, State)> for ProofState {
92    fn from(value: (PublicKey, State)) -> Self {
93        Self {
94            y: value.0,
95            state: value.1,
96            witness: None,
97        }
98    }
99}
100
101/// Check Spendable Response [NUT-07]
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct CheckStateResponse {
104    /// Proof states
105    pub states: Vec<ProofState>,
106}