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