iota_types/stardust/output/
alias.rs

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