Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions framework/base/src/contract_base/contract_base_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ pub trait ContractBase: Sized {
/// Gateway into the call value retrieval functionality.
/// The payment annotations should normally be the ones to handle this,
/// but the developer is also given direct access to the API.
fn call_value(&self) -> CallValueWrapper<Self::Api> {
CallValueWrapper::new()
}
fn call_value(&self) -> CallValueWrapper<Self::Api>;

/// Gateway to the functionality related to sending transactions from the current contract.
#[inline]
Expand Down
29 changes: 26 additions & 3 deletions framework/base/src/contract_base/universal_contract_obj.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
use core::marker::PhantomData;
use core::{cell::UnsafeCell, marker::PhantomData};

use crate::api::VMApi;
use crate::api::{const_handles, RawHandle, VMApi};

use super::ContractBase;
use super::{CallValueWrapper, ContractBase};

pub struct ContractObjData {
pub call_value_egld_handle: RawHandle,
pub call_value_multi_esdt_handle: RawHandle,
}

impl Default for ContractObjData {
fn default() -> Self {
ContractObjData {
call_value_egld_handle: const_handles::UNINITIALIZED_HANDLE,
call_value_multi_esdt_handle: const_handles::UNINITIALIZED_HANDLE,
}
}
}

/// A unique empty structure that automatically implements all smart contract traits.
///
Expand All @@ -18,15 +32,20 @@ where
A: VMApi,
{
_phantom: PhantomData<A>,
pub data: UnsafeCell<ContractObjData>,
}

unsafe impl<A> Sync for UniversalContractObj<A> where A: VMApi {}
unsafe impl<A> Send for UniversalContractObj<A> where A: VMApi {}

impl<A> UniversalContractObj<A>
where
A: VMApi,
{
pub fn new() -> Self {
Self {
_phantom: PhantomData,
data: UnsafeCell::new(ContractObjData::default()),
}
}
}
Expand All @@ -45,4 +64,8 @@ where
A: VMApi,
{
type Api = A;

fn call_value(&self) -> CallValueWrapper<'_, Self::Api> {
CallValueWrapper::new(&self.data)
}
}
40 changes: 19 additions & 21 deletions framework/base/src/contract_base/wrappers/call_value_wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use core::marker::PhantomData;
use core::{cell::UnsafeCell, marker::PhantomData};

