diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index c78fb9937f..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, @@ -71,6 +77,10 @@ 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 the amount is 0, it returns without error. pub fn direct_non_zero_egld(&self, to: &ManagedAddress, amount: &BigUint) { if amount == &0 { return; @@ -92,6 +102,24 @@ 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 the amount is 0, it returns without error. + #[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, &[]); + } + + /// 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, @@ -127,6 +155,39 @@ where } } + /// 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, + to: &ManagedAddress, + token_identifier: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + gas: u64, + endpoint_name: D, + arguments: &[ManagedBuffer], + ) where + D: Into>, + { + if amount == &0 { + return; + } + self.direct_esdt_with_gas_limit( + to, + token_identifier, + nonce, + amount, + gas, + endpoint_name, + arguments, + ); + } + + /// Sends a single ESDT transfer to target address. #[inline] #[allow(clippy::too_many_arguments)] pub fn direct_esdt( @@ -139,6 +200,9 @@ where self.direct_esdt_with_gas_limit(to, token_identifier, nonce, amount, 0, Empty, &[]); } + /// 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, @@ -156,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, @@ -189,7 +258,33 @@ 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. + /// + /// 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, + to: &ManagedAddress, + token: &EgldOrEsdtTokenIdentifier, + nonce: u64, + amount: &BigUint, + gas: u64, + endpoint_name: D, + arguments: &[ManagedBuffer], + ) where + D: Into>, + { + if amount == &0 { + return; + } + 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, @@ -205,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, @@ -222,6 +320,32 @@ 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 the amount is 0, it returns without error. + pub fn transfer_esdt_non_zero_via_async_call( + &self, + to: ManagedAddress, + token: TokenIdentifier, + nonce: u64, + amount: BigUint, + ) { + if amount == 0 { + return; + } + ContractCallNoPayment::::new(to, ManagedBuffer::new()) + .with_esdt_transfer((token, nonce, amount)) + .async_call() + .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, @@ -233,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, @@ -240,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, @@ -266,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(); @@ -292,9 +424,31 @@ 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 the amount is 0, it returns without error. + pub fn esdt_non_zero_local_mint( + &self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) { + if amount == &0 { + return; + } + self.esdt_local_mint(token, nonce, amount); + } + /// 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; @@ -316,6 +470,24 @@ 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 the amount is 0, it returns without error. + pub fn esdt_non_zero_local_burn( + &self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) { + if amount == &0 { + return; + } + self.esdt_local_burn(token, nonce, amount); + } + /// Allows burning of multiple ESDT tokens at once. /// /// Will execute a synchronous call to the appropriate burn builtin function for each. @@ -329,10 +501,28 @@ where } } - /// Creates a new NFT token of a certain type (determined by `token_identifier`). + /// 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( + &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. - /// 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( @@ -377,6 +567,37 @@ 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 the amount is 0, it returns without error. + #[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 { + 0 + } else { + self.esdt_nft_create(token, amount, name, royalties, hash, attributes, uris) + } + } + + /// Quick way of creating a new NFT token instance. + /// + /// Returns the new NFT nonce. #[inline] pub fn esdt_nft_create_compact( &self, @@ -387,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, @@ -409,7 +633,47 @@ where ) } + /// 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, + token: &TokenIdentifier, + amount: &BigUint, + attributes: &T, + ) -> u64 { + self.esdt_non_zero_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. + /// + /// If the amount is 0, it returns without error. + pub fn esdt_non_zero_nft_create_compact_named( + &self, + token: &TokenIdentifier, + amount: &BigUint, + name: &ManagedBuffer, + attributes: &T, + ) -> u64 { + if amount == &0 { + 0 + } else { + self.esdt_nft_create_compact_named(token, amount, name, attributes) + } + } + /// 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( @@ -453,6 +717,38 @@ 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, + 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 { + payment_amount.clone() + } else { + self.sell_nft( + nft_id, + nft_nonce, + nft_amount, + buyer, + payment_token, + payment_nonce, + payment_amount, + ) + } + } + + /// Adds a new URI to an NFT, via a synchronous builtin function call. pub fn nft_add_uri( &self, token_id: &TokenIdentifier, @@ -462,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, @@ -487,6 +784,7 @@ where ); } + /// Changes attributes of an NFT, via a synchronous builtin function call. pub fn nft_update_attributes( &self, token_id: &TokenIdentifier,