multiversx_sc/storage/mappers/timelock/
timelock_mapper.rs1use core::{borrow::Borrow, marker::PhantomData};
2
3pub use crate::storage::mappers::{
4 single_value_mapper::SingleValue, source::CurrentStorage, StorageMapper,
5};
6use crate::{
7 abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName},
8 api::{BlockchainApi, BlockchainApiImpl, StorageMapperApi},
9 codec::{
10 multi_types::PlaceholderOutput, EncodeErrorHandler, TopDecode, TopEncode, TopEncodeMulti,
11 TopEncodeMultiOutput,
12 },
13 imports::StorageMapperFromAddress,
14 storage::{
15 mappers::source::StorageAddress, storage_clear, storage_overwrite, storage_set, StorageKey,
16 },
17 storage_get,
18 types::{ManagedAddress, ManagedType},
19};
20
21const UNLOCK_TIMESTAMP_KEY: &[u8] = b"unlock_timestamp";
22const FUTURE_VALUE_KEY: &[u8] = b"future_value";
23
24pub struct TimelockMapper<SA, T, A = CurrentStorage>
25where
26 SA: StorageMapperApi,
27 A: StorageAddress<SA>,
28 T: TopEncode + TopDecode + 'static,
29{
30 address: A,
31 key: StorageKey<SA>,
32 _phantom_api: PhantomData<SA>,
33 _phantom_item: PhantomData<T>,
34}
35
36impl<SA, T> StorageMapper<SA> for TimelockMapper<SA, T>
37where
38 SA: StorageMapperApi,
39 T: TopEncode + TopDecode,
40{
41 #[inline]
42 fn new(base_key: StorageKey<SA>) -> Self {
43 TimelockMapper {
44 address: CurrentStorage,
45 key: base_key,
46 _phantom_api: PhantomData,
47 _phantom_item: PhantomData,
48 }
49 }
50}
51
52impl<SA, T> TimelockMapper<SA, T>
53where
54 SA: StorageMapperApi + BlockchainApi,
55 T: TopEncode + TopDecode,
56{
57 pub fn set<BT>(&self, new_current_value: BT)
60 where
61 BT: Borrow<T>,
62 {
63 storage_set(self.key.as_ref(), new_current_value.borrow());
64 }
65
66 pub fn commit(&self) -> bool {
68 let now = SA::blockchain_api_impl().get_block_timestamp();
69 let unlock_timestamp: u64 = storage_get(self.get_unlock_timestamp_key().as_ref());
70
71 if now >= unlock_timestamp {
72 storage_overwrite(self.get_future_value_key().as_ref(), self.key.as_ref());
73 storage_clear(self.get_future_value_key().as_ref());
74 return true;
75 }
76
77 false
78 }
79
80 pub fn set_unlock_timestamp<BT>(&self, unlock_timestamp: u64, future_value: BT)
85 where
86 BT: Borrow<T>,
87 {
88 storage_set(self.get_unlock_timestamp_key().as_ref(), &unlock_timestamp);
89 storage_set(self.get_future_value_key().as_ref(), future_value.borrow());
90 }
91}
92
93impl<SA, T, A> TimelockMapper<SA, T, A>
94where
95 SA: StorageMapperApi,
96 T: TopEncode + TopDecode,
97 A: StorageAddress<SA>,
98{
99 pub fn get(&self) -> T {
101 self.address.address_storage_get(self.key.as_ref())
102 }
103
104 pub fn get_unlock_timestamp(&self) -> u64 {
106 self.address
107 .address_storage_get(self.get_unlock_timestamp_key().as_ref())
108 }
109
110 pub fn get_future_value(&self) -> T {
112 self.address
113 .address_storage_get(self.get_future_value_key().as_ref())
114 }
115
116 fn get_unlock_timestamp_key(&self) -> StorageKey<SA> {
117 let mut base_key = self.key.buffer.clone();
118 base_key.append_bytes(UNLOCK_TIMESTAMP_KEY);
119
120 StorageKey::from(base_key)
121 }
122
123 fn get_future_value_key(&self) -> StorageKey<SA> {
124 let mut base_key = self.key.buffer.clone();
125 base_key.append_bytes(FUTURE_VALUE_KEY);
126
127 StorageKey::from(base_key)
128 }
129}
130
131impl<SA, T> StorageMapperFromAddress<SA> for TimelockMapper<SA, T, ManagedAddress<SA>>
132where
133 SA: StorageMapperApi,
134 T: TopEncode + TopDecode,
135{
136 #[inline]
137 fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
138 TimelockMapper {
139 address,
140 key: base_key,
141 _phantom_api: PhantomData,
142 _phantom_item: PhantomData,
143 }
144 }
145}
146
147impl<SA, T> TopEncodeMulti for TimelockMapper<SA, T>
148where
149 SA: StorageMapperApi,
150 T: TopEncode + TopDecode,
151{
152 fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
153 where
154 O: TopEncodeMultiOutput,
155 H: EncodeErrorHandler,
156 {
157 output.push_single_value(&self.get(), h)
158 }
159}
160
161impl<SA, T, R> TypeAbiFrom<TimelockMapper<SA, T>> for SingleValue<R>
162where
163 SA: StorageMapperApi,
164 T: TopEncode + TopDecode,
165 R: TopDecode + TypeAbiFrom<T>,
166{
167}
168
169impl<SA, T> TypeAbiFrom<TimelockMapper<SA, T>> for PlaceholderOutput
170where
171 SA: StorageMapperApi,
172 T: TopEncode + TopDecode,
173{
174}
175
176impl<SA, T> TypeAbiFrom<Self> for TimelockMapper<SA, T>
177where
178 SA: StorageMapperApi,
179 T: TopEncode + TopDecode + TypeAbi,
180{
181}
182
183impl<SA, T> TypeAbi for TimelockMapper<SA, T>
184where
185 SA: StorageMapperApi,
186 T: TopEncode + TopDecode + TypeAbi,
187{
188 type Unmanaged = T::Unmanaged;
189
190 fn type_name() -> TypeName {
191 T::type_name()
192 }
193
194 fn type_name_rust() -> TypeName {
195 T::type_name_rust()
196 }
197
198 fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
199 T::provide_type_descriptions(accumulator)
200 }
201}