Skip to main content

iota_types/timelock/
timelock.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk_types::{ObjectData, ObjectId, StructTag, TypeTag};
5use serde::{Deserialize, Serialize};
6
7use crate::{error::IotaError, gas_coin::GasCoin, id::UID, object::Object};
8
9/// All basic outputs whose IDs start with this prefix represent vested rewards
10/// that were created during the stardust upgrade on IOTA mainnet.
11pub const VESTED_REWARD_ID_PREFIX: &str =
12    "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18";
13
14/// Rust version of the Move stardust::TimeLock type.
15#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
16pub struct TimeLock<T> {
17    id: UID,
18    /// The locked object.
19    locked: T,
20    /// This is the epoch time stamp of when the lock expires.
21    expiration_timestamp_ms: u64,
22    /// Timelock related label.
23    label: Option<String>,
24}
25
26impl<T> TimeLock<T> {
27    /// Constructor.
28    pub fn new(id: UID, locked: T, expiration_timestamp_ms: u64, label: Option<String>) -> Self {
29        Self {
30            id,
31            locked,
32            expiration_timestamp_ms,
33            label,
34        }
35    }
36
37    /// Get the TimeLock's `id`.
38    pub fn id(&self) -> &ObjectId {
39        self.id.object_id()
40    }
41
42    /// Get the TimeLock's `locked` object.
43    pub fn locked(&self) -> &T {
44        &self.locked
45    }
46
47    /// Get the TimeLock's `expiration_timestamp_ms`.
48    pub fn expiration_timestamp_ms(&self) -> u64 {
49        self.expiration_timestamp_ms
50    }
51
52    /// Get the TimeLock's `label``.
53    pub fn label(&self) -> &Option<String> {
54        &self.label
55    }
56}
57
58impl<'de, T> TimeLock<T>
59where
60    T: Serialize + Deserialize<'de>,
61{
62    /// Create a `TimeLock` from BCS bytes.
63    pub fn from_bcs_bytes(content: &'de [u8]) -> Result<Self, IotaError> {
64        bcs::from_bytes(content).map_err(|err| IotaError::ObjectDeserialization {
65            error: format!("Unable to deserialize TimeLock object: {err:?}"),
66        })
67    }
68
69    /// Serialize a `TimeLock` as a `Vec<u8>` of BCS.
70    pub fn to_bcs_bytes(&self) -> Vec<u8> {
71        bcs::to_bytes(&self).unwrap()
72    }
73}
74
75/// Is this other StructTag representing a `TimeLock<Balance<T>>`?
76pub fn is_timelocked_balance(other: &StructTag) -> bool {
77    if !other.is_time_lock() {
78        return false;
79    }
80
81    match &other.type_params()[0] {
82        TypeTag::Struct(tag) => tag.is_balance(),
83        _ => false,
84    }
85}
86
87/// Is this other StructTag representing a `TimeLock<Balance<IOTA>>`?
88pub fn is_timelocked_gas_balance(other: &StructTag) -> bool {
89    if !other.is_time_lock() {
90        return false;
91    }
92
93    match &other.type_params()[0] {
94        TypeTag::Struct(tag) => GasCoin::is_gas_balance(tag),
95        _ => false,
96    }
97}
98
99impl<'de, T> TryFrom<&'de Object> for TimeLock<T>
100where
101    T: Serialize + Deserialize<'de>,
102{
103    type Error = IotaError;
104
105    fn try_from(object: &'de Object) -> Result<Self, Self::Error> {
106        match &object.data {
107            ObjectData::Struct(o) => {
108                if o.struct_tag().is_time_lock() {
109                    return TimeLock::from_bcs_bytes(o.contents());
110                }
111            }
112            ObjectData::Package(_) => {}
113        }
114
115        Err(IotaError::Type {
116            error: format!("Object type is not a TimeLock: {object:?}"),
117        })
118    }
119}