1use std::fmt;
18use std::ops::Deref;
19
20use ark::vtxo::VtxoRef;
21
22use ark::Vtxo;
23use crate::movement::MovementId;
24
25const SPENDABLE: &'static str = "Spendable";
26const LOCKED: &'static str = "Locked";
27const SPENT: &'static str = "Spent";
28
29#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
33pub enum VtxoStateKind {
34 Spendable,
36 Locked,
38 Spent,
40}
41
42impl VtxoStateKind {
43 pub fn as_str(&self) -> &str {
45 match self {
46 VtxoStateKind::Spendable => SPENDABLE,
47 VtxoStateKind::Locked => LOCKED,
48 VtxoStateKind::Spent => SPENT,
49 }
50 }
51}
52
53impl fmt::Display for VtxoStateKind {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.write_str(self.as_str())
56 }
57}
58
59impl fmt::Debug for VtxoStateKind {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.write_str(self.as_str())
62 }
63}
64
65lazy_static::lazy_static! {
66 pub static ref UNSPENT_STATES: Vec<VtxoStateKind> = vec![
67 VtxoStateKind::Spendable,
68 VtxoStateKind::Locked,
69 ];
70}
71
72#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
74#[serde(tag = "type", rename_all = "kebab-case")]
75pub enum VtxoState {
76 Spendable,
78 Spent,
80 Locked {
82 movement_id: Option<MovementId>,
84 },
85}
86
87impl VtxoState {
88 pub fn kind(&self) -> VtxoStateKind {
90 match self {
91 VtxoState::Locked { .. } => VtxoStateKind::Locked,
92 VtxoState::Spendable => VtxoStateKind::Spendable,
93 VtxoState::Spent => VtxoStateKind::Spent,
94 }
95 }
96}
97
98#[derive(Clone, Debug, PartialEq, Eq)]
100pub struct WalletVtxo {
101 pub vtxo: Vtxo,
103 pub state: VtxoState,
105}
106
107impl VtxoRef for WalletVtxo {
108 fn vtxo_id(&self) -> ark::VtxoId { self.vtxo.id() }
109 fn vtxo(&self) -> Option<&Vtxo> { Some(&self.vtxo) }
110}
111
112impl<'a> VtxoRef for &'a WalletVtxo {
113 fn vtxo_id(&self) -> ark::VtxoId { self.vtxo.id() }
114 fn vtxo(&self) -> Option<&Vtxo> { Some(&self.vtxo) }
115}
116
117impl Deref for WalletVtxo {
118 type Target = Vtxo;
119
120 fn deref(&self) -> &Vtxo {
121 &self.vtxo
122 }
123}
124
125#[cfg(test)]
126mod test {
127 use super::*;
128
129 #[test]
130 fn convert_serialize() {
131 let states = [
132 VtxoStateKind::Spendable,
133 VtxoStateKind::Spent,
134 VtxoStateKind::Locked,
135 ];
136
137 assert_eq!(
138 serde_json::to_string(&states).unwrap(),
139 serde_json::to_string(&[SPENDABLE, SPENT, LOCKED]).unwrap(),
140 );
141
142 match VtxoState::Spent {
145 VtxoState::Spendable => {},
146 VtxoState::Spent => {},
147 VtxoState::Locked { .. } => {},
148 }
149 }
150}