diff --git a/framework/base/src/api/managed_types/const_handles.rs b/framework/base/src/api/managed_types/const_handles.rs
index 6d990f9c6e..ccf4e9a06c 100644
--- a/framework/base/src/api/managed_types/const_handles.rs
+++ b/framework/base/src/api/managed_types/const_handles.rs
@@ -7,26 +7,27 @@ pub const UNINITIALIZED_HANDLE: RawHandle = i32::MAX;
/// WARNING! With the current VM this still needs to be initialized before use.
pub const BIG_INT_CONST_ZERO: RawHandle = -10;
-
-pub const CALL_VALUE_EGLD: RawHandle = -11;
-pub const CALL_VALUE_SINGLE_ESDT: RawHandle = -13;
-
-pub const BIG_INT_TEMPORARY_1: RawHandle = -14;
-pub const BIG_INT_TEMPORARY_2: RawHandle = -15;
-pub const BIG_FLOAT_TEMPORARY: RawHandle = -16;
+pub const BIG_INT_TEMPORARY_1: RawHandle = -11;
+pub const BIG_INT_TEMPORARY_2: RawHandle = -12;
+pub const BIG_FLOAT_TEMPORARY: RawHandle = -15;
/// WARNING! With the current VM this still needs to be initialized before use.
pub const MBUF_CONST_EMPTY: RawHandle = -20;
-pub const CALL_VALUE_MULTI_ESDT: RawHandle = -21;
-pub const CALL_VALUE_SINGLE_ESDT_TOKEN_NAME: RawHandle = -22;
-pub const CALLBACK_CLOSURE_ARGS_BUFFER: RawHandle = -23;
pub const MBUF_TEMPORARY_1: RawHandle = -25;
pub const MBUF_TEMPORARY_2: RawHandle = -26;
-pub const MBUF_EGLD_000000: RawHandle = -27;
pub const ADDRESS_CALLER: RawHandle = -30;
pub const ADDRESS_SELF: RawHandle = -31;
+pub const CALL_VALUE_EGLD: RawHandle = -35;
+pub const CALL_VALUE_EGLD_MULTI: RawHandle = -36;
+pub const CALL_VALUE_EGLD_FROM_ESDT: RawHandle = -37;
+pub const CALL_VALUE_MULTI_ESDT: RawHandle = -38;
+pub const CALL_VALUE_ALL: RawHandle = -39;
+pub const MBUF_EGLD_000000: RawHandle = -40;
+
+pub const CALLBACK_CLOSURE_ARGS_BUFFER: RawHandle = -50;
+
pub const NEW_HANDLE_START_FROM: RawHandle = -200; // > -100 reserved for APIs
// Vec of 64 entries of 1 bit
@@ -40,3 +41,37 @@ pub const fn get_scaling_factor_handle(decimals: usize) -> i32 {
let decimals_i32 = decimals as i32;
SCALING_FACTOR_START - decimals_i32
}
+
+/// Payload of the singleton ManagedVec that contains the current single EGLD transfer, modelled as an ESDT payment.
+pub const EGLD_PAYMENT_PAYLOAD: [u8; 16] = [
+ 0xff,
+ 0xff,
+ 0xff,
+ (0x0100 + MBUF_EGLD_000000) as u8,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0xff,
+ 0xff,
+ 0xff,
+ (0x0100 + CALL_VALUE_EGLD) as u8,
+];
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn egld_payment_payload_test() {
+ let mut bytes = [0u8; 4];
+ bytes.copy_from_slice(&EGLD_PAYMENT_PAYLOAD[0..4]);
+ assert_eq!(i32::from_be_bytes(bytes), MBUF_EGLD_000000);
+ bytes.copy_from_slice(&EGLD_PAYMENT_PAYLOAD[12..16]);
+ assert_eq!(i32::from_be_bytes(bytes), CALL_VALUE_EGLD);
+ }
+}
diff --git a/framework/base/src/api/managed_types/static_var_api_flags.rs b/framework/base/src/api/managed_types/static_var_api_flags.rs
index 1c9e153e69..2040d8acf3 100644
--- a/framework/base/src/api/managed_types/static_var_api_flags.rs
+++ b/framework/base/src/api/managed_types/static_var_api_flags.rs
@@ -3,11 +3,12 @@ use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StaticVarApiFlags: u8 {
- const NONE = 0b00000000;
- const CALL_VALUE_EGLD_INITIALIZED = 0b00000001;
- const CALL_VALUE_EGLD_MULTI_INITIALIZED = 0b00000010;
- const CALL_VALUE_MULTI_ESDT_INITIALIZED = 0b00000100;
- const CALL_VALUE_ALL_INITIALIZED = 0b00001000;
+ const NONE = 0b00000000;
+ const CALL_VALUE_EGLD_SINGLE_INITIALIZED = 0b00000001;
+ const CALL_VALUE_ESDT_UNCHECKED_INITIALIZED = 0b00000010;
+ const CALL_VALUE_EGLD_MULTI_INITIALIZED = 0b00000100;
+ const CALL_VALUE_EGLD_FROM_ESDT_INITIALIZED = 0b00001000;
+ const CALL_VALUE_ALL_INITIALIZED = 0b00010000;
}
}
@@ -32,21 +33,27 @@ pub mod tests {
assert!(current.check_and_set(StaticVarApiFlags::NONE));
assert_eq!(current, StaticVarApiFlags::NONE);
- assert!(!current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED));
- assert_eq!(current, StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED);
- assert!(current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED));
- assert_eq!(current, StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED);
+ assert!(!current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED));
+ assert_eq!(
+ current,
+ StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED
+ );
+ assert!(current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED));
+ assert_eq!(
+ current,
+ StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED
+ );
assert!(!current.check_and_set(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED));
assert_eq!(
current,
- StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED
+ StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED
| StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED
);
assert!(current.check_and_set(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED));
assert_eq!(
current,
- StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED
+ StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED
| StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED
);
}
diff --git a/framework/base/src/contract_base/wrappers/call_value_wrapper.rs b/framework/base/src/contract_base/wrappers/call_value_wrapper.rs
index 5fdfc795e7..7a1743b2e0 100644
--- a/framework/base/src/contract_base/wrappers/call_value_wrapper.rs
+++ b/framework/base/src/contract_base/wrappers/call_value_wrapper.rs
@@ -3,15 +3,14 @@ use core::marker::PhantomData;
use crate::{
api::{
const_handles, use_raw_handle, CallValueApi, CallValueApiImpl, ErrorApi, ErrorApiImpl,
- HandleConstraints, ManagedBufferApiImpl, ManagedTypeApi, RawHandle, StaticVarApiFlags,
- StaticVarApiImpl,
+ ManagedBufferApiImpl, ManagedTypeApi, RawHandle, StaticVarApiFlags, StaticVarApiImpl,
},
err_msg,
types::{
- BigUint, ConstDecimals, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment,
- EgldOrMultiEsdtPayment, EsdtTokenPayment, ManagedDecimal, ManagedRef, ManagedType,
- ManagedVec, ManagedVecItem, ManagedVecItemPayload, ManagedVecPayloadIterator,
- ManagedVecRef, TokenIdentifier, EGLD_000000_TOKEN_IDENTIFIER,
+ big_num_cmp::bi_gt_zero, BigInt, BigUint, ConstDecimals, EgldOrEsdtTokenIdentifier,
+ EgldOrEsdtTokenPayment, EgldOrMultiEsdtPayment, EsdtTokenPayment, ManagedDecimal,
+ ManagedRef, ManagedType, ManagedVec, ManagedVecItem, ManagedVecItemPayload,
+ ManagedVecPayloadIterator, ManagedVecRef, TokenIdentifier, EGLD_000000_TOKEN_IDENTIFIER,
},
};
@@ -33,12 +32,47 @@ where
}
}
+ /// Cached transfers from the VM.
+ fn all_esdt_transfers_unchecked(&self) -> A::ManagedBufferHandle {
+ let all_transfers_unchecked_handle: A::ManagedBufferHandle =
+ use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT);
+ if !A::static_var_api_impl()
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ESDT_UNCHECKED_INITIALIZED)
+ {
+ A::call_value_api_impl()
+ .load_all_esdt_transfers(all_transfers_unchecked_handle.clone());
+ }
+ all_transfers_unchecked_handle
+ }
+
+ /// Cached egld transfer searched for in the ESDT transfers from the VM.
+ fn egld_from_multi_esdt(&self) -> A::BigIntHandle {
+ let egld_from_multi_esdt_handle: A::BigIntHandle =
+ use_raw_handle(const_handles::CALL_VALUE_EGLD_FROM_ESDT);
+ if !A::static_var_api_impl()
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_FROM_ESDT_INITIALIZED)
+ {
+ let all_transfers_unchecked_handle = self.all_esdt_transfers_unchecked();
+ let egld_handle_result = find_egld_000000_transfer::(all_transfers_unchecked_handle);
+ if let Some(found_egld_handle) = egld_handle_result {
+ BigInt::::clone_to_handle(
+ use_raw_handle(found_egld_handle),
+ egld_from_multi_esdt_handle.clone(),
+ );
+ } else {
+ BigInt::::set_value(egld_from_multi_esdt_handle.clone(), 0);
+ }
+ }
+ egld_from_multi_esdt_handle
+ }
+
/// Retrieves the EGLD call value from the VM.
- /// Will return 0 in case of an ESDT transfer (cannot have both EGLD and ESDT transfer simultaneously).
+ ///
+ /// Will return 0 in case of an ESDT transfer, even though EGLD and ESDT transfers are now posible.
pub fn egld_value(&self) -> ManagedRef<'static, A, BigUint> {
let call_value_handle: A::BigIntHandle = use_raw_handle(const_handles::CALL_VALUE_EGLD);
if !A::static_var_api_impl()
- .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED)
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_SINGLE_INITIALIZED)
{
A::call_value_api_impl().load_egld_value(call_value_handle.clone());
}
@@ -52,23 +86,82 @@ where
)
}
+ /// The quantity of EGLD transfered, either via simple EGLD transfer, or via ESDT multi-transfer.
+ pub fn egld_value_multi(&self) -> ManagedRef<'static, A, BigUint> {
+ let egld_value_multi_handle: A::BigIntHandle =
+ use_raw_handle(const_handles::CALL_VALUE_EGLD_MULTI);
+ if !A::static_var_api_impl()
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_MULTI_INITIALIZED)
+ {
+ let egld_single = self.egld_value();
+ if bi_gt_zero::(egld_single.get_handle()) {
+ BigInt::::clone_to_handle(
+ egld_single.get_handle(),
+ egld_value_multi_handle.clone(),
+ );
+ } else {
+ let egld_from_multi_esdt_handle = self.egld_from_multi_esdt();
+ BigInt::::clone_to_handle(
+ egld_from_multi_esdt_handle,
+ egld_value_multi_handle.clone(),
+ );
+ }
+ }
+ unsafe { ManagedRef::wrap_handle(egld_value_multi_handle) }
+ }
+
/// Returns all ESDT transfers that accompany this SC call.
/// Will return 0 results if nothing was transfered, or just EGLD.
- /// Fully managed underlying types, very efficient.
+ ///
+ /// Will crash for EGLD + ESDT multi transfers.
pub fn all_esdt_transfers(&self) -> ManagedRef<'static, A, ManagedVec>> {
- let call_value_handle = load_all_transfers::();
-
- let egld_payment = find_egld_000000_transfer::(call_value_handle.clone());
- if egld_payment.is_some() {
- A::error_api_impl().signal_error(err_msg::ESDT_UNEXPECTED_EGLD.as_bytes())
+ let multi_esdt_handle: A::ManagedBufferHandle =
+ use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT);
+ if !A::static_var_api_impl()
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ESDT_UNCHECKED_INITIALIZED)
+ {
+ let egld_value_multi_handle = self.egld_from_multi_esdt();
+ if bi_gt_zero::(egld_value_multi_handle) {
+ A::error_api_impl().signal_error(err_msg::ESDT_UNEXPECTED_EGLD.as_bytes())
+ }
}
- unsafe { ManagedRef::wrap_handle(call_value_handle) }
+
+ unsafe { ManagedRef::wrap_handle(multi_esdt_handle) }
}
+ /// Will return all transfers in the form of a list of EgldOrEsdtTokenPayment.
+ ///
+ /// Both EGLD and ESDT can be returned.
+ ///
+ /// In case of a single EGLD transfer, only one item will be returned,
+ /// the EGLD payment represented as an ESDT transfer (EGLD-000000).
pub fn all_transfers(
&self,
) -> ManagedRef<'static, A, ManagedVec>> {
- let (_, all_transfers_handle) = load_all_call_data::();
+ let all_transfers_handle: A::ManagedBufferHandle =
+ use_raw_handle(const_handles::CALL_VALUE_ALL);
+ if !A::static_var_api_impl()
+ .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED)
+ {
+ let egld_single = self.egld_value();
+ if bi_gt_zero::(egld_single.get_handle()) {
+ A::managed_type_impl().mb_overwrite(
+ use_raw_handle(const_handles::MBUF_EGLD_000000),
+ EGLD_000000_TOKEN_IDENTIFIER.as_bytes(),
+ );
+ let _ = A::managed_type_impl().mb_set_slice(
+ all_transfers_handle.clone(),
+ 0,
+ &const_handles::EGLD_PAYMENT_PAYLOAD[..],
+ );
+ } else {
+ // clone all_esdt_transfers_unchecked -> all_transfers
+ let all_transfers_unchecked_handle = self.all_esdt_transfers_unchecked();
+ let _ = A::managed_type_impl().mb_set_slice(all_transfers_handle.clone(), 0, &[]);
+ A::managed_type_impl()
+ .mb_append(all_transfers_handle.clone(), all_transfers_unchecked_handle);
+ }
+ }
unsafe { ManagedRef::wrap_handle(all_transfers_handle) }
}
@@ -129,14 +222,16 @@ where
///
/// In case no transfer of value happen, it will return a payment of 0 EGLD.
pub fn egld_or_single_esdt(&self) -> EgldOrEsdtTokenPayment {
- let esdt_transfers = self.all_esdt_transfers();
+ let esdt_transfers_handle = self.all_esdt_transfers_unchecked();
+ let esdt_transfers: ManagedRef<'static, A, ManagedVec>> =
+ unsafe { ManagedRef::wrap_handle(esdt_transfers_handle) };
match esdt_transfers.len() {
0 => EgldOrEsdtTokenPayment {
token_identifier: EgldOrEsdtTokenIdentifier::egld(),
token_nonce: 0,
amount: self.egld_value().clone_value(),
},
- 1 => esdt_transfers.get(0).clone().into(),
+ 1 => esdt_transfers.get(0).clone(),
_ => A::error_api_impl().signal_error(err_msg::INCORRECT_NUM_ESDT_TRANSFERS.as_bytes()),
}
}
@@ -171,22 +266,6 @@ where
}
}
-fn load_all_transfers() -> A::ManagedBufferHandle
-where
- A: CallValueApi + ErrorApi + ManagedTypeApi,
-{
- // let mut all_transfers_handle: A::ManagedBufferHandle =
- // use_raw_handle(A::static_var_api_impl().get_call_value_multi_esdt_handle());
- // if all_transfers_handle == const_handles::UNINITIALIZED_HANDLE {
- // all_transfers_handle = use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT);
- // A::static_var_api_impl()
- // .set_call_value_multi_esdt_handle(all_transfers_handle.get_raw_handle());
- // A::call_value_api_impl().load_all_esdt_transfers(all_transfers_handle.clone());
- // }
- // all_transfers_handle
- todo!()
-}
-
fn find_egld_000000_transfer(transfers_vec_handle: A::ManagedBufferHandle) -> Option
where
A: CallValueApi + ErrorApi + ManagedTypeApi,
@@ -217,25 +296,3 @@ where
egld_payload.map(|payload| RawHandle::read_from_payload(payload.slice_unchecked(12)))
}
}
-
-fn load_all_call_data() -> (A::BigIntHandle, A::ManagedBufferHandle)
-where
- A: CallValueApi + ErrorApi + ManagedTypeApi,
-{
- // let all_transfers_handle = load_all_transfers::();
- // let mut egld_amount_handle: A::BigIntHandle =
- // use_raw_handle(A::static_var_api_impl().get_call_value_egld_handle());
- // if egld_amount_handle == const_handles::UNINITIALIZED_HANDLE {
- // let egld_payment = find_egld_000000_transfer::(all_transfers_handle.clone());
- // if let Some(egld_amount_raw_handle) = egld_payment {
- // egld_amount_handle = use_raw_handle(egld_amount_raw_handle);
- // } else {
- // egld_amount_handle = use_raw_handle(const_handles::CALL_VALUE_EGLD);
- // A::call_value_api_impl().load_egld_value(egld_amount_handle.clone());
- // }
- // A::static_var_api_impl().set_call_value_egld_handle(egld_amount_handle.get_raw_handle());
- // }
-
- // (egld_amount_handle, all_transfers_handle)
- todo!()
-}
diff --git a/framework/base/src/types/managed/basic/big_num_cmp.rs b/framework/base/src/types/managed/basic/big_num_cmp.rs
index c5ce6da5a0..dcb3bc6c49 100644
--- a/framework/base/src/types/managed/basic/big_num_cmp.rs
+++ b/framework/base/src/types/managed/basic/big_num_cmp.rs
@@ -4,7 +4,7 @@ use crate::api::{const_handles, BigIntApiImpl, ManagedTypeApi};
use super::BigInt;
-pub(crate) fn bi_cmp_0(bi_handle: M::BigIntHandle) -> Ordering
+pub(crate) fn bi_cmp_zero(bi_handle: M::BigIntHandle) -> Ordering
where
M: ManagedTypeApi,
{
@@ -15,13 +15,20 @@ where
}
}
+pub(crate) fn bi_gt_zero(bi_handle: M::BigIntHandle) -> bool
+where
+ M: ManagedTypeApi,
+{
+ bi_cmp_zero::(bi_handle) == Ordering::Greater
+}
+
pub(crate) fn bi_cmp_i64(bi_handle: M::BigIntHandle, other: i64) -> Ordering
where
M: ManagedTypeApi,
{
let api = M::managed_type_impl();
if other == 0 {
- bi_cmp_0::(bi_handle)
+ bi_cmp_zero::(bi_handle)
} else {
let big_int_temp_1 = BigInt::::make_temp(const_handles::BIG_INT_TEMPORARY_1, other);
api.bi_cmp(bi_handle, big_int_temp_1)
diff --git a/framework/base/src/types/managed/basic/mod.rs b/framework/base/src/types/managed/basic/mod.rs
index ef10f15b5e..253adc0fb8 100644
--- a/framework/base/src/types/managed/basic/mod.rs
+++ b/framework/base/src/types/managed/basic/mod.rs
@@ -5,7 +5,7 @@ mod big_int;
mod big_int_cmp;
mod big_int_operators;
mod big_int_sign;
-mod big_num_cmp;
+pub(crate) mod big_num_cmp;
pub(crate) mod cast_to_i64;
mod elliptic_curve;
mod managed_buffer;