iota_types/stardust/output/
alias.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk_types::{Identifier, StructTag, TypeTag};
5use serde::{Deserialize, Serialize};
6use serde_with::serde_as;
7
8use crate::{
9    balance::Balance,
10    base_types::IotaAddress,
11    collection_types::Bag,
12    error::IotaError,
13    id::UID,
14    object::{Data, Object},
15};
16
17pub const ALIAS_MODULE_NAME: Identifier = Identifier::from_static("alias");
18pub const ALIAS_OUTPUT_MODULE_NAME: Identifier = Identifier::from_static("alias_output");
19pub const ALIAS_OUTPUT_STRUCT_NAME: Identifier = Identifier::from_static("AliasOutput");
20pub const ALIAS_STRUCT_NAME: Identifier = Identifier::from_static("Alias");
21pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"alias";
22pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector<u8>";
23
24#[serde_as]
25#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
26pub struct Alias {
27    /// The ID of the Alias = hash of the Output ID that created the Alias
28    /// Output in Stardust. This is the AliasID from Stardust.
29    pub id: UID,
30
31    /// The last State Controller address assigned before the migration.
32    pub legacy_state_controller: IotaAddress,
33    /// A counter increased by 1 every time the alias was state transitioned.
34    pub state_index: u32,
35    /// State metadata that can be used to store additional information.
36    pub state_metadata: Option<Vec<u8>>,
37
38    /// The sender feature.
39    pub sender: Option<IotaAddress>,
40    /// The metadata feature.
41    pub metadata: Option<Vec<u8>>,
42
43    /// The immutable issuer feature.
44    pub immutable_issuer: Option<IotaAddress>,
45    /// The immutable metadata feature.
46    pub immutable_metadata: Option<Vec<u8>>,
47}
48
49impl Alias {
50    /// Returns the struct tag that represents the fully qualified path of an
51    /// [`Alias`] in its move package.
52    pub fn tag() -> StructTag {
53        StructTag::new(
54            IotaAddress::STARDUST,
55            ALIAS_MODULE_NAME,
56            ALIAS_STRUCT_NAME,
57            Vec::new(),
58        )
59    }
60}
61
62#[serde_as]
63#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
64pub struct AliasOutput {
65    /// This is a "random" UID, not the AliasID from Stardust.
66    pub id: UID,
67
68    /// The amount of coins held by the output.
69    pub balance: Balance,
70    /// The `Bag` holds native tokens, key-ed by the stringified type of the
71    /// asset. Example: key: "0xabcded::soon::SOON", value:
72    /// Balance<0xabcded::soon::SOON>.
73    pub native_tokens: Bag,
74}
75
76impl AliasOutput {
77    /// Returns the struct tag that represents the fully qualified path of an
78    /// [`AliasOutput`] in its move package.
79    pub fn tag(type_param: TypeTag) -> StructTag {
80        StructTag::new(
81            IotaAddress::STARDUST,
82            ALIAS_OUTPUT_MODULE_NAME,
83            ALIAS_OUTPUT_STRUCT_NAME,
84            vec![type_param],
85        )
86    }
87
88    /// Create an `AliasOutput` from BCS bytes.
89    pub fn from_bcs_bytes(content: &[u8]) -> Result<Self, IotaError> {
90        bcs::from_bytes(content).map_err(|err| IotaError::ObjectDeserialization {
91            error: format!("Unable to deserialize AliasOutput object: {err:?}"),
92        })
93    }
94
95    pub fn is_alias_output(s: &StructTag) -> bool {
96        s.address() == IotaAddress::STARDUST
97            && s.module() == &ALIAS_OUTPUT_MODULE_NAME
98            && s.name() == &ALIAS_OUTPUT_STRUCT_NAME
99    }
100}
101
102impl TryFrom<&Object> for AliasOutput {
103    type Error = IotaError;
104    fn try_from(object: &Object) -> Result<Self, Self::Error> {
105        match &object.data {
106            Data::Struct(o) => {
107                if AliasOutput::is_alias_output(o.struct_tag()) {
108                    return AliasOutput::from_bcs_bytes(o.contents());
109                }
110            }
111            Data::Package(_) => {}
112        }
113
114        Err(IotaError::Type {
115            error: format!("Object type is not an AliasOutput: {object:?}"),
116        })
117    }
118}