titan_types/
transaction.rs

1use {
2    crate::rune::RuneAmount,
3    crate::tx_out::SpentStatus,
4    bitcoin::{BlockHash, ScriptBuf, TxIn, Txid},
5    borsh::{BorshDeserialize, BorshSerialize},
6    serde::{Deserialize, Serialize},
7    std::io::{Read, Result, Write},
8};
9
10#[derive(Debug, Serialize, Deserialize)]
11pub struct TransactionStatus {
12    pub confirmed: bool,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub block_height: Option<u64>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub block_hash: Option<BlockHash>,
17}
18
19impl TransactionStatus {
20    pub fn unconfirmed() -> Self {
21        Self {
22            confirmed: false,
23            block_height: None,
24            block_hash: None,
25        }
26    }
27
28    pub fn confirmed(block_height: u64, block_hash: BlockHash) -> Self {
29        Self {
30            confirmed: true,
31            block_height: Some(block_height),
32            block_hash: Some(block_hash),
33        }
34    }
35}
36
37#[derive(Debug, Serialize, Deserialize)]
38pub struct Transaction {
39    pub txid: Txid,
40    pub version: i32,
41    pub lock_time: u32,
42    pub input: Vec<TxIn>,
43    pub output: Vec<TxOut>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub status: Option<TransactionStatus>,
46}
47
48impl From<bitcoin::Transaction> for Transaction {
49    fn from(transaction: bitcoin::Transaction) -> Self {
50        Transaction {
51            txid: transaction.compute_txid(),
52            version: transaction.version.0,
53            lock_time: transaction.lock_time.to_consensus_u32(),
54            input: transaction.input,
55            output: transaction
56                .output
57                .iter()
58                .map(|tx_out| TxOut {
59                    value: tx_out.value.to_sat(),
60                    script_pubkey: tx_out.script_pubkey.clone(),
61                    runes: vec![],
62                    risky_runes: vec![],
63                    spent: SpentStatus::Unspent,
64                })
65                .collect(),
66            status: None,
67        }
68    }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct TxOut {
73    pub value: u64,
74    pub script_pubkey: ScriptBuf,
75    pub runes: Vec<RuneAmount>,
76    pub risky_runes: Vec<RuneAmount>,
77    pub spent: SpentStatus,
78}
79
80impl BorshSerialize for TxOut {
81    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
82        BorshSerialize::serialize(&self.value, writer)?;
83        let script_bytes = self.script_pubkey.as_bytes();
84        BorshSerialize::serialize(&(script_bytes.len() as u32), writer)?;
85        writer.write_all(script_bytes)?;
86        BorshSerialize::serialize(&self.runes, writer)?;
87        BorshSerialize::serialize(&self.risky_runes, writer)?;
88        BorshSerialize::serialize(&self.spent, writer)?;
89        Ok(())
90    }
91}
92
93impl BorshDeserialize for TxOut {
94    fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
95        let value = u64::deserialize_reader(reader)?;
96        let script_len = u32::deserialize_reader(reader)? as usize;
97        let mut script_bytes = vec![0u8; script_len];
98        reader.read_exact(&mut script_bytes)?;
99        let script_pubkey = ScriptBuf::from_bytes(script_bytes);
100        let runes = Vec::<RuneAmount>::deserialize_reader(reader)?;
101        let risky_runes = Vec::<RuneAmount>::deserialize_reader(reader)?;
102        let spent = SpentStatus::deserialize_reader(reader)?;
103
104        Ok(Self {
105            value,
106            script_pubkey,
107            runes,
108            risky_runes,
109            spent,
110        })
111    }
112}