diff --git a/sdk/src/types/block/context_input/mod.rs b/sdk/src/types/block/context_input/mod.rs new file mode 100644 index 0000000000..140eec203f --- /dev/null +++ b/sdk/src/types/block/context_input/mod.rs @@ -0,0 +1,83 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod reward; + +use derive_more::From; + +pub use self::reward::RewardContextInput; +use crate::types::block::Error; + +/// A Context Input provides additional contextual information for the execution of a transaction, such as for different +/// functionality related to accounts, commitments, or Mana rewards. A Context Input does not need to be unlocked. +#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)] +#[packable(unpack_error = Error)] +#[packable(tag_type = u8, with_error = Error::InvalidContextInputKind)] +pub enum ContextInput { + /// A [`RewardContextInput`]. + #[packable(tag = RewardContextInput::KIND)] + Reward(RewardContextInput), + // TODO: Commitment Input https://github.com/iotaledger/iota-sdk/issues/901 and Block Issuance Credit Input https://github.com/iotaledger/iota-sdk/issues/906 +} + +impl core::fmt::Debug for ContextInput { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Reward(input) => input.fmt(f), + } + } +} + +impl ContextInput { + /// Returns the context input kind of a `ContextInput`. + pub fn kind(&self) -> u8 { + match self { + Self::Reward(_) => RewardContextInput::KIND, + } + } + + /// Checks whether the context input is a [`RewardContextInput`]. + pub fn is_reward(&self) -> bool { + matches!(self, Self::Reward(_)) + } + + /// Gets the input as an actual [`RewardContextInput`]. + /// PANIC: do not call on a non-reward context input. + pub fn as_reward(&self) -> &RewardContextInput { + let Self::Reward(input) = self; + input + } +} + +pub mod dto { + use serde::{Deserialize, Serialize}; + + pub use super::reward::dto::RewardContextInputDto; + use super::*; + use crate::types::block::Error; + + /// Describes all the different context input types. + #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, From)] + #[serde(untagged)] + pub enum ContextInputDto { + Reward(RewardContextInputDto), + } + + impl From<&ContextInput> for ContextInputDto { + fn from(value: &ContextInput) -> Self { + match value { + ContextInput::Reward(u) => Self::Reward(u.into()), + } + } + } + + impl TryFrom for ContextInput { + type Error = Error; + + fn try_from(value: ContextInputDto) -> Result { + match value { + ContextInputDto::Reward(u) => Ok(Self::Reward(u.try_into()?)), + } + } + } +} diff --git a/sdk/src/types/block/context_input/reward.rs b/sdk/src/types/block/context_input/reward.rs new file mode 100644 index 0000000000..3ee3afb106 --- /dev/null +++ b/sdk/src/types/block/context_input/reward.rs @@ -0,0 +1,52 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use derive_more::{Display, From}; + +/// A Reward Context Input indicates which transaction Input is claiming Mana rewards. +#[derive(Clone, Copy, Debug, Display, Eq, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)] +pub struct RewardContextInput(u16); + +impl RewardContextInput { + /// The context input kind of a [`RewardContextInput`]. + pub const KIND: u8 = 2; + + /// Creates a new [`RewardContextInput`]. + pub fn new(index: u16) -> Self { + Self(index) + } + + /// Returns the index of a [`RewardContextInput`]. + pub fn index(&self) -> u16 { + self.0 + } +} + +pub(crate) mod dto { + use serde::{Deserialize, Serialize}; + + use super::*; + + /// A Reward Context Input is an input that indicates which transaction Input is claiming Mana rewards. + #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] + pub struct RewardContextInputDto { + #[serde(rename = "type")] + pub kind: u8, + pub index: u16, + } + + impl From<&RewardContextInput> for RewardContextInputDto { + fn from(value: &RewardContextInput) -> Self { + Self { + kind: RewardContextInput::KIND, + index: value.index(), + } + } + } + + impl From for RewardContextInput { + fn from(value: RewardContextInputDto) -> Self { + Self::new(value.index) + } + } +} diff --git a/sdk/src/types/block/error.rs b/sdk/src/types/block/error.rs index 99dce8c8f4..c8a0b5ffe5 100644 --- a/sdk/src/types/block/error.rs +++ b/sdk/src/types/block/error.rs @@ -41,6 +41,7 @@ pub enum Error { InsufficientStorageDepositAmount { amount: u64, required: u64 }, StorageDepositReturnExceedsOutputAmount { deposit: u64, amount: u64 }, InsufficientStorageDepositReturnAmount { deposit: u64, required: u64 }, + InvalidContextInputKind(u8), InvalidEssenceKind(u8), InvalidFeatureCount(>::Error), InvalidFeatureKind(u8), @@ -164,6 +165,7 @@ impl fmt::Display for Error { f, "storage deposit return of {deposit} exceeds the original output amount of {amount}" ), + Self::InvalidContextInputKind(k) => write!(f, "invalid context input kind: {k}"), Self::InvalidEssenceKind(k) => write!(f, "invalid essence kind: {k}"), Self::InvalidFeatureCount(count) => write!(f, "invalid feature count: {count}"), Self::InvalidFeatureKind(k) => write!(f, "invalid feature kind: {k}"), diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 2b7e4f541a..06b98b9feb 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -12,6 +12,8 @@ mod issuer_id; /// A module that provides types and syntactic validations of addresses. pub mod address; +/// A module that provides types and syntactic validations of context inputs. +pub mod context_input; /// A module that provides types and syntactic validations of blocks. pub mod core; /// A module that contains helper functions and types.