1use monero_serai::transaction::{Input, Transaction};
4
5pub fn tx_fee(tx: &Transaction) -> u64 {
11 let mut fee = 0_u64;
12
13 match &tx {
14 Transaction::V1 { prefix, .. } => {
15 for input in &prefix.inputs {
16 match input {
17 Input::Gen(_) => return 0,
18 Input::ToKey { amount, .. } => {
19 fee = fee.checked_add(amount.unwrap_or(0)).unwrap();
20 }
21 }
22 }
23
24 for output in &prefix.outputs {
25 fee = fee.checked_sub(output.amount.unwrap_or(0)).unwrap();
26 }
27 }
28 Transaction::V2 { proofs, .. } => {
29 fee = proofs.as_ref().unwrap().base.fee;
30 }
31 };
32
33 fee
34}
35
36#[cfg(test)]
37mod test {
38 use curve25519_dalek::edwards::CompressedEdwardsY;
39 use monero_serai::transaction::{NotPruned, Output, Timelock, TransactionPrefix};
40
41 use super::*;
42
43 #[test]
44 #[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
45 fn tx_fee_panic() {
46 let input = Input::ToKey {
47 amount: Some(u64::MAX),
48 key_offsets: vec![],
49 key_image: CompressedEdwardsY::default(),
50 };
51
52 let output = Output {
53 amount: Some(u64::MAX),
54 key: CompressedEdwardsY::default(),
55 view_tag: None,
56 };
57
58 let tx = Transaction::<NotPruned>::V1 {
59 prefix: TransactionPrefix {
60 additional_timelock: Timelock::None,
61 inputs: vec![input; 2],
62 outputs: vec![output],
63 extra: vec![],
64 },
65 signatures: vec![],
66 };
67
68 tx_fee(&tx);
69 }
70}