1use {
2 crate::rune::RuneAmount,
3 bitcoin::{hashes::Hash, Txid},
4 borsh::{BorshDeserialize, BorshSerialize},
5 serde::{Deserialize, Serialize},
6 std::io::{Read, Result, Write},
7};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SpenderReference {
11 pub txid: Txid,
12 pub vin: u32,
13}
14
15impl BorshSerialize for SpenderReference {
16 fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
17 BorshSerialize::serialize(&self.txid.as_raw_hash().to_byte_array(), writer)?;
18 BorshSerialize::serialize(&self.vin, writer)?;
19 Ok(())
20 }
21}
22
23impl BorshDeserialize for SpenderReference {
24 fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
25 let txid_bytes = <[u8; 32]>::deserialize_reader(reader)?;
26 let txid = bitcoin::Txid::from_byte_array(txid_bytes);
27 let vin = u32::deserialize_reader(reader)?;
28 Ok(Self { txid, vin })
29 }
30}
31
32#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
33pub enum SpentStatus {
34 Unspent,
35 Spent(SpenderReference),
36}
37
38#[derive(Clone, Serialize, Deserialize)]
40struct SpentStatusJson {
41 spent: bool,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 vin: Option<SpenderReference>,
44}
45
46impl Serialize for SpentStatus {
47 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
48 where
49 S: serde::Serializer,
50 {
51 match self {
52 SpentStatus::Unspent => SpentStatusJson {
53 spent: false,
54 vin: None,
55 },
56 SpentStatus::Spent(vin) => SpentStatusJson {
57 spent: true,
58 vin: Some(vin.clone()),
59 },
60 }
61 .serialize(serializer)
62 }
63}
64
65impl<'de> Deserialize<'de> for SpentStatus {
66 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
67 where
68 D: serde::Deserializer<'de>,
69 {
70 let json = SpentStatusJson::deserialize(deserializer)?;
71 Ok(if json.spent {
72 SpentStatus::Spent(json.vin.ok_or_else(|| {
73 serde::de::Error::custom("missing vin field for spent transaction")
74 })?)
75 } else {
76 SpentStatus::Unspent
77 })
78 }
79}
80
81#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
82pub struct TxOutEntry {
83 pub runes: Vec<RuneAmount>,
84 pub risky_runes: Vec<RuneAmount>,
85 pub value: u64,
86 pub spent: SpentStatus,
87}
88
89impl TxOutEntry {
90 pub fn has_runes(&self) -> bool {
91 !self.runes.is_empty()
92 }
93}