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 BigUint, EgldDecimals, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment,
13 EgldOrMultiEsdtPayment, EsdtTokenPayment, ManagedDecimal, ManagedRef, ManagedType,
14 ManagedVec, ManagedVecItem, ManagedVecItemPayload, ManagedVecPayloadIterator,
15 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 all_transfers = self.all_transfers();
70 match all_transfers.len() {
71 0 => {
72 use crate::api::BigIntApiImpl;
73
74 let call_value_handle: A::BigIntHandle =
75 use_raw_handle(const_handles::CALL_VALUE_EGLD);
76 A::managed_type_impl().bi_set_int64(call_value_handle.clone(), 0);
77 unsafe { ManagedRef::wrap_handle(call_value_handle) }
78 }
79 1 => {
80 let first = all_transfers.get(0);
81 if !first.token_identifier.is_egld() {
82 A::error_api_impl().signal_error(err_msg::NON_PAYABLE_FUNC_ESDT.as_bytes());
83 }
84 unsafe { ManagedRef::wrap_handle(first.amount.get_handle()) }
85 }
86 _ => A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_TRANSFERS.as_bytes()),
87 }
88 }
89
90 #[deprecated(
102 since = "0.55.0",
103 note = "Does not cover multi-transfer scenarios properly, but left for backwards compatibility. Please use .egld() instead!"
104 )]
105 pub fn egld_value(&self) -> ManagedRef<'static, A, BigUint<A>> {
106 self.egld_direct_non_strict()
107 }
108
109 pub fn egld_decimal(&self) -> ManagedDecimal<A, EgldDecimals> {
111 ManagedDecimal::<A, EgldDecimals>::const_decimals_from_raw(self.egld_value().clone())
112 }
113
114 pub fn all_esdt_transfers(&self) -> ManagedRef<'static, A, ManagedVec<A, EsdtTokenPayment<A>>> {
121 let multi_esdt_handle: A::ManagedBufferHandle = self.all_esdt_transfers_unchecked();
122 let checked = A::static_var_api_impl()
123 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ESDT_INITIALIZED);
124 if !checked && egld_000000_transfer_exists::<A>(multi_esdt_handle.clone()) {
125 A::error_api_impl().signal_error(err_msg::ESDT_UNEXPECTED_EGLD.as_bytes())
126 }
127
128 unsafe { ManagedRef::wrap_handle(multi_esdt_handle) }
129 }
130
131 pub fn all_transfers(
138 &self,
139 ) -> ManagedRef<'static, A, ManagedVec<A, EgldOrEsdtTokenPayment<A>>> {
140 let all_transfers_handle: A::ManagedBufferHandle =
141 use_raw_handle(const_handles::CALL_VALUE_ALL);
142 if !A::static_var_api_impl()
143 .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED)
144 {
145 A::call_value_api_impl().load_all_transfers(all_transfers_handle.clone());
146 }
147 unsafe { ManagedRef::wrap_handle(all_transfers_handle) }
148 }
149
150 pub fn multi_esdt<const N: usize>(&self) -> [ManagedVecRef<'static, EsdtTokenPayment<A>>; N] {
158 let esdt_transfers = self.all_esdt_transfers();
159 let array = esdt_transfers.to_array_of_refs::<N>().unwrap_or_else(|| {
160 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes())
161 });
162 unsafe { core::mem::transmute(array) }
163 }
164
165 pub fn multi_egld_or_esdt<const N: usize>(
171 &self,
172 ) -> [ManagedVecRef<'static, EgldOrEsdtTokenPayment<A>>; N] {
173 let esdt_transfers = self.all_transfers();
174 let array = esdt_transfers.to_array_of_refs::<N>().unwrap_or_else(|| {
175 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_TRANSFERS.as_bytes())
176 });
177 unsafe { core::mem::transmute(array) }
178 }
179
180 pub fn single_esdt(&self) -> ManagedVecRef<'static, EsdtTokenPayment<A>> {
186 let esdt_transfers = self.all_esdt_transfers();
187 if esdt_transfers.len() != 1 {
188 A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes())
189 }
190 let value = esdt_transfers.get(0);
191 unsafe { core::mem::transmute(value) }
192 }
193
194 pub fn single_fungible_esdt(
200 &self,
201 ) -> (
202 ManagedRef<'static, A, TokenIdentifier<A>>,
203 ManagedRef<'static, A, BigUint<A>>,
204 ) {
205 let payment = self.single_esdt();
206 if payment.token_nonce != 0 {
207 A::error_api_impl().signal_error(err_msg::FUNGIBLE_TOKEN_EXPECTED_ERR_MSG.as_bytes());
208 }
209
210 unsafe {
211 (
212 ManagedRef::wrap_handle(payment.token_identifier.get_handle()),
213 ManagedRef::wrap_handle(payment.amount.get_handle()),
214 )
215 }
216 }
217
218 pub fn egld_or_single_esdt(&self) -> EgldOrEsdtTokenPayment<A> {
224 let esdt_transfers_handle = self.all_esdt_transfers_unchecked();
225 let esdt_transfers: ManagedRef<'static, A, ManagedVec<A, EgldOrEsdtTokenPayment<A>>> =
226 unsafe { ManagedRef::wrap_handle(esdt_transfers_handle) };
227 match esdt_transfers.len() {
228 0 => EgldOrEsdtTokenPayment {
229 token_identifier: EgldOrEsdtTokenIdentifier::egld(),
230 token_nonce: 0,
231 amount: self.egld_direct_non_strict().clone(),
232 },
233 1 => esdt_transfers.get(0).clone(),
234 _ => A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes()),
235 }
236 }
237
238 pub fn egld_or_single_fungible_esdt(&self) -> (EgldOrEsdtTokenIdentifier<A>, BigUint<A>) {
247 let payment = self.egld_or_single_esdt();
248 if payment.token_nonce != 0 {
249 A::error_api_impl().signal_error(err_msg::FUNGIBLE_TOKEN_EXPECTED_ERR_MSG.as_bytes());
250 }
251
252 (payment.token_identifier, payment.amount)
253 }
254
255 pub fn any_payment(&self) -> EgldOrMultiEsdtPayment<A> {
259 let esdt_transfers = self.all_esdt_transfers();
260 if esdt_transfers.is_empty() {
261 EgldOrMultiEsdtPayment::Egld(self.egld_direct_non_strict().clone())
262 } else {
263 EgldOrMultiEsdtPayment::MultiEsdt(esdt_transfers.clone())
264 }
265 }
266}
267
268fn egld_000000_transfer_exists<A>(transfers_vec_handle: A::ManagedBufferHandle) -> bool
269where
270 A: CallValueApi + ErrorApi + ManagedTypeApi,
271{
272 A::managed_type_impl().mb_overwrite(
273 use_raw_handle(const_handles::MBUF_EGLD_000000),
274 EGLD_000000_TOKEN_IDENTIFIER.as_bytes(),
275 );
276 unsafe {
277 let mut iter: ManagedVecPayloadIterator<
278 A,
279 <EsdtTokenPayment<A> as ManagedVecItem>::PAYLOAD,
280 > = ManagedVecPayloadIterator::new(transfers_vec_handle);
281
282 iter.any(|payload| {
283 let token_identifier_handle = RawHandle::read_from_payload(payload.slice_unchecked(0));
284 A::managed_type_impl().mb_eq(
285 use_raw_handle(const_handles::MBUF_EGLD_000000),
286 use_raw_handle(token_identifier_handle),
287 )
288 })
289 }
290}