Skip to main content

iota_types/timelock/
timelocked_staked_iota.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk_types::{ObjectData, ObjectId};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    committee::EpochId, error::IotaError, governance::StakedIota, id::UID, object::Object,
9};
10
11/// Rust version of the Move
12/// stardust::timelocked_staked_iota::TimelockedStakedIota type.
13#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
14pub struct TimelockedStakedIota {
15    id: UID,
16    /// A self-custodial object holding the staked IOTA tokens.
17    staked_iota: StakedIota,
18    /// This is the epoch time stamp of when the lock expires.
19    expiration_timestamp_ms: u64,
20    /// Timelock related label.
21    label: Option<String>,
22}
23
24impl TimelockedStakedIota {
25    /// Get the TimelockedStakedIota's `id`.
26    pub fn id(&self) -> ObjectId {
27        self.id.id.bytes
28    }
29
30    /// Get the wrapped StakedIota's `pool_id`.
31    pub fn pool_id(&self) -> ObjectId {
32        self.staked_iota.pool_id()
33    }
34
35    /// Get the wrapped StakedIota's `activation_epoch`.
36    pub fn activation_epoch(&self) -> EpochId {
37        self.staked_iota.activation_epoch()
38    }
39
40    /// Get the wrapped StakedIota's `request_epoch`.
41    pub fn request_epoch(&self) -> EpochId {
42        // TODO: this might change when we implement warm up period.
43        self.staked_iota.activation_epoch().saturating_sub(1)
44    }
45
46    /// Get the wrapped StakedIota's `principal`.
47    pub fn principal(&self) -> u64 {
48        self.staked_iota.principal()
49    }
50
51    /// Get the TimelockedStakedIota's `expiration_timestamp_ms`.
52    pub fn expiration_timestamp_ms(&self) -> u64 {
53        self.expiration_timestamp_ms
54    }
55
56    /// Get the TimelockedStakedIota's `label``.
57    pub fn label(&self) -> &Option<String> {
58        &self.label
59    }
60}
61
62impl TryFrom<&Object> for TimelockedStakedIota {
63    type Error = IotaError;
64    fn try_from(object: &Object) -> Result<Self, Self::Error> {
65        match &object.data {
66            ObjectData::Struct(o) => {
67                if o.struct_tag().is_timelocked_staked_iota() {
68                    return bcs::from_bytes(o.contents()).map_err(|err| IotaError::Type {
69                        error: format!(
70                            "Unable to deserialize TimelockedStakedIota object: {err:?}"
71                        ),
72                    });
73                }
74            }
75            ObjectData::Package(_) => {}
76        }
77
78        Err(IotaError::Type {
79            error: format!("Object type is not a TimelockedStakedIota: {object:?}"),
80        })
81    }
82}