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, Clone, 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, Clone, 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    pub status: TransactionStatus,
45}
46
47impl From<(bitcoin::Transaction, TransactionStatus)> for Transaction {
48    fn from((transaction, status): (bitcoin::Transaction, TransactionStatus)) -> Self {
49        Transaction {
50            txid: transaction.compute_txid(),
51            version: transaction.version.0,
52            lock_time: transaction.lock_time.to_consensus_u32(),
53            input: transaction.input,
54            output: transaction
55                .output
56                .iter()
57                .map(|tx_out| TxOut {
58                    value: tx_out.value.to_sat(),
59                    script_pubkey: tx_out.script_pubkey.clone(),
60                    runes: vec![],
61                    risky_runes: vec![],
62                    spent: SpentStatus::Unspent,
63                })
64                .collect(),
65            status,
66        }
67    }
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct TxOut {
72    pub value: u64,
73    pub script_pubkey: ScriptBuf,
74    pub runes: Vec<RuneAmount>,
75    pub risky_runes: Vec<RuneAmount>,
76    pub spent: SpentStatus,
77}
78
79impl BorshSerialize for TxOut {
80    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
81        BorshSerialize::serialize(&self.value, writer)?;
82        let script_bytes = self.script_pubkey.as_bytes();
83        BorshSerialize::serialize(&(script_bytes.len() as u32), writer)?;
84        writer.write_all(script_bytes)?;
85        BorshSerialize::serialize(&self.runes, writer)?;
86        BorshSerialize::serialize(&self.risky_runes, writer)?;
87        BorshSerialize::serialize(&self.spent, writer)?;
88        Ok(())
89    }
90}
91
92impl BorshDeserialize for TxOut {
93    fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
94        let value = u64::deserialize_reader(reader)?;
95        let script_len = u32::deserialize_reader(reader)? as usize;
96        let mut script_bytes = vec![0u8; script_len];
97        reader.read_exact(&mut script_bytes)?;
98        let script_pubkey = ScriptBuf::from_bytes(script_bytes);
99        let runes = Vec::<RuneAmount>::deserialize_reader(reader)?;
100        let risky_runes = Vec::<RuneAmount>::deserialize_reader(reader)?;
101        let spent = SpentStatus::deserialize_reader(reader)?;
102
103        Ok(Self {
104            value,
105            script_pubkey,
106            runes,
107            risky_runes,
108            spent,
109        })
110    }
111}