1use std::fmt;
18use std::ops::Deref;
19
20use ark::Vtxo;
21use ark::vtxo::{Bare, Full, VtxoRef};
22use crate::movement::MovementId;
23
24const SPENDABLE: &'static str = "Spendable";
25const LOCKED: &'static str = "Locked";
26const SPENT: &'static str = "Spent";
27
28#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
32pub enum VtxoStateKind {
33 Spendable,
35 Locked,
37 Spent,
39}
40
41impl VtxoStateKind {
42 pub fn as_str(&self) -> &str {
44 match self {
45 VtxoStateKind::Spendable => SPENDABLE,
46 VtxoStateKind::Locked => LOCKED,
47 VtxoStateKind::Spent => SPENT,
48 }
49 }
50
51 pub fn as_byte(&self) -> u8 {
52 match self {
53 VtxoStateKind::Spendable => 0,
54 VtxoStateKind::Locked { .. } => 1,
55 VtxoStateKind::Spent => 2,
56 }
57 }
58
59 pub const ALL: &[VtxoStateKind] = &[
61 VtxoStateKind::Spendable,
62 VtxoStateKind::Locked,
63 VtxoStateKind::Spent,
64 ];
65
66 pub const UNSPENT_STATES: &[VtxoStateKind] = &[
68 VtxoStateKind::Spendable,
69 VtxoStateKind::Locked,
70 ];
71}
72
73impl fmt::Display for VtxoStateKind {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.write_str(self.as_str())
76 }
77}
78
79impl fmt::Debug for VtxoStateKind {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.write_str(self.as_str())
82 }
83}
84
85#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[serde(tag = "type", rename_all = "kebab-case")]
88pub enum VtxoState {
89 Spendable,
91 Locked {
93 movement_id: Option<MovementId>,
95 },
96 Spent,
98}
99
100impl VtxoState {
101 pub fn kind(&self) -> VtxoStateKind {
103 match self {
104 VtxoState::Spendable => VtxoStateKind::Spendable,
105 VtxoState::Locked { .. } => VtxoStateKind::Locked,
106 VtxoState::Spent => VtxoStateKind::Spent,
107 }
108 }
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
113pub struct WalletVtxo {
114 #[serde(with = "ark::encode::serde")]
116 pub vtxo: Vtxo<Full>,
117 pub state: VtxoState,
119}
120
121impl VtxoRef for WalletVtxo {
122 fn vtxo_id(&self) -> ark::VtxoId { self.vtxo.id() }
123 fn as_bare_vtxo(&self) -> Option<std::borrow::Cow<'_, Vtxo<Bare>>> {
124 Some(std::borrow::Cow::Owned(self.vtxo.to_bare()))
125 }
126 fn as_full_vtxo(&self) -> Option<&Vtxo<Full>> { Some(&self.vtxo) }
127 fn into_full_vtxo(self) -> Option<Vtxo<Full>> { Some(self.vtxo) }
128}
129
130impl<'a> VtxoRef for &'a WalletVtxo {
131 fn vtxo_id(&self) -> ark::VtxoId { self.vtxo.id() }
132 fn as_bare_vtxo(&self) -> Option<std::borrow::Cow<'_, Vtxo<Bare>>> {
133 Some(std::borrow::Cow::Owned(self.vtxo.to_bare()))
134 }
135 fn as_full_vtxo(&self) -> Option<&Vtxo<Full>> { Some(&self.vtxo) }
136 fn into_full_vtxo(self) -> Option<Vtxo<Full>> { Some(self.vtxo.clone()) }
137}
138
139impl AsRef<Vtxo<Full>> for WalletVtxo {
140 fn as_ref(&self) -> &Vtxo<Full> {
141 &self.vtxo
142 }
143}
144
145impl Deref for WalletVtxo {
146 type Target = Vtxo<Full>;
147
148 fn deref(&self) -> &Vtxo<Full> {
149 &self.vtxo
150 }
151}
152
153#[cfg(test)]
154mod test {
155 use super::*;
156
157 #[test]
158 fn convert_serialize() {
159 let states = [
160 VtxoStateKind::Spendable,
161 VtxoStateKind::Spent,
162 VtxoStateKind::Locked,
163 ];
164
165 assert_eq!(
166 serde_json::to_string(&states).unwrap(),
167 serde_json::to_string(&[SPENDABLE, SPENT, LOCKED]).unwrap(),
168 );
169
170 match VtxoState::Spent {
173 VtxoState::Spendable => {},
174 VtxoState::Spent => {},
175 VtxoState::Locked { .. } => {},
176 }
177 }
178}