iota_types/
coin_manager.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk_types::Identifier;
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    IotaAddress, StructTag,
9    coin::{CoinMetadata, TreasuryCap},
10    error::IotaError,
11    id::UID,
12    object::{Data, Object},
13};
14
15pub const COIN_MANAGER_TREASURY_CAP_STRUCT_NAME: Identifier =
16    Identifier::from_static("CoinManagerTreasuryCap");
17
18/// The purpose of a CoinManager is to allow access to all
19/// properties of a Coin on-chain from within a single shared object
20/// This includes access to the total supply and metadata
21/// In addition a optional maximum supply can be set and a custom
22/// additional Metadata field can be added.
23/// Holds all related objects to a Coin in a convenient shared function.
24#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
25pub struct CoinManager {
26    /// The unique identifier of the object.
27    pub id: UID,
28    /// The original TreasuryCap object as returned by `create_currency`
29    pub treasury_cap: TreasuryCap,
30    /// Metadata object, original one from the `coin` module, if available
31    pub metadata: Option<CoinMetadata>,
32    /// Immutable Metadata object, only to be used as a last resort if the
33    /// original metadata is frozen
34    pub immutable_metadata: Option<ImmutableCoinMetadata>,
35    /// Optional maximum supply, if set you can't mint more as this number - can
36    /// only be set once
37    pub maximum_supply: Option<u64>,
38    /// Flag indicating if the supply is considered immutable (TreasuryCap is
39    /// exchanged for this)
40    pub supply_immutable: bool,
41    /// Flag indicating if the metadata is considered immutable (MetadataCap is
42    /// exchanged for this)
43    pub metadata_immutable: bool,
44}
45
46impl CoinManager {
47    pub fn from_bcs_bytes(content: &[u8]) -> Result<Self, IotaError> {
48        bcs::from_bytes(content).map_err(|err| IotaError::ObjectDeserialization {
49            error: format!("Unable to deserialize CoinManager object: {err}"),
50        })
51    }
52}
53
54/// The immutable version of CoinMetadata, used in case of migrating from frozen
55/// objects to a `CoinManager` holding the metadata.
56#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
57pub struct ImmutableCoinMetadata {
58    /// Number of decimal places the coin uses.
59    pub decimals: u8,
60    /// Name for the token
61    pub name: String,
62    /// Symbol for the token
63    pub symbol: String,
64    /// Description of the token
65    pub description: String,
66    /// URL for the token logo
67    pub icon_url: Option<String>,
68}
69
70/// Like `TreasuryCap`, but for dealing with `TreasuryCap` inside `CoinManager`
71/// objects
72#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
73pub struct CoinManagerTreasuryCap {
74    /// The unique identifier of the object.
75    pub id: UID,
76}
77
78impl CoinManagerTreasuryCap {
79    pub fn is_coin_manager_treasury_cap(object_type: &StructTag) -> bool {
80        object_type.address() == IotaAddress::FRAMEWORK
81            && object_type.module() == &Identifier::COIN_MANAGER_MODULE
82            && object_type.name() == &COIN_MANAGER_TREASURY_CAP_STRUCT_NAME
83    }
84}
85
86impl TryFrom<Object> for CoinManager {
87    type Error = IotaError;
88    fn try_from(object: Object) -> Result<Self, Self::Error> {
89        TryFrom::try_from(&object)
90    }
91}
92
93impl TryFrom<&Object> for CoinManager {
94    type Error = IotaError;
95    fn try_from(object: &Object) -> Result<Self, Self::Error> {
96        if let Data::Struct(o) = &object.data {
97            if o.struct_tag().is_coin_manager() {
98                return CoinManager::from_bcs_bytes(o.contents());
99            }
100        }
101
102        Err(IotaError::Type {
103            error: format!("Object type is not a CoinManager: {object:?}"),
104        })
105    }
106}