diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index aa0c837fde..519c71158d 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -188,16 +188,17 @@ where } /// Sends a single ESDT transfer to target address. - #[inline] - #[allow(clippy::too_many_arguments)] pub fn direct_esdt( &self, to: &ManagedAddress, token_identifier: &TokenIdentifier, - nonce: u64, + token_nonce: u64, amount: &BigUint, ) { - self.direct_esdt_with_gas_limit(to, token_identifier, nonce, amount, 0, Empty, &[]); + Tx::new_tx_from_sc() + .to(to) + .esdt_refs(token_identifier, token_nonce, amount) + .transfer(); } /// Sends a single ESDT transfer to target address. diff --git a/framework/base/src/types/interaction/contract_call_convert.rs b/framework/base/src/types/interaction/contract_call_convert.rs index 88e6ae6627..fe4225d9a4 100644 --- a/framework/base/src/types/interaction/contract_call_convert.rs +++ b/framework/base/src/types/interaction/contract_call_convert.rs @@ -38,7 +38,7 @@ where function_call: self .basic .function_call - .convert_to_single_transfer_fungible_call(&payment), + .convert_to_single_transfer_fungible_call(payment.as_refs()), explicit_gas_limit: self.basic.explicit_gas_limit, _return_type: PhantomData, }, @@ -55,7 +55,7 @@ where function_call: self .basic .function_call - .convert_to_single_transfer_nft_call(&self.basic.to, &payment), + .convert_to_single_transfer_nft_call(&self.basic.to, payment.as_refs()), explicit_gas_limit: self.basic.explicit_gas_limit, _return_type: PhantomData, }, diff --git a/framework/base/src/types/interaction/function_call.rs b/framework/base/src/types/interaction/function_call.rs index efb149e2b4..1d78735a79 100644 --- a/framework/base/src/types/interaction/function_call.rs +++ b/framework/base/src/types/interaction/function_call.rs @@ -9,7 +9,10 @@ use crate::{ CallTypeApi, ManagedTypeApi, ESDT_MULTI_TRANSFER_FUNC_NAME, ESDT_NFT_TRANSFER_FUNC_NAME, ESDT_TRANSFER_FUNC_NAME, }, - types::{EsdtTokenPayment, ManagedAddress, ManagedBuffer, ManagedVec, MultiValueEncoded}, + types::{ + EsdtTokenPayment, EsdtTokenPaymentRefs, ManagedAddress, ManagedBuffer, ManagedVec, + MultiValueEncoded, + }, }; use super::{ContractCallNoPayment, ManagedArgBuffer, TypedFunctionCall}; @@ -159,7 +162,7 @@ where /// Constructs `ESDTTransfer` builtin function call. pub(super) fn convert_to_single_transfer_fungible_call( self, - payment: &EsdtTokenPayment, + payment: EsdtTokenPaymentRefs<'_, Api>, ) -> FunctionCall { FunctionCall::new(ESDT_TRANSFER_FUNC_NAME) .argument(&payment.token_identifier) @@ -177,7 +180,7 @@ where pub(super) fn convert_to_single_transfer_nft_call( self, to: &ManagedAddress, - payment: &EsdtTokenPayment, + payment: EsdtTokenPaymentRefs<'_, Api>, ) -> FunctionCall { FunctionCall::new(ESDT_NFT_TRANSFER_FUNC_NAME) .argument(&payment.token_identifier) diff --git a/framework/base/src/types/interaction/tx.rs b/framework/base/src/types/interaction/tx.rs index 9e41ae8b2d..27b11f59f8 100644 --- a/framework/base/src/types/interaction/tx.rs +++ b/framework/base/src/types/interaction/tx.rs @@ -1,6 +1,7 @@ use crate::{ api::CallTypeApi, contract_base::BlockchainWrapper, + proxy_imports::{EsdtTokenPaymentRefs, TokenIdentifier}, types::{ BigUint, CodeMetadata, EgldOrEsdtTokenPayment, EsdtTokenPayment, ManagedAddress, ManagedBuffer, ManagedOption, ManagedVec, MultiEsdtPayment, @@ -203,6 +204,30 @@ where } } + /// Sets a single token payment, with the token identifier and amount kept as references. + /// + /// This is handy whem we only want one ESDT transfer and we want to avoid unnecessary object clones. + pub fn esdt_refs<'a>( + self, + token_identifier: &'a TokenIdentifier, + token_nonce: u64, + amount: &'a BigUint, + ) -> Tx, Gas, Data, RH> { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: EsdtTokenPaymentRefs { + token_identifier, + token_nonce, + amount, + }, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } + /// Adds a collection of ESDT payments to a transaction. pub fn multi_esdt( self, diff --git a/framework/base/src/types/interaction/tx_payment.rs b/framework/base/src/types/interaction/tx_payment.rs index 2511d2ede8..4b2f54e29f 100644 --- a/framework/base/src/types/interaction/tx_payment.rs +++ b/framework/base/src/types/interaction/tx_payment.rs @@ -4,6 +4,7 @@ mod tx_payment_multi_esdt; mod tx_payment_none; mod tx_payment_other; mod tx_payment_single_esdt; +mod tx_payment_single_esdt_ref; pub use tx_payment_egld::{Egld, EgldPayment}; pub use tx_payment_egld_value::TxEgldValue; diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs index de9f65eff9..3c1a554d03 100644 --- a/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs @@ -15,18 +15,27 @@ where fn perform_transfer_execute( self, - _env: &Env, + env: &Env, to: &ManagedAddress, gas_limit: u64, fc: FunctionCall, ) { - let _ = SendRawWrapper::::new().multi_esdt_transfer_execute( - to, - self, - gas_limit, - &fc.function_name, - &fc.arg_buffer, - ); + match self.len() { + 0 => ().perform_transfer_execute(env, to, gas_limit, fc), + 1 => self + .get(0) + .as_refs() + .perform_transfer_execute(env, to, gas_limit, fc), + _ => { + let _ = SendRawWrapper::::new().multi_esdt_transfer_execute( + to, + self, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + }, + } } fn with_normalized( @@ -44,7 +53,7 @@ where { match self.len() { 0 => ().with_normalized(env, from, to, fc, f), - 1 => self.get(0).with_normalized(env, from, to, fc, f), + 1 => self.get(0).as_refs().with_normalized(env, from, to, fc, f), _ => to.with_address_ref(env, |to_addr| { let fc_conv = fc.convert_to_multi_transfer_esdt_call(to_addr, self); f(&from.resolve_address(env), &BigUint::zero(), &fc_conv) diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs index f2fdf5aacb..f5bf61c0f1 100644 --- a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs @@ -23,7 +23,8 @@ where gas_limit: u64, fc: FunctionCall, ) { - MultiEsdtPayment::from_single_item(self).perform_transfer_execute(env, to, gas_limit, fc); + self.as_refs() + .perform_transfer_execute(env, to, gas_limit, fc); } fn with_normalized( @@ -39,15 +40,7 @@ where To: TxToSpecified, F: FnOnce(&ManagedAddress, &BigUint, &FunctionCall) -> R, { - to.with_address_ref(env, |to_addr| { - if self.token_nonce == 0 { - let fc_conv = fc.convert_to_single_transfer_fungible_call(&self); - f(to_addr, &BigUint::zero(), &fc_conv) - } else { - let fc_conv = fc.convert_to_single_transfer_nft_call(to_addr, &self); - f(&from.resolve_address(env), &BigUint::zero(), &fc_conv) - } - }) + self.as_refs().with_normalized(env, from, to, fc, f) } fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs new file mode 100644 index 0000000000..c0d568e11b --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs @@ -0,0 +1,81 @@ +use crate::{ + api::ManagedTypeApi, + contract_base::SendRawWrapper, + types::{ + BigUint, EsdtTokenPayment, EsdtTokenPaymentRefs, ManagedAddress, ManagedVec, + MultiEsdtPayment, TokenIdentifier, TxFrom, TxToSpecified, + }, +}; + +use super::{AnnotatedEgldPayment, FullPaymentData, FunctionCall, TxEgldValue, TxEnv, TxPayment}; + +impl<'a, Env> TxPayment for EsdtTokenPaymentRefs<'a, Env::Api> +where + Env: TxEnv, +{ + fn is_no_payment(&self) -> bool { + self.amount == &0u32 + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + if self.token_nonce == 0 { + // fungible ESDT + let _ = SendRawWrapper::::new().transfer_esdt_execute( + to, + self.token_identifier, + self.amount, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + } else { + // non-fungible/semi-fungible ESDT + let _ = SendRawWrapper::::new().transfer_esdt_nft_execute( + to, + self.token_identifier, + self.token_nonce, + self.amount, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + } + } + + fn with_normalized( + self, + env: &Env, + from: &From, + to: To, + fc: FunctionCall, + f: F, + ) -> R + where + From: TxFrom, + To: TxToSpecified, + F: FnOnce(&ManagedAddress, &BigUint, &FunctionCall) -> R, + { + to.with_address_ref(env, |to_addr| { + if self.token_nonce == 0 { + let fc_conv = fc.convert_to_single_transfer_fungible_call(self); + f(to_addr, &BigUint::zero(), &fc_conv) + } else { + let fc_conv = fc.convert_to_single_transfer_nft_call(to_addr, self); + f(&from.resolve_address(env), &BigUint::zero(), &fc_conv) + } + }) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: MultiEsdtPayment::from_single_item(self.to_owned_payment()), + } + } +} diff --git a/framework/base/src/types/managed/wrapped/esdt_token_payment.rs b/framework/base/src/types/managed/wrapped/esdt_token_payment.rs index 246b28de1d..161c2c1ee3 100644 --- a/framework/base/src/types/managed/wrapped/esdt_token_payment.rs +++ b/framework/base/src/types/managed/wrapped/esdt_token_payment.rs @@ -222,3 +222,31 @@ impl ManagedVecItem for EsdtTokenPayment { writer(&arr[..]) } } + +/// The version of `EsdtTokenPayment` that contains referrences instead of owned fields. +pub struct EsdtTokenPaymentRefs<'a, M: ManagedTypeApi> { + pub token_identifier: &'a TokenIdentifier, + pub token_nonce: u64, + pub amount: &'a BigUint, +} + +impl EsdtTokenPayment { + pub fn as_refs(&self) -> EsdtTokenPaymentRefs<'_, M> { + EsdtTokenPaymentRefs { + token_identifier: &self.token_identifier, + token_nonce: self.token_nonce, + amount: &self.amount, + } + } +} + +impl<'a, M: ManagedTypeApi> EsdtTokenPaymentRefs<'a, M> { + /// Will clone the referenced values. + pub fn to_owned_payment(&self) -> EsdtTokenPayment { + EsdtTokenPayment { + token_identifier: self.token_identifier.clone(), + token_nonce: self.token_nonce, + amount: self.amount.clone(), + } + } +} diff --git a/framework/base/src/types/managed/wrapped/mod.rs b/framework/base/src/types/managed/wrapped/mod.rs index 8ac485fa38..a2dcd6008a 100644 --- a/framework/base/src/types/managed/wrapped/mod.rs +++ b/framework/base/src/types/managed/wrapped/mod.rs @@ -23,7 +23,7 @@ pub use egld_or_esdt_token_payment::EgldOrEsdtTokenPayment; pub use egld_or_multi_esdt_payment::EgldOrMultiEsdtPayment; pub(crate) use encoded_managed_vec_item::EncodedManagedVecItem; pub use esdt_token_data::EsdtTokenData; -pub use esdt_token_payment::{EsdtTokenPayment, MultiEsdtPayment}; +pub use esdt_token_payment::{EsdtTokenPayment, EsdtTokenPaymentRefs, MultiEsdtPayment}; pub use managed_address::ManagedAddress; pub use managed_buffer_cached_builder::ManagedBufferCachedBuilder; pub(crate) use managed_byte_array::ManagedBufferSizeContext;