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>
28where
29 SA: StorageMapperApi,
30 A: StorageAddress<SA>,
31 T: TopEncode + TopDecode + 'static,
32{
33 address: A,
34 key: StorageKey<SA>,
35 _phantom_api: PhantomData<SA>,
36 _phantom_item: PhantomData<T>,
37}
38
39impl<SA, T> StorageMapper<SA> for TimelockMapper<SA, T>
40where
41 SA: StorageMapperApi,
42 T: TopEncode + TopDecode,
43{
44 #[inline]
45 fn new(base_key: StorageKey<SA>) -> Self {
46 TimelockMapper {
47 address: CurrentStorage,
48 key: base_key,
49 _phantom_api: PhantomData,
50 _phantom_item: PhantomData,
51 }
52 }
53}
54
55impl<SA, T> TimelockMapper<SA, T>
56where
57 SA: StorageMapperApi + BlockchainApi,
58 T: TopEncode + TopDecode,
59{
60 pub fn set<BT>(&self, new_current_value: BT)
63 where
64 BT: Borrow<T>,
65 {
66 storage_set(self.key.as_ref(), new_current_value.borrow());
67 }
68
69 pub fn commit(&self) -> bool {
71 let now = SA::blockchain_api_impl().get_block_timestamp();
72 let unlock_timestamp: u64 = storage_get(self.get_unlock_timestamp_key().as_ref());
73
74 if now >= unlock_timestamp {
75 storage_overwrite(self.get_future_value_key().as_ref(), self.key.as_ref());
76 storage_clear(self.get_future_value_key().as_ref());
77 return true;
78 }
79
80 false
81 }
82
83 pub fn set_unlock_timestamp<BT>(&self, unlock_timestamp: u64, future_value: BT)
88 where
89 BT: Borrow<T>,
90 {
91 storage_set(self.get_unlock_timestamp_key().as_ref(), &unlock_timestamp);
92 storage_set(self.get_future_value_key().as_ref(), future_value.borrow());
93 }
94}
95
96impl<SA, T, A> TimelockMapper<SA, T, A>
97where
98 SA: StorageMapperApi,
99 T: TopEncode + TopDecode,
100 A: StorageAddress<SA>,
101{
102 pub fn get(&self) -> T {
104 self.address.address_storage_get(self.key.as_ref())
105 }
106
107 pub fn get_unlock_timestamp(&self) -> u64 {
109 self.address
110 .address_storage_get(self.get_unlock_timestamp_key().as_ref())
111 }
112
113 pub fn get_future_value(&self) -> T {
115 self.address
116 .address_storage_get(self.get_future_value_key().as_ref())
117 }
118
119 fn get_unlock_timestamp_key(&self) -> StorageKey<SA> {
120 let mut base_key = self.key.buffer.clone();
121 base_key.append_bytes(UNLOCK_TIMESTAMP_KEY);
122
123 StorageKey::from(base_key)
124 }
125
126 fn get_future_value_key(&self) -> StorageKey<SA> {
127 let mut base_key = self.key.buffer.clone();
128 base_key.append_bytes(FUTURE_VALUE_KEY);
129
130 StorageKey::from(base_key)
131 }
132}
133
134impl<SA, T> StorageMapperFromAddress<SA> for TimelockMapper<SA, T, ManagedAddress<SA>>
135where
136 SA: StorageMapperApi,
137 T: TopEncode + TopDecode,
138{
139 #[inline]
140 fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
141 TimelockMapper {
142 address,
143 key: base_key,
144 _phantom_api: PhantomData,
145 _phantom_item: PhantomData,
146 }
147 }
148}
149
150impl<SA, T> TopEncodeMulti for TimelockMapper<SA, T>
151where
152 SA: StorageMapperApi,
153 T: TopEncode + TopDecode,
154{
155 fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
156 where
157 O: TopEncodeMultiOutput,
158 H: EncodeErrorHandler,
159 {
160 output.push_single_value(&self.get(), h)
161 }
162}
163
164impl<SA, T, R> TypeAbiFrom<TimelockMapper<SA, T>> for SingleValue<R>
165where
166 SA: StorageMapperApi,
167 T: TopEncode + TopDecode,
168 R: TopDecode + TypeAbiFrom<T>,
169{
170}
171
172impl<SA, T> TypeAbiFrom<TimelockMapper<SA, T>> for PlaceholderOutput
173where
174 SA: StorageMapperApi,
175 T: TopEncode + TopDecode,
176{
177}
178
179impl<SA, T> TypeAbiFrom<Self> for TimelockMapper<SA, T>
180where
181 SA: StorageMapperApi,
182 T: TopEncode + TopDecode + TypeAbi,
183{
184}
185
186impl<SA, T> TypeAbi for TimelockMapper<SA, T>
187where
188 SA: StorageMapperApi,
189 T: TopEncode + TopDecode + TypeAbi,
190{
191 type Unmanaged = T::Unmanaged;
192
193 fn type_name() -> TypeName {
194 T::type_name()
195 }
196
197 fn type_name_rust() -> TypeName {
198 T::type_name_rust()
199 }
200
201 fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
202 T::provide_type_descriptions(accumulator)
203 }
204}