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;