use crate::{
api::{
const_handles, use_raw_handle, CallValueApi, CallValueApiImpl, ErrorApi, ErrorApiImpl,
HandleConstraints, ManagedTypeApi, StaticVarApiImpl,
ManagedTypeApi,
},
contract_base::ContractObjData,
err_msg,
types::{
BigUint, ConstDecimals, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment,
Expand All @@ -13,35 +14,34 @@ use crate::{
},
};

#[derive(Default)]
pub struct CallValueWrapper<A>
pub struct CallValueWrapper<'a, A>
where
A: CallValueApi + ErrorApi + ManagedTypeApi,
{
_phantom: PhantomData<A>,
pub data_cell: &'a UnsafeCell<ContractObjData>,
}

impl<A> CallValueWrapper<A>
impl<'a, A> CallValueWrapper<'a, A>
where
A: CallValueApi + ErrorApi + ManagedTypeApi,
{
pub fn new() -> Self {
pub fn new(data_cell: &'a UnsafeCell<ContractObjData>) -> Self {
CallValueWrapper {
_phantom: PhantomData,
data_cell,
}
}

/// 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).
pub fn egld_value(&self) -> ManagedRef<'static, A, BigUint<A>> {
let mut call_value_handle: A::BigIntHandle =
use_raw_handle(A::static_var_api_impl().get_call_value_egld_handle());
if call_value_handle == const_handles::UNINITIALIZED_HANDLE {
call_value_handle = use_raw_handle(const_handles::CALL_VALUE_EGLD);
A::static_var_api_impl().set_call_value_egld_handle(call_value_handle.get_raw_handle());
A::call_value_api_impl().load_egld_value(call_value_handle.clone());
let data = unsafe { &mut *self.data_cell.get() };
if data.call_value_egld_handle == const_handles::UNINITIALIZED_HANDLE {
data.call_value_egld_handle = const_handles::CALL_VALUE_EGLD;
A::call_value_api_impl().load_egld_value(use_raw_handle(data.call_value_egld_handle));
}
unsafe { ManagedRef::wrap_handle(call_value_handle) }
unsafe { ManagedRef::wrap_handle(use_raw_handle(data.call_value_egld_handle)) }
}

/// Returns the EGLD call value from the VM as ManagedDecimal
Expand All @@ -55,15 +55,13 @@ where
/// Will return 0 results if nothing was transfered, or just EGLD.
/// Fully managed underlying types, very efficient.
pub fn all_esdt_transfers(&self) -> ManagedRef<'static, A, ManagedVec<A, EsdtTokenPayment<A>>> {
let mut call_value_handle: A::ManagedBufferHandle =
use_raw_handle(A::static_var_api_impl().get_call_value_multi_esdt_handle());
if call_value_handle == const_handles::UNINITIALIZED_HANDLE {
call_value_handle = use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT);
A::static_var_api_impl()
.set_call_value_multi_esdt_handle(call_value_handle.get_raw_handle());
A::call_value_api_impl().load_all_esdt_transfers(call_value_handle.clone());
let data = unsafe { &mut *self.data_cell.get() };
if data.call_value_multi_esdt_handle == const_handles::UNINITIALIZED_HANDLE {
data.call_value_multi_esdt_handle = const_handles::CALL_VALUE_MULTI_ESDT;
A::call_value_api_impl()
.load_all_esdt_transfers(use_raw_handle(data.call_value_multi_esdt_handle));
}
unsafe { ManagedRef::wrap_handle(call_value_handle) }
unsafe { ManagedRef::wrap_handle(use_raw_handle(data.call_value_multi_esdt_handle)) }
}

/// Verify and casts the received multi ESDT transfer in to an array.
Expand Down
33 changes: 18 additions & 15 deletions framework/base/src/io/call_value_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::{
const_handles, use_raw_handle, CallValueApi, CallValueApiImpl, ErrorApi, ErrorApiImpl,
ManagedBufferApiImpl, ManagedTypeApi,
},
contract_base::CallValueWrapper,
err_msg,
imports::ContractBase,
types::{
BigUint, EgldOrEsdtTokenIdentifier, EsdtTokenPayment, ManagedRef, ManagedType, ManagedVec,
},
Expand Down Expand Up @@ -38,11 +38,12 @@ where
/// Called initially in the generated code whenever `#[payable("<token identifier>")]` annotation is provided.
///
/// Was never really used, expected to be deprecated/removed.
pub fn payable_single_specific_token<A>(expected_tokend_identifier: &str)
pub fn payable_single_specific_token<A, O>(obj: &O, expected_tokend_identifier: &str)
where
A: CallValueApi + ManagedTypeApi + ErrorApi,
O: ContractBase<Api = A>,
{
let transfers = CallValueWrapper::<A>::new().all_esdt_transfers();
let transfers = obj.call_value().all_esdt_transfers();
if transfers.len() != 1 {
A::error_api_impl().signal_error(err_msg::SINGLE_ESDT_EXPECTED.as_bytes());
}
Expand All @@ -62,37 +63,39 @@ where
}

/// Initializes an argument annotated with `#[payment_amount]` or `#[payment]`.
pub fn arg_payment_amount<A>() -> BigUint<A>
pub fn arg_payment_amount<A, O>(obj: &O) -> BigUint<A>
where
A: CallValueApi + ManagedTypeApi,
O: ContractBase<Api = A>,
{
CallValueWrapper::<A>::new().egld_or_single_esdt().amount
obj.call_value().egld_or_single_esdt().amount
}

/// Initializes an argument annotated with `#[payment_token]`.
pub fn arg_payment_token<A>() -> EgldOrEsdtTokenIdentifier<A>
pub fn arg_payment_token<A, O>(obj: &O) -> EgldOrEsdtTokenIdentifier<A>
where
A: CallValueApi + ManagedTypeApi,
O: ContractBase<Api = A>,
{
CallValueWrapper::<A>::new()
.egld_or_single_esdt()
.token_identifier
obj.call_value().egld_or_single_esdt().token_identifier
}

/// Initializes an argument annotated with `#[payment_nonce]`.
pub fn arg_payment_nonce<A>() -> u64
pub fn arg_payment_nonce<A, O>(obj: &O) -> u64
where
A: CallValueApi + ManagedTypeApi,
O: ContractBase<Api = A>,
{
CallValueWrapper::<A>::new()
.egld_or_single_esdt()
.token_nonce
obj.call_value().egld_or_single_esdt().token_nonce
}

/// Initializes an argument annotated with `#[payment_multi]`.
pub fn arg_payment_multi<A>() -> ManagedRef<'static, A, ManagedVec<A, EsdtTokenPayment<A>>>
pub fn arg_payment_multi<A, O>(
obj: &O,
) -> ManagedRef<'static, A, ManagedVec<A, EsdtTokenPayment<A>>>
where
A: CallValueApi + ManagedTypeApi,
O: ContractBase<Api = A>,
{
CallValueWrapper::<A>::new().all_esdt_transfers()
obj.call_value().all_esdt_transfers()
}
4 changes: 2 additions & 2 deletions framework/derive/src/generate/payable_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn call_value_init_snippet(mpm: MethodPayableMetadata) -> proc_macro2::TokenStre
},
MethodPayableMetadata::SingleEsdtToken(token_identifier) => {
quote! {
multiversx_sc::io::call_value_init::payable_single_specific_token::<Self::Api>(#token_identifier);
multiversx_sc::io::call_value_init::payable_single_specific_token::<Self::Api, _>(&*self, #token_identifier);
}
},
MethodPayableMetadata::AnyToken => {
Expand All @@ -51,7 +51,7 @@ fn opt_payment_arg_snippet(
.map(|arg| {
let pat = &arg.pat;
quote! {
let #pat = multiversx_sc::io::call_value_init::#init_fn_name::<Self::Api>();
let #pat = multiversx_sc::io::call_value_init::#init_fn_name::<Self::Api, Self>(&*self);
}
})
.unwrap_or_default()
Expand Down
4 changes: 4 additions & 0 deletions framework/derive/src/generate/snippets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ pub fn impl_contract_base() -> proc_macro2::TokenStream {
A: multiversx_sc::api::VMApi,
{
type Api = A;

fn call_value(&self) -> multiversx_sc::contract_base::CallValueWrapper<'_, Self::Api> {
multiversx_sc::contract_base::CallValueWrapper::new(&self.0.data)
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions framework/scenario/tests/contract_without_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ mod sample_adder {
A: multiversx_sc::api::VMApi,
{
type Api = A;

fn call_value(&self) -> multiversx_sc::contract_base::CallValueWrapper<'_, Self::Api> {
multiversx_sc::contract_base::CallValueWrapper::new(&self.0.data)
}
}

impl<A> super::module_1::AutoImpl for ContractObj<A> where A: multiversx_sc::api::VMApi {}
Expand Down
Loading