bee_block/payload/treasury_transaction/
mod.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! Module describing the treasury payload.
5
6use crate::{
7    input::{Input, TreasuryInput},
8    output::{Output, TreasuryOutput},
9    protocol::ProtocolParameters,
10    Error,
11};
12
13/// [`TreasuryTransactionPayload`] represents a transaction which moves funds from the treasury.
14#[derive(Clone, Debug, Eq, PartialEq, packable::Packable)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[packable(unpack_visitor = ProtocolParameters)]
17pub struct TreasuryTransactionPayload {
18    #[packable(verify_with = verify_input)]
19    input: Input,
20    #[packable(verify_with = verify_output)]
21    output: Output,
22}
23
24impl TreasuryTransactionPayload {
25    /// The payload kind of a [`TreasuryTransactionPayload`].
26    pub const KIND: u32 = 4;
27
28    /// Creates a new [`TreasuryTransactionPayload`].
29    pub fn new(input: TreasuryInput, output: TreasuryOutput) -> Result<Self, Error> {
30        Ok(Self {
31            input: input.into(),
32            output: output.into(),
33        })
34    }
35
36    /// Returns the input of a [`TreasuryTransactionPayload`].
37    pub fn input(&self) -> &TreasuryInput {
38        if let Input::Treasury(ref input) = self.input {
39            input
40        } else {
41            // It has already been validated at construction that `input` is a `TreasuryInput`.
42            unreachable!()
43        }
44    }
45
46    /// Returns the output of a [`TreasuryTransactionPayload`].
47    pub fn output(&self) -> &TreasuryOutput {
48        if let Output::Treasury(ref output) = self.output {
49            output
50        } else {
51            // It has already been validated at construction that `output` is a `TreasuryOutput`.
52            unreachable!()
53        }
54    }
55}
56
57fn verify_input<const VERIFY: bool>(input: &Input, _: &ProtocolParameters) -> Result<(), Error> {
58    if VERIFY && !matches!(input, Input::Treasury(_)) {
59        Err(Error::InvalidInputKind(input.kind()))
60    } else {
61        Ok(())
62    }
63}
64
65fn verify_output<const VERIFY: bool>(output: &Output, _: &ProtocolParameters) -> Result<(), Error> {
66    if VERIFY && !matches!(output, Output::Treasury(_)) {
67        Err(Error::InvalidOutputKind(output.kind()))
68    } else {
69        Ok(())
70    }
71}
72
73#[cfg(feature = "dto")]
74#[allow(missing_docs)]
75pub mod dto {
76    use serde::{Deserialize, Serialize};
77
78    use super::*;
79    use crate::{
80        error::dto::DtoError,
81        input::dto::{InputDto, TreasuryInputDto},
82        output::dto::{OutputDto, TreasuryOutputDto},
83    };
84
85    /// The payload type to define a treasury transaction.
86    #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
87    pub struct TreasuryTransactionPayloadDto {
88        #[serde(rename = "type")]
89        pub kind: u32,
90        pub input: InputDto,
91        pub output: OutputDto,
92    }
93
94    impl From<&TreasuryTransactionPayload> for TreasuryTransactionPayloadDto {
95        fn from(value: &TreasuryTransactionPayload) -> Self {
96            TreasuryTransactionPayloadDto {
97                kind: TreasuryTransactionPayload::KIND,
98                input: InputDto::Treasury(TreasuryInputDto::from(value.input())),
99                output: OutputDto::Treasury(TreasuryOutputDto::from(value.output())),
100            }
101        }
102    }
103
104    impl TreasuryTransactionPayload {
105        pub fn try_from_dto(
106            value: &TreasuryTransactionPayloadDto,
107            token_supply: u64,
108        ) -> Result<TreasuryTransactionPayload, DtoError> {
109            Ok(TreasuryTransactionPayload::new(
110                if let InputDto::Treasury(ref input) = value.input {
111                    input.try_into()?
112                } else {
113                    return Err(DtoError::InvalidField("input"));
114                },
115                if let OutputDto::Treasury(ref output) = value.output {
116                    TreasuryOutput::try_from_dto(output, token_supply)?
117                } else {
118                    return Err(DtoError::InvalidField("output"));
119                },
120            )?)
121        }
122    }
123}