From dbdfe94c0241cccff3445b462b035a5091070fd2 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 13:39:40 +0300 Subject: [PATCH 1/8] send wrapper non zero endpoints --- .../contract_base/wrappers/send_wrapper.rs | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index c78fb9937f..27e7200598 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -92,6 +92,17 @@ where self.direct_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]); } + #[inline] + pub fn direct_non_zero( + &self, + to: &ManagedAddress, + token: &EgldOrEsdtTokenIdentifier, + nonce: u64, + amount: &BigUint, + ) { + self.direct_non_zero_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]); + } + #[allow(clippy::too_many_arguments)] pub fn direct_esdt_with_gas_limit( &self, @@ -127,6 +138,43 @@ where } } + #[allow(clippy::too_many_arguments)] + pub fn direct_non_zero_esdt_with_gas_limit( + &self, + to: &ManagedAddress, + token_identifier: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + gas: u64, + endpoint_name: D, + arguments: &[ManagedBuffer], + ) where + D: Into>, + { + if amount == &0 { + if nonce == 0 { + let _ = self.send_raw_wrapper().transfer_esdt_execute( + to, + token_identifier, + amount, + gas, + &endpoint_name.into(), + &arguments.into(), + ); + } else { + let _ = self.send_raw_wrapper().transfer_esdt_nft_execute( + to, + token_identifier, + nonce, + amount, + gas, + &endpoint_name.into(), + &arguments.into(), + ); + } + } + } + #[inline] #[allow(clippy::too_many_arguments)] pub fn direct_esdt( @@ -190,6 +238,42 @@ where } } + #[allow(clippy::too_many_arguments)] + pub fn direct_non_zero_with_gas_limit( + &self, + to: &ManagedAddress, + token: &EgldOrEsdtTokenIdentifier, + nonce: u64, + amount: &BigUint, + gas: u64, + endpoint_name: D, + arguments: &[ManagedBuffer], + ) where + D: Into>, + { + if amount == &0 { + if let Some(esdt_token_identifier) = token.as_esdt_option() { + self.direct_esdt_with_gas_limit( + to, + &esdt_token_identifier, + nonce, + amount, + gas, + endpoint_name, + arguments, + ); + } else { + let _ = self.send_raw_wrapper().direct_egld_execute( + to, + amount, + gas, + &endpoint_name.into(), + &arguments.into(), + ); + } + } + } + pub fn direct_multi( &self, to: &ManagedAddress, @@ -292,6 +376,35 @@ where ); } + pub fn esdt_non_zero_local_mint( + &self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) { + if amount == &0 { + let mut arg_buffer = ManagedArgBuffer::new(); + let func_name: &str; + + arg_buffer.push_arg(token); + + if nonce == 0 { + func_name = ESDT_LOCAL_MINT_FUNC_NAME; + } else { + func_name = ESDT_NFT_ADD_QUANTITY_FUNC_NAME; + arg_buffer.push_arg(nonce); + } + + arg_buffer.push_arg(amount); + + let _ = self.call_local_esdt_built_in_function( + A::blockchain_api_impl().get_gas_left(), + &ManagedBuffer::from(func_name), + &arg_buffer, + ); + } + } + /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set, /// or this will fail with "action is not allowed" @@ -315,6 +428,33 @@ where &arg_buffer, ); } + pub fn esdt_non_zero_local_burn( + &self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) { + if amount == &0 { + let mut arg_buffer = ManagedArgBuffer::new(); + let func_name: &str; + + arg_buffer.push_arg(token); + if nonce == 0 { + func_name = ESDT_LOCAL_BURN_FUNC_NAME; + } else { + func_name = ESDT_NFT_BURN_FUNC_NAME; + arg_buffer.push_arg(nonce); + } + + arg_buffer.push_arg(amount); + + let _ = self.call_local_esdt_built_in_function( + A::blockchain_api_impl().get_gas_left(), + &ManagedBuffer::from(func_name), + &arg_buffer, + ); + } + } /// Allows burning of multiple ESDT tokens at once. /// @@ -328,6 +468,15 @@ where ); } } + pub fn esdt_non_zero_local_burn_multi(&self, payments: &ManagedVec>) { + for payment in payments { + self.esdt_non_zero_local_burn( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + } /// Creates a new NFT token of a certain type (determined by `token_identifier`). /// `attributes` can be any serializable custom struct. @@ -377,6 +526,50 @@ where } } + #[allow(clippy::too_many_arguments)] + pub fn esdt_non_zero_nft_create( + &self, + token: &TokenIdentifier, + amount: &BigUint, + name: &ManagedBuffer, + royalties: &BigUint, + hash: &ManagedBuffer, + attributes: &T, + uris: &ManagedVec>, + ) -> u64 { + if amount == &0 { + let mut arg_buffer = ManagedArgBuffer::new(); + arg_buffer.push_arg(token); + arg_buffer.push_arg(amount); + arg_buffer.push_arg(name); + arg_buffer.push_arg(royalties); + arg_buffer.push_arg(hash); + arg_buffer.push_arg(attributes); + + if uris.is_empty() { + // at least one URI is required, so we push an empty one + arg_buffer.push_arg(codec::Empty); + } else { + // The API function has the last argument as variadic, + // so we top-encode each and send as separate argument + for uri in uris { + arg_buffer.push_arg(uri); + } + } + + let output = self.call_local_esdt_built_in_function( + A::blockchain_api_impl().get_gas_left(), + &ManagedBuffer::from(ESDT_NFT_CREATE_FUNC_NAME), + &arg_buffer, + ); + + if let Some(first_result_bytes) = output.try_get(0) { + return first_result_bytes.parse_as_u64().unwrap_or_default(); + } + } + 0 + } + #[inline] pub fn esdt_nft_create_compact( &self, @@ -409,6 +602,47 @@ where ) } + #[inline] + pub fn esdt_non_zero_nft_create_compact( + &self, + token: &TokenIdentifier, + amount: &BigUint, + attributes: &T, + ) -> u64 { + self.esdt_non_zero_nft_create_compact_named( + token, + amount, + &ManagedBuffer::new(), + attributes, + ) + } + + pub fn esdt_non_zero_nft_create_compact_named( + &self, + token: &TokenIdentifier, + amount: &BigUint, + name: &ManagedBuffer, + attributes: &T, + ) -> u64 { + if amount == &0 { + let big_zero = BigUint::zero(); + let empty_buffer = ManagedBuffer::new(); + let empty_vec = ManagedVec::from_handle(empty_buffer.get_handle()); + + self.esdt_nft_create( + token, + amount, + name, + &big_zero, + &empty_buffer, + attributes, + &empty_vec, + ) + } else { + 0 + } + } + /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator. /// Returns the payment amount left after sending royalties. #[allow(clippy::too_many_arguments)] @@ -453,6 +687,52 @@ where } } + #[allow(clippy::too_many_arguments)] + pub fn sell_nft_non_zero( + &self, + nft_id: &TokenIdentifier, + nft_nonce: u64, + nft_amount: &BigUint, + buyer: &ManagedAddress, + payment_token: &EgldOrEsdtTokenIdentifier, + payment_nonce: u64, + payment_amount: &BigUint, + ) -> BigUint { + if nft_amount == &0 || payment_amount == &0 { + let nft_token_data = BlockchainWrapper::::new().get_esdt_token_data( + &BlockchainWrapper::::new().get_sc_address(), + nft_id, + nft_nonce, + ); + let royalties_amount = + payment_amount.clone() * nft_token_data.royalties / PERCENTAGE_TOTAL; + + let _ = self.send_raw_wrapper().transfer_esdt_nft_execute( + buyer, + nft_id, + nft_nonce, + nft_amount, + 0, + &ManagedBuffer::new(), + &ManagedArgBuffer::new(), + ); + + if royalties_amount > 0u32 { + self.direct( + &nft_token_data.creator, + payment_token, + payment_nonce, + &royalties_amount, + ); + + return payment_amount.clone() - royalties_amount; + } else { + return payment_amount.clone(); + } + } + payment_amount.clone() + } + pub fn nft_add_uri( &self, token_id: &TokenIdentifier, From c2e70a7db06a32dc139905e384231493138e6450 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 13:50:22 +0300 Subject: [PATCH 2/8] deduplicate code --- .../contract_base/wrappers/send_wrapper.rs | 176 +++--------------- 1 file changed, 29 insertions(+), 147 deletions(-) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 27e7200598..37907a80d9 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -152,27 +152,17 @@ where D: Into>, { if amount == &0 { - if nonce == 0 { - let _ = self.send_raw_wrapper().transfer_esdt_execute( - to, - token_identifier, - amount, - gas, - &endpoint_name.into(), - &arguments.into(), - ); - } else { - let _ = self.send_raw_wrapper().transfer_esdt_nft_execute( - to, - token_identifier, - nonce, - amount, - gas, - &endpoint_name.into(), - &arguments.into(), - ); - } + return; } + self.direct_esdt_with_gas_limit( + to, + token_identifier, + nonce, + amount, + gas, + endpoint_name, + arguments, + ); } #[inline] @@ -252,26 +242,9 @@ where D: Into>, { if amount == &0 { - if let Some(esdt_token_identifier) = token.as_esdt_option() { - self.direct_esdt_with_gas_limit( - to, - &esdt_token_identifier, - nonce, - amount, - gas, - endpoint_name, - arguments, - ); - } else { - let _ = self.send_raw_wrapper().direct_egld_execute( - to, - amount, - gas, - &endpoint_name.into(), - &arguments.into(), - ); - } + return; } + self.direct_with_gas_limit(to, token, nonce, amount, gas, endpoint_name, arguments); } pub fn direct_multi( @@ -383,26 +356,9 @@ where amount: &BigUint, ) { if amount == &0 { - let mut arg_buffer = ManagedArgBuffer::new(); - let func_name: &str; - - arg_buffer.push_arg(token); - - if nonce == 0 { - func_name = ESDT_LOCAL_MINT_FUNC_NAME; - } else { - func_name = ESDT_NFT_ADD_QUANTITY_FUNC_NAME; - arg_buffer.push_arg(nonce); - } - - arg_buffer.push_arg(amount); - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(func_name), - &arg_buffer, - ); + return; } + self.esdt_local_mint(token, nonce, amount); } /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. @@ -435,25 +391,9 @@ where amount: &BigUint, ) { if amount == &0 { - let mut arg_buffer = ManagedArgBuffer::new(); - let func_name: &str; - - arg_buffer.push_arg(token); - if nonce == 0 { - func_name = ESDT_LOCAL_BURN_FUNC_NAME; - } else { - func_name = ESDT_NFT_BURN_FUNC_NAME; - arg_buffer.push_arg(nonce); - } - - arg_buffer.push_arg(amount); - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(func_name), - &arg_buffer, - ); + return; } + self.esdt_local_burn(token, nonce, amount); } /// Allows burning of multiple ESDT tokens at once. @@ -538,36 +478,10 @@ where uris: &ManagedVec>, ) -> u64 { if amount == &0 { - let mut arg_buffer = ManagedArgBuffer::new(); - arg_buffer.push_arg(token); - arg_buffer.push_arg(amount); - arg_buffer.push_arg(name); - arg_buffer.push_arg(royalties); - arg_buffer.push_arg(hash); - arg_buffer.push_arg(attributes); - - if uris.is_empty() { - // at least one URI is required, so we push an empty one - arg_buffer.push_arg(codec::Empty); - } else { - // The API function has the last argument as variadic, - // so we top-encode each and send as separate argument - for uri in uris { - arg_buffer.push_arg(uri); - } - } - - let output = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(ESDT_NFT_CREATE_FUNC_NAME), - &arg_buffer, - ); - - if let Some(first_result_bytes) = output.try_get(0) { - return first_result_bytes.parse_as_u64().unwrap_or_default(); - } + 0 + } else { + self.esdt_nft_create(token, amount, name, royalties, hash, attributes, uris) } - 0 } #[inline] @@ -625,21 +539,9 @@ where attributes: &T, ) -> u64 { if amount == &0 { - let big_zero = BigUint::zero(); - let empty_buffer = ManagedBuffer::new(); - let empty_vec = ManagedVec::from_handle(empty_buffer.get_handle()); - - self.esdt_nft_create( - token, - amount, - name, - &big_zero, - &empty_buffer, - attributes, - &empty_vec, - ) - } else { 0 + } else { + self.esdt_nft_create_compact_named(token, amount, name, attributes) } } @@ -699,38 +601,18 @@ where payment_amount: &BigUint, ) -> BigUint { if nft_amount == &0 || payment_amount == &0 { - let nft_token_data = BlockchainWrapper::::new().get_esdt_token_data( - &BlockchainWrapper::::new().get_sc_address(), - nft_id, - nft_nonce, - ); - let royalties_amount = - payment_amount.clone() * nft_token_data.royalties / PERCENTAGE_TOTAL; - - let _ = self.send_raw_wrapper().transfer_esdt_nft_execute( - buyer, + payment_amount.clone() + } else { + self.sell_nft( nft_id, nft_nonce, nft_amount, - 0, - &ManagedBuffer::new(), - &ManagedArgBuffer::new(), - ); - - if royalties_amount > 0u32 { - self.direct( - &nft_token_data.creator, - payment_token, - payment_nonce, - &royalties_amount, - ); - - return payment_amount.clone() - royalties_amount; - } else { - return payment_amount.clone(); - } + buyer, + payment_token, + payment_nonce, + payment_amount, + ) } - payment_amount.clone() } pub fn nft_add_uri( From 7acd6ad6a61bf683fc7ef00c1d59422c11ae7365 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 13:56:44 +0300 Subject: [PATCH 3/8] transfer esdt non zero via async call --- .../src/contract_base/wrappers/send_wrapper.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 37907a80d9..be83fe9463 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -279,6 +279,22 @@ where .call_and_exit_ignore_callback() } + pub fn transfer_esdt_non_zero_via_async_call( + &self, + to: ManagedAddress, + token: TokenIdentifier, + nonce: u64, + amount: BigUint, + ) -> ! { + if amount == 0 { + unreachable!() + } + ContractCallNoPayment::::new(to, ManagedBuffer::new()) + .with_esdt_transfer((token, nonce, amount)) + .async_call() + .call_and_exit_ignore_callback() + } + pub fn transfer_multiple_esdt_via_async_call( &self, to: ManagedAddress, From e6355ae37a8125b5c1e7bdae6ca6ac6a35e39549 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 14:03:40 +0300 Subject: [PATCH 4/8] fix logic of transfer_non_zero+esdt_via_async_call --- framework/base/src/contract_base/wrappers/send_wrapper.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index be83fe9463..d8ca32cf1d 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -287,7 +287,9 @@ where amount: BigUint, ) -> ! { if amount == 0 { - unreachable!() + ContractCallNoPayment::::new(to, ManagedBuffer::new()) + .async_call() + .call_and_exit_ignore_callback() } ContractCallNoPayment::::new(to, ManagedBuffer::new()) .with_esdt_transfer((token, nonce, amount)) From b9092327ce7e791af92dcda8b43152876366a463 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 14:12:23 +0300 Subject: [PATCH 5/8] add comments for docs --- .../contract_base/wrappers/send_wrapper.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index d8ca32cf1d..052b02972b 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -71,6 +71,9 @@ where self.send_raw_wrapper().direct_egld(to, amount, Empty) } + /// Sends EGLD to a given address, directly. + /// Used especially for sending EGLD to regular accounts. + /// If amount is 0 returns without error pub fn direct_non_zero_egld(&self, to: &ManagedAddress, amount: &BigUint) { if amount == &0 { return; @@ -92,6 +95,9 @@ where self.direct_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]); } + /// Sends either EGLD, ESDT or NFT to the target address, + /// depending on the token identifier and nonce + /// If amount is 0 returns without error #[inline] pub fn direct_non_zero( &self, @@ -138,6 +144,7 @@ where } } + /// If amount is 0 returns without error #[allow(clippy::too_many_arguments)] pub fn direct_non_zero_esdt_with_gas_limit( &self, @@ -177,6 +184,7 @@ where self.direct_esdt_with_gas_limit(to, token_identifier, nonce, amount, 0, Empty, &[]); } + /// If amount is 0 returns without error pub fn direct_non_zero_esdt_payment( &self, to: &ManagedAddress, @@ -228,6 +236,7 @@ where } } + /// If amount is 0 returns without error #[allow(clippy::too_many_arguments)] pub fn direct_non_zero_with_gas_limit( &self, @@ -279,6 +288,12 @@ where .call_and_exit_ignore_callback() } + /// Performs a simple ESDT/NFT transfer, but via async call. + /// As with any async call, this immediately terminates the execution of the current call. + /// So only use as the last call in your endpoint. + /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead. + /// Note that EGLD can NOT be transfered with this function. + /// If amount is 0 continues with the async call without making any transfer pub fn transfer_esdt_non_zero_via_async_call( &self, to: ManagedAddress, @@ -367,6 +382,12 @@ where ); } + /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards. + /// Note that the SC must have the ESDTLocalMint or ESDTNftAddQuantity roles set, + /// or this will fail with "action is not allowed" + /// For SFTs, you must use `self.send().esdt_nft_create()` before adding additional quantity. + /// This function cannot be used for NFTs. + /// If amount is 0 returns without error pub fn esdt_non_zero_local_mint( &self, token: &TokenIdentifier, @@ -402,6 +423,11 @@ where &arg_buffer, ); } + + /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. + /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set, + /// or this will fail with "action is not allowed" + /// If amount is 0 returns without error pub fn esdt_non_zero_local_burn( &self, token: &TokenIdentifier, @@ -426,6 +452,11 @@ where ); } } + + /// Allows burning of multiple ESDT tokens at once. + /// + /// Will execute a synchronous call to the appropriate burn builtin function for each. + /// If any of the token amounts is 0 skips that token without throwing error pub fn esdt_non_zero_local_burn_multi(&self, payments: &ManagedVec>) { for payment in payments { self.esdt_non_zero_local_burn( @@ -484,6 +515,12 @@ where } } + /// Creates a new NFT token of a certain type (determined by `token_identifier`). + /// `attributes` can be any serializable custom struct. + /// This is a built-in function, so the smart contract execution is resumed after. + /// Must have ESDTNftCreate role set, or this will fail with "action is not allowed". + /// Returns the nonce of the newly created NFT. + /// If amount is 0 returns without error #[allow(clippy::too_many_arguments)] pub fn esdt_non_zero_nft_create( &self, @@ -534,6 +571,7 @@ where ) } + /// If amount is 0 returns without error #[inline] pub fn esdt_non_zero_nft_create_compact( &self, @@ -549,6 +587,7 @@ where ) } + /// If amount is 0 returns without error pub fn esdt_non_zero_nft_create_compact_named( &self, token: &TokenIdentifier, @@ -607,6 +646,9 @@ where } } + /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator. + /// Returns the payment amount left after sending royalties. + /// If the nft_amount or the payment_amount is 0 returns without error #[allow(clippy::too_many_arguments)] pub fn sell_nft_non_zero( &self, From ad2708566c163ce60a8fc12bc465a170891f40cf Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 14:28:50 +0300 Subject: [PATCH 6/8] fix transfer_esdt_non_zero_via_async_call return --- framework/base/src/contract_base/wrappers/send_wrapper.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 052b02972b..350d00a9f5 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -300,11 +300,9 @@ where token: TokenIdentifier, nonce: u64, amount: BigUint, - ) -> ! { + ) { if amount == 0 { - ContractCallNoPayment::::new(to, ManagedBuffer::new()) - .async_call() - .call_and_exit_ignore_callback() + return; } ContractCallNoPayment::::new(to, ManagedBuffer::new()) .with_esdt_transfer((token, nonce, amount)) From 84ffda62cf15ff08ef131c7f624a113af7032325 Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Fri, 8 Sep 2023 14:31:55 +0300 Subject: [PATCH 7/8] fix docs comment --- framework/base/src/contract_base/wrappers/send_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 350d00a9f5..790fbd1631 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -293,7 +293,7 @@ where /// So only use as the last call in your endpoint. /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead. /// Note that EGLD can NOT be transfered with this function. - /// If amount is 0 continues with the async call without making any transfer + /// If amount is 0 returns without error pub fn transfer_esdt_non_zero_via_async_call( &self, to: ManagedAddress, From 9de7e9ed69b8a097b8502b91ccaf7eab0ecf643a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 8 Sep 2023 14:48:57 +0300 Subject: [PATCH 8/8] SendWrapper improved docs --- .../contract_base/wrappers/send_wrapper.rs | 134 ++++++++++++++---- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 790fbd1631..02387193a1 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -50,11 +50,17 @@ where SendRawWrapper::new() } + /// A proxy for calling the system smart contract. + /// + /// Use the methods of this proxy to launch contract calls to the system SC. #[inline] pub fn esdt_system_sc_proxy(&self) -> ESDTSystemSmartContractProxy { ESDTSystemSmartContractProxy::new_proxy_obj() } + /// Convenient way to quickly instance a minimal contract call (with no EGLD, no arguments, etc.) + /// + /// You can further configure this contract call by chaining methods to it. #[inline] pub fn contract_call( &self, @@ -73,7 +79,8 @@ where /// Sends EGLD to a given address, directly. /// Used especially for sending EGLD to regular accounts. - /// If amount is 0 returns without error + /// + /// If the amount is 0, it returns without error. pub fn direct_non_zero_egld(&self, to: &ManagedAddress, amount: &BigUint) { if amount == &0 { return; @@ -96,8 +103,9 @@ where } /// Sends either EGLD, ESDT or NFT to the target address, - /// depending on the token identifier and nonce - /// If amount is 0 returns without error + /// depending on the token identifier and nonce. + /// + /// If the amount is 0, it returns without error. #[inline] pub fn direct_non_zero( &self, @@ -109,6 +117,9 @@ where self.direct_non_zero_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]); } + /// Sends a single ESDT transfer, and calls an endpoint at the destination. + /// + /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it. #[allow(clippy::too_many_arguments)] pub fn direct_esdt_with_gas_limit( &self, @@ -144,7 +155,11 @@ where } } - /// If amount is 0 returns without error + /// Sends a single ESDT transfer, and calls an endpoint at the destination. + /// + /// If the amount is 0, it returns without error. + /// + /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it. #[allow(clippy::too_many_arguments)] pub fn direct_non_zero_esdt_with_gas_limit( &self, @@ -172,6 +187,7 @@ where ); } + /// Sends a single ESDT transfer to target address. #[inline] #[allow(clippy::too_many_arguments)] pub fn direct_esdt( @@ -184,7 +200,9 @@ where self.direct_esdt_with_gas_limit(to, token_identifier, nonce, amount, 0, Empty, &[]); } - /// If amount is 0 returns without error + /// Sends a single ESDT transfer to target address. + /// + /// If the amount is 0, it returns without error. pub fn direct_non_zero_esdt_payment( &self, to: &ManagedAddress, @@ -202,6 +220,11 @@ where ); } + /// Sends either EGLD, ESDT or NFT to the target address, + /// depending on the token identifier and nonce. + /// Also and calls an endpoint at the destination. + /// + /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it. #[allow(clippy::too_many_arguments)] pub fn direct_with_gas_limit( &self, @@ -235,8 +258,13 @@ where ); } } - - /// If amount is 0 returns without error + /// Sends either EGLD, ESDT or NFT to the target address, + /// depending on the token identifier and nonce. + /// Also and calls an endpoint at the destination. + /// + /// If the amount is 0, it returns without error. + /// + /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it. #[allow(clippy::too_many_arguments)] pub fn direct_non_zero_with_gas_limit( &self, @@ -256,6 +284,7 @@ where self.direct_with_gas_limit(to, token, nonce, amount, gas, endpoint_name, arguments); } + /// Sends multiple ESDT tokens to a target address. pub fn direct_multi( &self, to: &ManagedAddress, @@ -271,9 +300,12 @@ where } /// Performs a simple ESDT/NFT transfer, but via async call. - /// As with any async call, this immediately terminates the execution of the current call. - /// So only use as the last call in your endpoint. - /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead. + /// + /// As with any async call, this immediately terminates the execution of the current call, + /// so only use as the last call in your endpoint. + /// + /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead. + /// /// Note that EGLD can NOT be transfered with this function. pub fn transfer_esdt_via_async_call( &self, @@ -289,11 +321,14 @@ where } /// Performs a simple ESDT/NFT transfer, but via async call. - /// As with any async call, this immediately terminates the execution of the current call. - /// So only use as the last call in your endpoint. + /// + /// As with any async call, this immediately terminates the execution of the current call, + /// so only use as the last call in your endpoint. + /// /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead. /// Note that EGLD can NOT be transfered with this function. - /// If amount is 0 returns without error + /// + /// If the amount is 0, it returns without error. pub fn transfer_esdt_non_zero_via_async_call( &self, to: ManagedAddress, @@ -310,6 +345,7 @@ where .call_and_exit_ignore_callback() } + /// Sends multiple ESDT tokens to a target address, via an async call. pub fn transfer_multiple_esdt_via_async_call( &self, to: ManagedAddress, @@ -321,6 +357,9 @@ where .call_and_exit_ignore_callback() } + /// Creates a call to the `ClaimDeveloperRewards` builtin function. + /// + /// In itself, this does nothing. You need to then call turn the contract call into an async call. pub fn claim_developer_rewards( &self, child_sc_address: ManagedAddress, @@ -328,7 +367,9 @@ where ContractCallNoPayment::new(child_sc_address, CLAIM_DEVELOPER_REWARDS_FUNC_NAME) } - /// Sends a synchronous call to change a smart contract address. + /// Creates a call to the `ChangeOwnerAddress` builtin function. + /// + /// In itself, this does nothing. You need to then call turn the contract call into an async call. pub fn change_owner_address( &self, child_sc_address: ManagedAddress, @@ -354,9 +395,12 @@ where } /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards. + /// /// Note that the SC must have the ESDTLocalMint or ESDTNftAddQuantity roles set, - /// or this will fail with "action is not allowed" + /// or this will fail with "action is not allowed". + /// /// For SFTs, you must use `self.send().esdt_nft_create()` before adding additional quantity. + /// /// This function cannot be used for NFTs. pub fn esdt_local_mint(&self, token: &TokenIdentifier, nonce: u64, amount: &BigUint) { let mut arg_buffer = ManagedArgBuffer::new(); @@ -381,11 +425,14 @@ where } /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards. + /// /// Note that the SC must have the ESDTLocalMint or ESDTNftAddQuantity roles set, - /// or this will fail with "action is not allowed" + /// or this will fail with "action is not allowed". + /// /// For SFTs, you must use `self.send().esdt_nft_create()` before adding additional quantity. /// This function cannot be used for NFTs. - /// If amount is 0 returns without error + /// + /// If the amount is 0, it returns without error. pub fn esdt_non_zero_local_mint( &self, token: &TokenIdentifier, @@ -399,8 +446,9 @@ where } /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. + /// /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set, - /// or this will fail with "action is not allowed" + /// or this will fail with "action is not allowed". pub fn esdt_local_burn(&self, token: &TokenIdentifier, nonce: u64, amount: &BigUint) { let mut arg_buffer = ManagedArgBuffer::new(); let func_name: &str; @@ -423,9 +471,11 @@ where } /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. + /// /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set, - /// or this will fail with "action is not allowed" - /// If amount is 0 returns without error + /// or this will fail with "action is not allowed". + /// + /// If the amount is 0, it returns without error. pub fn esdt_non_zero_local_burn( &self, token: &TokenIdentifier, @@ -454,7 +504,8 @@ where /// Allows burning of multiple ESDT tokens at once. /// /// Will execute a synchronous call to the appropriate burn builtin function for each. - /// If any of the token amounts is 0 skips that token without throwing error + /// + /// If any of the token amounts is 0 skips that token without throwing error. pub fn esdt_non_zero_local_burn_multi(&self, payments: &ManagedVec>) { for payment in payments { self.esdt_non_zero_local_burn( @@ -465,10 +516,13 @@ where } } - /// Creates a new NFT token of a certain type (determined by `token_identifier`). + /// Creates a new NFT token of a certain type (determined by `token_identifier`). /// `attributes` can be any serializable custom struct. - /// This is a built-in function, so the smart contract execution is resumed after. + /// + /// This is a synchronous built-in function call, so the smart contract execution is resumed afterwards. + /// /// Must have ESDTNftCreate role set, or this will fail with "action is not allowed". + /// /// Returns the nonce of the newly created NFT. #[allow(clippy::too_many_arguments)] pub fn esdt_nft_create( @@ -513,12 +567,16 @@ where } } - /// Creates a new NFT token of a certain type (determined by `token_identifier`). - /// `attributes` can be any serializable custom struct. + /// Creates a new NFT token of a certain type (determined by `token_identifier`). + /// + /// `attributes` can be any serializable custom struct. + /// /// This is a built-in function, so the smart contract execution is resumed after. /// Must have ESDTNftCreate role set, or this will fail with "action is not allowed". + /// /// Returns the nonce of the newly created NFT. - /// If amount is 0 returns without error + /// + /// If the amount is 0, it returns without error. #[allow(clippy::too_many_arguments)] pub fn esdt_non_zero_nft_create( &self, @@ -537,6 +595,9 @@ where } } + /// Quick way of creating a new NFT token instance. + /// + /// Returns the new NFT nonce. #[inline] pub fn esdt_nft_create_compact( &self, @@ -547,6 +608,9 @@ where self.esdt_nft_create_compact_named(token, amount, &ManagedBuffer::new(), attributes) } + /// Quick way of creating a new NFT token instance, with custom name. + /// + /// Returns the new NFT nonce. pub fn esdt_nft_create_compact_named( &self, token: &TokenIdentifier, @@ -569,7 +633,11 @@ where ) } - /// If amount is 0 returns without error + /// Quick way of creating a new NFT token instance. + /// + /// Returns the new NFT nonce. + /// + /// If the amount is 0, it returns without error. #[inline] pub fn esdt_non_zero_nft_create_compact( &self, @@ -585,7 +653,11 @@ where ) } - /// If amount is 0 returns without error + /// Quick way of creating a new NFT token instance, with custom name. + /// + /// Returns the new NFT nonce. + /// + /// If the amount is 0, it returns without error. pub fn esdt_non_zero_nft_create_compact_named( &self, token: &TokenIdentifier, @@ -601,6 +673,7 @@ where } /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator. + /// /// Returns the payment amount left after sending royalties. #[allow(clippy::too_many_arguments)] pub fn sell_nft( @@ -645,7 +718,9 @@ where } /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator. + /// /// Returns the payment amount left after sending royalties. + /// /// If the nft_amount or the payment_amount is 0 returns without error #[allow(clippy::too_many_arguments)] pub fn sell_nft_non_zero( @@ -673,6 +748,7 @@ where } } + /// Adds a new URI to an NFT, via a synchronous builtin function call. pub fn nft_add_uri( &self, token_id: &TokenIdentifier, @@ -682,6 +758,7 @@ where self.nft_add_multiple_uri(token_id, nft_nonce, &ManagedVec::from_single_item(new_uri)); } + /// Adds a multiple URIs to an NFT, via a synchronous builtin function call. pub fn nft_add_multiple_uri( &self, token_id: &TokenIdentifier, @@ -707,6 +784,7 @@ where ); } + /// Changes attributes of an NFT, via a synchronous builtin function call. pub fn nft_update_attributes( &self, token_id: &TokenIdentifier,