bee_block/output/token_scheme/
simple.rs

1// Copyright 2022 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use packable::{
5    error::{UnpackError, UnpackErrorExt},
6    packer::Packer,
7    unpacker::Unpacker,
8    Packable,
9};
10use primitive_types::U256;
11
12use crate::error::Error;
13
14///
15#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct SimpleTokenScheme {
18    // Amount of tokens minted by a foundry.
19    minted_tokens: U256,
20    // Amount of tokens melted by a foundry.
21    melted_tokens: U256,
22    // Maximum supply of tokens controlled by a foundry.
23    maximum_supply: U256,
24}
25
26impl SimpleTokenScheme {
27    /// The [`TokenScheme`](crate::output::TokenScheme) kind of a [`SimpleTokenScheme`].
28    pub const KIND: u8 = 0;
29
30    /// Creates a new [`SimpleTokenScheme`].
31    #[inline(always)]
32    pub fn new(minted_tokens: U256, melted_tokens: U256, maximum_supply: U256) -> Result<Self, Error> {
33        verify_supply(&minted_tokens, &melted_tokens, &maximum_supply)?;
34
35        Ok(Self {
36            minted_tokens,
37            melted_tokens,
38            maximum_supply,
39        })
40    }
41
42    /// Returns the number of minted tokens of the [`SimpleTokenScheme`].
43    #[inline(always)]
44    pub fn minted_tokens(&self) -> U256 {
45        self.minted_tokens
46    }
47
48    /// Returns the number of melted tokens of the [`SimpleTokenScheme`].
49    #[inline(always)]
50    pub fn melted_tokens(&self) -> U256 {
51        self.melted_tokens
52    }
53
54    /// Returns the maximum supply of the [`SimpleTokenScheme`].
55    #[inline(always)]
56    pub fn maximum_supply(&self) -> U256 {
57        self.maximum_supply
58    }
59
60    /// Returns the circulating supply of the [`SimpleTokenScheme`].
61    #[inline(always)]
62    pub fn circulating_supply(&self) -> U256 {
63        self.minted_tokens - self.melted_tokens
64    }
65}
66
67impl Packable for SimpleTokenScheme {
68    type UnpackError = Error;
69    type UnpackVisitor = ();
70
71    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
72        self.minted_tokens.pack(packer)?;
73        self.melted_tokens.pack(packer)?;
74        self.maximum_supply.pack(packer)?;
75
76        Ok(())
77    }
78
79    fn unpack<U: Unpacker, const VERIFY: bool>(
80        unpacker: &mut U,
81        visitor: &Self::UnpackVisitor,
82    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
83        let minted_tokens = U256::unpack::<_, VERIFY>(unpacker, visitor).coerce()?;
84        let melted_tokens = U256::unpack::<_, VERIFY>(unpacker, visitor).coerce()?;
85        let maximum_supply = U256::unpack::<_, VERIFY>(unpacker, visitor).coerce()?;
86
87        if VERIFY {
88            verify_supply(&minted_tokens, &melted_tokens, &maximum_supply).map_err(UnpackError::Packable)?;
89        }
90
91        Ok(Self {
92            minted_tokens,
93            melted_tokens,
94            maximum_supply,
95        })
96    }
97}
98
99#[inline]
100fn verify_supply(minted_tokens: &U256, melted_tokens: &U256, maximum_supply: &U256) -> Result<(), Error> {
101    if maximum_supply.is_zero() || melted_tokens > minted_tokens || minted_tokens - melted_tokens > *maximum_supply {
102        return Err(Error::InvalidFoundryOutputSupply {
103            minted: *minted_tokens,
104            melted: *melted_tokens,
105            max: *maximum_supply,
106        });
107    }
108
109    Ok(())
110}
111
112#[cfg(feature = "dto")]
113#[allow(missing_docs)]
114pub mod dto {
115    use serde::{Deserialize, Serialize};
116
117    use super::*;
118    use crate::{dto::U256Dto, error::dto::DtoError};
119
120    /// Describes a foundry output that is controlled by an alias.
121    #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
122    pub struct SimpleTokenSchemeDto {
123        #[serde(rename = "type")]
124        pub kind: u8,
125        // Amount of tokens minted by a foundry.
126        #[serde(rename = "mintedTokens")]
127        pub minted_tokens: U256Dto,
128        // Amount of tokens melted by a foundry.
129        #[serde(rename = "meltedTokens")]
130        pub melted_tokens: U256Dto,
131        // Maximum supply of tokens controlled by a foundry.
132        #[serde(rename = "maximumSupply")]
133        pub maximum_supply: U256Dto,
134    }
135
136    impl From<&SimpleTokenScheme> for SimpleTokenSchemeDto {
137        fn from(value: &SimpleTokenScheme) -> Self {
138            Self {
139                kind: SimpleTokenScheme::KIND,
140                minted_tokens: (&value.minted_tokens()).into(),
141                melted_tokens: (&value.melted_tokens()).into(),
142                maximum_supply: (&value.maximum_supply()).into(),
143            }
144        }
145    }
146
147    impl TryFrom<&SimpleTokenSchemeDto> for SimpleTokenScheme {
148        type Error = DtoError;
149
150        fn try_from(value: &SimpleTokenSchemeDto) -> Result<Self, Self::Error> {
151            Self::new(
152                U256::try_from(&value.minted_tokens).map_err(|_| DtoError::InvalidField("mintedTokens"))?,
153                U256::try_from(&value.melted_tokens).map_err(|_| DtoError::InvalidField("meltedTokens"))?,
154                U256::try_from(&value.maximum_supply).map_err(|_| DtoError::InvalidField("maximumSupply"))?,
155            )
156            .map_err(DtoError::Block)
157        }
158    }
159}