multiversx_sc/contract_base/wrappers/
call_value_wrapper.rs1use core::marker::PhantomData;
2
3use multiversx_chain_core::EGLD_000000_TOKEN_IDENTIFIER;
4
5use crate::{
6 api::{
7 const_handles, use_raw_handle, CallValueApi, CallValueApiImpl, ErrorApi, ErrorApiImpl,
8 ManagedBufferApiImpl, ManagedTypeApi, RawHandle, StaticVarApiFlags, StaticVarApiImpl,
9 },
10 err_msg,
11 types::{
12 big_num_cmp::bi_gt_zero, BigUint, EgldDecimals, EgldOrEsdtTokenIdentifier,
13 EgldOrEsdtTokenPayment, EgldOrMultiEsdtPayment, EsdtTokenPayment, ManagedDecimal,
14 ManagedRef, ManagedType, ManagedVec, ManagedVecItem, ManagedVecItemPayload,
15 ManagedVecPayloadIterator, ManagedVecRef, TokenIdentifier,
16 },
17};
18
19#[derive(Default)]
20pub struct CallValueWrapper<A>
21where
22 A: CallValueApi + ErrorApi + ManagedTypeApi,
23{
24 _phantom: PhantomData<A>,
25}
26
27impl<A> CallValueWrapper<A>
28where
29 A: CallValueApi + ErrorApi + ManagedTypeApi,
30{
31 pub fn new() -> Self {
32 CallValueWrapper {
33 _phantom: PhantomData,
34 }
35 }
36
37 fn all_esdt_transfers_unchecked(&self) -> A::ManagedBufferHandle {
39 let all_transfers_unchecked_handle: A::ManagedBufferHandle =
40 use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT);
41 if !A::static_var_api_impl()
42 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ESDT_UNCHECKED_INITIALIZED)
43 {
44 A::call_value_api_impl()
45 .load_all_esdt_transfers(all_transfers_unchecked_handle.clone());
46 }
47 all_transfers_unchecked_handle
48 }
49
50 pub fn egld_direct_non_strict(&self) -> ManagedRef<'static, A, BigUint<A>> {
54 let call_value_handle: A::BigIntHandle = use_raw_handle(const_handles::CALL_VALUE_EGLD);
55 if !A::static_var_api_impl()
56 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_DIRECT_INITIALIZED)
57 {
58 A::call_value_api_impl().load_egld_value(call_value_handle.clone());
59 }
60 unsafe { ManagedRef::wrap_handle(call_value_handle) }
61 }
62
63 pub fn egld(&self) -> ManagedRef<'static, A, BigUint<A>> {
69 let esdt_transfers_handle = self.all_esdt_transfers_unchecked();
70 let esdt_transfers: ManagedRef<'static, A, ManagedVec<A, EgldOrEsdtTokenPayment<A>>> =
71 unsafe { ManagedRef::wrap_handle(esdt_transfers_handle) };
72 match esdt_transfers.len() {
73 0 => self.egld_direct_non_strict(),
74 1 => {
75 let first = esdt_transfers.get(0);
76 if !first.token_identifier.is_egld() {
77 A::error_api_impl().signal_error(err_msg::NON_PAYABLE_FUNC_ESDT.as_bytes());
78 }
79 unsafe { ManagedRef::wrap_handle(first.amount.get_handle()) }
80 },
81 _ => A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_TRANSFERS.as_bytes()),
82 }
83 }
84
85 #[deprecated(
97 since = "0.55.0",
98 note = "Does not cover multi-transfer scenarios properly, but left for backwards compatibility. Please use .egld() instead!"
99 )]
100 pub fn egld_value(&self) -> ManagedRef<'static, A, BigUint<A>> {
101 self.egld_direct_non_strict()
102 }
103
104 pub fn egld_decimal(&self) -> ManagedDecimal<A, EgldDecimals> {
106 ManagedDecimal::<A, EgldDecimals>::const_decimals_from_raw(self.egld_value().clone())
107 }
108
109 pub fn all_esdt_transfers(&self) -> ManagedRef<'static, A, ManagedVec<A, EsdtTokenPayment<A>>> {
114 let multi_esdt_handle: A::ManagedBufferHandle = self.all_esdt_transfers_unchecked();
115 let checked = A::static_var_api_impl()
116 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ESDT_INITIALIZED);
117 if !checked && egld_000000_transfer_exists::<A>(multi_esdt_handle.clone()) {
118 A::error_api_impl().signal_error(err_msg::ESDT_UNEXPECTED_EGLD.as_bytes())
119 }
120
121 unsafe { ManagedRef::wrap_handle(multi_esdt_handle) }
122 }
123
124 pub fn all_transfers(
131 &self,
132 ) -> ManagedRef<'static, A, ManagedVec<A, EgldOrEsdtTokenPayment<A>>> {
133 let all_transfers_handle: A::ManagedBufferHandle =
134 use_raw_handle(const_handles::CALL_VALUE_ALL);
135 if !A::static_var_api_impl()
136 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED)
137 {
138 let egld_single = self.egld_direct_non_strict();
139 if bi_gt_zero::<A>(egld_single.get_handle()) {
140 A::managed_type_impl().mb_overwrite(
141 use_raw_handle(const_handles::MBUF_EGLD_000000),
142 EGLD_000000_TOKEN_IDENTIFIER.as_bytes(),
143 );
144 A::managed_type_impl().mb_overwrite(
145 all_transfers_handle.clone(),
146 &const_handles::EGLD_PAYMENT_PAYLOAD[..],
147 );
148 } else {
149 let all_transfers_unchecked_handle = self.all_esdt_transfers_unchecked();
151 A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);
152 A::managed_type_impl()
153 .mb_append(all_transfers_handle.clone(), all_transfers_unchecked_handle);
154 }
155 }
156 unsafe { ManagedRef::wrap_handle(all_transfers_handle) }
157 }
158
159 pub fn multi_esdt<const N: usize>(&self) -> [ManagedVecRef<'static, EsdtTokenPayment<A>>; N] {
167 let esdt_transfers = self.all_esdt_transfers();
168 let array = esdt_transfers.to_array_of_refs::<N>().unwrap_or_else(|| {
169 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes())
170 });
171 unsafe { core::mem::transmute(array) }
172 }
173
174 pub fn multi_egld_or_esdt<const N: usize>(
180 &self,
181 ) -> [ManagedVecRef<'static, EgldOrEsdtTokenPayment<A>>; N] {
182 let esdt_transfers = self.all_transfers();
183 let array = esdt_transfers.to_array_of_refs::<N>().unwrap_or_else(|| {
184 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_TRANSFERS.as_bytes())
185 });
186 unsafe { core::mem::transmute(array) }
187 }
188
189 pub fn single_esdt(&self) -> ManagedVecRef<'static, EsdtTokenPayment<A>> {
195 let esdt_transfers = self.all_esdt_transfers();
196 if esdt_transfers.len() != 1 {
197 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes())
198 }
199 let value = esdt_transfers.get(0);
200 unsafe { core::mem::transmute(value) }
201 }
202
203 pub fn single_fungible_esdt(
209 &self,
210 ) -> (
211 ManagedRef<'static, A, TokenIdentifier<A>>,
212 ManagedRef<'static, A, BigUint<A>>,
213 ) {
214 let payment = self.single_esdt();
215 if payment.token_nonce != 0 {
216 A::error_api_impl().signal_error(err_msg::FUNGIBLE_TOKEN_EXPECTED_ERR_MSG.as_bytes());
217 }
218
219 unsafe {
220 (
221 ManagedRef::wrap_handle(payment.token_identifier.get_handle()),
222 ManagedRef::wrap_handle(payment.amount.get_handle()),
223 )
224 }
225 }
226
227 pub fn egld_or_single_esdt(&self) -> EgldOrEsdtTokenPayment<A> {
233 let esdt_transfers_handle = self.all_esdt_transfers_unchecked();
234 let esdt_transfers: ManagedRef<'static, A, ManagedVec<A, EgldOrEsdtTokenPayment<A>>> =
235 unsafe { ManagedRef::wrap_handle(esdt_transfers_handle) };
236 match esdt_transfers.len() {
237 0 => EgldOrEsdtTokenPayment {
238 token_identifier: EgldOrEsdtTokenIdentifier::egld(),
239 token_nonce: 0,
240 amount: self.egld_direct_non_strict().clone(),
241 },
242 1 => esdt_transfers.get(0).clone(),
243 _ => A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes()),
244 }
245 }
246
247 pub fn egld_or_single_fungible_esdt(&self) -> (EgldOrEsdtTokenIdentifier<A>, BigUint<A>) {
256 let payment = self.egld_or_single_esdt();
257 if payment.token_nonce != 0 {
258 A::error_api_impl().signal_error(err_msg::FUNGIBLE_TOKEN_EXPECTED_ERR_MSG.as_bytes());
259 }
260
261 (payment.token_identifier, payment.amount)
262 }
263
264 pub fn any_payment(&self) -> EgldOrMultiEsdtPayment<A> {
268 let esdt_transfers = self.all_esdt_transfers();
269 if esdt_transfers.is_empty() {
270 EgldOrMultiEsdtPayment::Egld(self.egld_direct_non_strict().clone())
271 } else {
272 EgldOrMultiEsdtPayment::MultiEsdt(esdt_transfers.clone())
273 }
274 }
275}
276
277fn egld_000000_transfer_exists<A>(transfers_vec_handle: A::ManagedBufferHandle) -> bool
278where
279 A: CallValueApi + ErrorApi + ManagedTypeApi,
280{
281 A::managed_type_impl().mb_overwrite(
282 use_raw_handle(const_handles::MBUF_EGLD_000000),
283 EGLD_000000_TOKEN_IDENTIFIER.as_bytes(),
284 );
285 unsafe {
286 let mut iter: ManagedVecPayloadIterator<
287 A,
288 <EsdtTokenPayment<A> as ManagedVecItem>::PAYLOAD,
289 > = ManagedVecPayloadIterator::new(transfers_vec_handle);
290
291 iter.any(|payload| {
292 let token_identifier_handle = RawHandle::read_from_payload(payload.slice_unchecked(0));
293 A::managed_type_impl().mb_eq(
294 use_raw_handle(const_handles::MBUF_EGLD_000000),
295 use_raw_handle(token_identifier_handle),
296 )
297 })
298 }
299}