multiversx_sc/contract_base/wrappers/
send_wrapper.rs

1use core::marker::PhantomData;
2
3use crate::codec::Empty;
4
5use crate::types::ManagedRef;
6use crate::{
7    api::{BlockchainApi, CallTypeApi, StorageReadApi},
8    codec,
9    types::{
10        system_proxy, BigUint, ESDTSystemSCAddress, EgldOrEsdtTokenIdentifier, EsdtTokenPayment,
11        FunctionCall, GasLeft, ManagedAddress, ManagedArgBuffer, ManagedBuffer, ManagedType,
12        ManagedVec, NotPayable, OriginalResultMarker, ReturnsRawResult, ReturnsResult, ToSelf,
13        TokenIdentifier, Tx, TxScEnv,
14    },
15};
16
17use super::BlockchainWrapper;
18
19const PERCENTAGE_TOTAL: u64 = 10_000;
20
21use super::SendRawWrapper;
22
23/// API that groups methods that either send EGLD or ESDT, or that call other contracts.
24// pub trait SendApi: Clone + Sized {
25
26#[derive(Default)]
27pub struct SendWrapper<A>
28where
29    A: CallTypeApi + StorageReadApi + BlockchainApi,
30{
31    _phantom: PhantomData<A>,
32}
33
34impl<A> SendWrapper<A>
35where
36    A: CallTypeApi + StorageReadApi + BlockchainApi,
37{
38    pub fn new() -> Self {
39        SendWrapper {
40            _phantom: PhantomData,
41        }
42    }
43
44    #[inline]
45    fn send_raw_wrapper(&self) -> SendRawWrapper<A> {
46        SendRawWrapper::new()
47    }
48
49    /// Backwards compatibility, synonymous to `esdt_system_sc_tx`, which is the more appropriate name now.
50    pub fn esdt_system_sc_proxy(
51        &self,
52    ) -> system_proxy::ESDTSystemSCProxyMethods<TxScEnv<A>, (), ESDTSystemSCAddress, ()> {
53        self.esdt_system_sc_tx()
54    }
55
56    /// Prepares a proxy object to call the ESDT system SC.
57    /// It has the destination address set, as well as the contract type (as specified in the proxy).
58    pub fn esdt_system_sc_tx(
59        &self,
60    ) -> system_proxy::ESDTSystemSCProxyMethods<TxScEnv<A>, (), ESDTSystemSCAddress, ()> {
61        Tx::new_tx_from_sc()
62            .to(ESDTSystemSCAddress)
63            .typed(system_proxy::ESDTSystemSCProxy)
64    }
65
66    /// Convenient way to quickly instance a minimal contract call (with no EGLD, no arguments, etc.)
67    ///
68    /// You can further configure this contract call by chaining methods to it.
69    #[cfg(feature = "contract-call-legacy")]
70    #[deprecated(
71        since = "0.62.0",
72        note = "Please use the unified transaction syntax instead."
73    )]
74    pub fn contract_call<R>(
75        &self,
76        to: ManagedAddress<A>,
77        endpoint_name: impl Into<ManagedBuffer<A>>,
78    ) -> crate::types::ContractCallNoPayment<A, R> {
79        crate::types::ContractCallNoPayment::new(to, endpoint_name)
80    }
81
82    /// Sends EGLD to a given address, directly.
83    /// Used especially for sending EGLD to regular accounts.
84    #[inline]
85    pub fn direct_egld(&self, to: &ManagedAddress<A>, amount: &BigUint<A>) {
86        Tx::new_tx_from_sc().to(to).egld(amount).transfer();
87    }
88
89    /// Sends EGLD to a given address, directly.
90    /// Used especially for sending EGLD to regular accounts.
91    ///
92    /// If the amount is 0, it returns without error.
93    pub fn direct_non_zero_egld(&self, to: &ManagedAddress<A>, amount: &BigUint<A>) {
94        Tx::new_tx_from_sc()
95            .to(to)
96            .egld(amount)
97            .transfer_if_not_empty();
98    }
99
100    /// Sends either EGLD, ESDT or NFT to the target address,
101    /// depending on the token identifier and nonce
102    #[inline]
103    pub fn direct(
104        &self,
105        to: &ManagedAddress<A>,
106        token: &EgldOrEsdtTokenIdentifier<A>,
107        nonce: u64,
108        amount: &BigUint<A>,
109    ) {
110        self.direct_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]);
111    }
112
113    /// Sends either EGLD, ESDT or NFT to the target address,
114    /// depending on the token identifier and nonce.
115    ///
116    /// If the amount is 0, it returns without error.
117    #[inline]
118    pub fn direct_non_zero(
119        &self,
120        to: &ManagedAddress<A>,
121        token: &EgldOrEsdtTokenIdentifier<A>,
122        nonce: u64,
123        amount: &BigUint<A>,
124    ) {
125        self.direct_non_zero_with_gas_limit(to, token, nonce, amount, 0, Empty, &[]);
126    }
127
128    /// Sends a single ESDT transfer, and calls an endpoint at the destination.
129    ///
130    /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it.
131    #[allow(clippy::too_many_arguments)]
132    pub fn direct_esdt_with_gas_limit<D>(
133        &self,
134        to: &ManagedAddress<A>,
135        token_identifier: &TokenIdentifier<A>,
136        nonce: u64,
137        amount: &BigUint<A>,
138        gas: u64,
139        endpoint_name: D,
140        arguments: &[ManagedBuffer<A>],
141    ) where
142        D: Into<ManagedBuffer<A>>,
143    {
144        if nonce == 0 {
145            self.send_raw_wrapper().transfer_esdt_execute(
146                to,
147                token_identifier,
148                amount,
149                gas,
150                &endpoint_name.into(),
151                &arguments.into(),
152            );
153        } else {
154            self.send_raw_wrapper().transfer_esdt_nft_execute(
155                to,
156                token_identifier,
157                nonce,
158                amount,
159                gas,
160                &endpoint_name.into(),
161                &arguments.into(),
162            );
163        }
164    }
165
166    /// Sends a single ESDT transfer, and calls an endpoint at the destination.
167    ///
168    /// If the amount is 0, it returns without error.
169    ///
170    /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it.
171    #[allow(clippy::too_many_arguments)]
172    pub fn direct_non_zero_esdt_with_gas_limit<D>(
173        &self,
174        to: &ManagedAddress<A>,
175        token_identifier: &TokenIdentifier<A>,
176        nonce: u64,
177        amount: &BigUint<A>,
178        gas: u64,
179        endpoint_name: D,
180        arguments: &[ManagedBuffer<A>],
181    ) where
182        D: Into<ManagedBuffer<A>>,
183    {
184        if amount == &0 {
185            return;
186        }
187        self.direct_esdt_with_gas_limit(
188            to,
189            token_identifier,
190            nonce,
191            amount,
192            gas,
193            endpoint_name,
194            arguments,
195        );
196    }
197
198    /// Sends a single ESDT transfer to target address.
199    pub fn direct_esdt(
200        &self,
201        to: &ManagedAddress<A>,
202        token_identifier: &TokenIdentifier<A>,
203        token_nonce: u64,
204        amount: &BigUint<A>,
205    ) {
206        Tx::new_tx_from_sc()
207            .to(to)
208            .single_esdt(token_identifier, token_nonce, amount)
209            .transfer();
210    }
211
212    /// Sends a single ESDT transfer to target address.
213    ///
214    /// If the amount is 0, it returns without error.
215    pub fn direct_non_zero_esdt_payment(
216        &self,
217        to: &ManagedAddress<A>,
218        payment: &EsdtTokenPayment<A>,
219    ) {
220        if payment.amount == 0 {
221            return;
222        }
223
224        self.direct_esdt(
225            to,
226            &payment.token_identifier,
227            payment.token_nonce,
228            &payment.amount,
229        );
230    }
231
232    /// Sends either EGLD, ESDT or NFT to the target address,
233    /// depending on the token identifier and nonce.
234    /// Also and calls an endpoint at the destination.
235    ///
236    /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it.
237    #[allow(clippy::too_many_arguments)]
238    pub fn direct_with_gas_limit<D>(
239        &self,
240        to: &ManagedAddress<A>,
241        token: &EgldOrEsdtTokenIdentifier<A>,
242        nonce: u64,
243        amount: &BigUint<A>,
244        gas: u64,
245        endpoint_name: D,
246        arguments: &[ManagedBuffer<A>],
247    ) where
248        D: Into<ManagedBuffer<A>>,
249    {
250        if let Some(esdt_token_identifier) = token.as_esdt_option() {
251            self.direct_esdt_with_gas_limit(
252                to,
253                &esdt_token_identifier,
254                nonce,
255                amount,
256                gas,
257                endpoint_name,
258                arguments,
259            );
260        } else {
261            self.send_raw_wrapper().direct_egld_execute(
262                to,
263                amount,
264                gas,
265                &endpoint_name.into(),
266                &arguments.into(),
267            );
268        }
269    }
270    /// Sends either EGLD, ESDT or NFT to the target address,
271    /// depending on the token identifier and nonce.
272    /// Also and calls an endpoint at the destination.
273    ///
274    /// If the amount is 0, it returns without error.
275    ///
276    /// Avoid if possible, use a contract call with ESDT transfer instead, and call `.transfer_execute()` on it.
277    #[allow(clippy::too_many_arguments)]
278    pub fn direct_non_zero_with_gas_limit<D>(
279        &self,
280        to: &ManagedAddress<A>,
281        token: &EgldOrEsdtTokenIdentifier<A>,
282        nonce: u64,
283        amount: &BigUint<A>,
284        gas: u64,
285        endpoint_name: D,
286        arguments: &[ManagedBuffer<A>],
287    ) where
288        D: Into<ManagedBuffer<A>>,
289    {
290        if amount == &0 {
291            return;
292        }
293        self.direct_with_gas_limit(to, token, nonce, amount, gas, endpoint_name, arguments);
294    }
295
296    /// Sends multiple ESDT tokens to a target address.
297    pub fn direct_multi(
298        &self,
299        to: &ManagedAddress<A>,
300        payments: &ManagedVec<A, EsdtTokenPayment<A>>,
301    ) {
302        Tx::new_tx_from_sc().to(to).payment(payments).transfer();
303    }
304
305    /// Performs a simple ESDT/NFT transfer, but via async call.  
306    ///
307    /// As with any async call, this immediately terminates the execution of the current call,
308    /// so only use as the last call in your endpoint.
309    ///
310    /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead.
311    ///
312    /// Note that EGLD can NOT be transferred with this function.  
313    pub fn transfer_esdt_via_async_call(
314        &self,
315        to: ManagedAddress<A>,
316        token: TokenIdentifier<A>,
317        nonce: u64,
318        amount: BigUint<A>,
319    ) -> ! {
320        Tx::new_tx_from_sc()
321            .to(to)
322            .esdt((token, nonce, amount))
323            .async_call_and_exit()
324    }
325
326    /// Performs a simple ESDT/NFT transfer, but via async call.  
327    ///
328    /// As with any async call, this immediately terminates the execution of the current call,
329    /// so only use as the last call in your endpoint.
330    ///
331    /// If you want to perform multiple transfers, use `self.send().transfer_multiple_esdt_via_async_call()` instead.  
332    /// Note that EGLD can NOT be transferred with this function.
333    ///
334    /// If the amount is 0, it returns without error.
335    pub fn transfer_esdt_non_zero_via_async_call(
336        &self,
337        to: ManagedAddress<A>,
338        token: TokenIdentifier<A>,
339        nonce: u64,
340        amount: BigUint<A>,
341    ) {
342        if amount == 0 {
343            return;
344        }
345        self.transfer_esdt_via_async_call(to, token, nonce, amount)
346    }
347
348    /// Sends multiple ESDT tokens to a target address, via an async call.
349    pub fn transfer_multiple_esdt_via_async_call(
350        &self,
351        to: ManagedAddress<A>,
352        payments: ManagedVec<A, EsdtTokenPayment<A>>,
353    ) -> ! {
354        Tx::new_tx_from_sc()
355            .to(to)
356            .payment(payments)
357            .async_call_and_exit()
358    }
359
360    /// Creates a call to the `ClaimDeveloperRewards` builtin function.
361    #[allow(clippy::type_complexity)]
362    pub fn claim_developer_rewards(
363        &self,
364        child_sc_address: ManagedAddress<A>,
365    ) -> Tx<
366        TxScEnv<A>,
367        (),
368        ManagedAddress<A>,
369        NotPayable,
370        (),
371        FunctionCall<A>,
372        OriginalResultMarker<()>,
373    > {
374        Tx::new_tx_from_sc()
375            .to(child_sc_address)
376            .typed(system_proxy::UserBuiltinProxy)
377            .claim_developer_rewards()
378    }
379
380    /// Creates a call to the `ChangeOwnerAddress` builtin function.
381    #[allow(clippy::type_complexity)]
382    pub fn change_owner_address(
383        &self,
384        child_sc_address: ManagedAddress<A>,
385        new_owner: &ManagedAddress<A>,
386    ) -> Tx<
387        TxScEnv<A>,
388        (),
389        ManagedAddress<A>,
390        NotPayable,
391        (),
392        FunctionCall<A>,
393        OriginalResultMarker<()>,
394    > {
395        Tx::new_tx_from_sc()
396            .to(child_sc_address)
397            .typed(system_proxy::UserBuiltinProxy)
398            .change_owner_address(new_owner)
399    }
400
401    /// Allows synchronously calling a local function by name. Execution is resumed afterwards.
402    /// You should never have to call this function directly.
403    /// Use the other specific methods instead.
404    pub fn call_local_esdt_built_in_function(
405        &self,
406        gas: u64,
407        endpoint_name: ManagedBuffer<A>,
408        arg_buffer: ManagedArgBuffer<A>,
409    ) -> ManagedVec<A, ManagedBuffer<A>> {
410        Tx::new_tx_from_sc()
411            .to(ToSelf)
412            .gas(gas)
413            .raw_call(endpoint_name)
414            .arguments_raw(arg_buffer)
415            .returns(ReturnsRawResult)
416            .sync_call()
417    }
418
419    /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards.
420    ///
421    /// Note that the SC must have the ESDTLocalMint or ESDTNftAddQuantity roles set,
422    /// or this will fail with "action is not allowed".
423    ///
424    /// For SFTs, you must use `self.send().esdt_nft_create()` before adding additional quantity.
425    ///
426    /// This function cannot be used for NFTs.
427    pub fn esdt_local_mint(&self, token: &TokenIdentifier<A>, nonce: u64, amount: &BigUint<A>) {
428        Tx::new_tx_from_sc()
429            .to(ToSelf)
430            .gas(GasLeft)
431            .typed(system_proxy::UserBuiltinProxy)
432            .esdt_local_mint(token, nonce, amount)
433            .sync_call()
434    }
435
436    /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards.
437    ///
438    /// Note that the SC must have the ESDTLocalMint or ESDTNftAddQuantity roles set,
439    /// or this will fail with "action is not allowed".
440    ///
441    /// For SFTs, you must use `self.send().esdt_nft_create()` before adding additional quantity.
442    /// This function cannot be used for NFTs.
443    ///
444    /// If the amount is 0, it returns without error.
445    pub fn esdt_non_zero_local_mint(
446        &self,
447        token: &TokenIdentifier<A>,
448        nonce: u64,
449        amount: &BigUint<A>,
450    ) {
451        if amount == &0 {
452            return;
453        }
454        self.esdt_local_mint(token, nonce, amount);
455    }
456
457    /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards.
458    ///
459    /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set,
460    /// or this will fail with "action is not allowed".
461    pub fn esdt_local_burn(&self, token: &TokenIdentifier<A>, nonce: u64, amount: &BigUint<A>) {
462        Tx::new_tx_from_sc()
463            .to(ToSelf)
464            .gas(GasLeft)
465            .typed(system_proxy::UserBuiltinProxy)
466            .esdt_local_burn(token, nonce, amount)
467            .sync_call()
468    }
469
470    /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards.
471    ///
472    /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set,
473    /// or this will fail with "action is not allowed".
474    ///
475    /// If the amount is 0, it returns without error.
476    pub fn esdt_non_zero_local_burn(
477        &self,
478        token: &TokenIdentifier<A>,
479        nonce: u64,
480        amount: &BigUint<A>,
481    ) {
482        if amount == &0 {
483            return;
484        }
485        self.esdt_local_burn(token, nonce, amount);
486    }
487
488    /// Allows burning of multiple ESDT tokens at once.
489    ///
490    /// Will execute a synchronous call to the appropriate burn builtin function for each.
491    pub fn esdt_local_burn_multi(&self, payments: &ManagedVec<A, EsdtTokenPayment<A>>) {
492        for payment in payments {
493            self.esdt_local_burn(
494                &payment.token_identifier,
495                payment.token_nonce,
496                &payment.amount,
497            );
498        }
499    }
500
501    /// Allows burning of multiple ESDT tokens at once.
502    ///
503    /// Will execute a synchronous call to the appropriate burn builtin function for each.
504    ///
505    /// If any of the token amounts is 0 skips that token without throwing error.
506    pub fn esdt_non_zero_local_burn_multi(&self, payments: &ManagedVec<A, EsdtTokenPayment<A>>) {
507        for payment in payments {
508            self.esdt_non_zero_local_burn(
509                &payment.token_identifier,
510                payment.token_nonce,
511                &payment.amount,
512            );
513        }
514    }
515
516    /// Creates a new NFT token of a certain type (determined by `token_identifier`).
517    /// `attributes` can be any serializable custom struct.  
518    ///
519    /// This is a synchronous built-in function call, so the smart contract execution is resumed afterwards.
520    ///
521    /// Must have ESDTNftCreate role set, or this will fail with "action is not allowed".
522    ///
523    /// Returns the nonce of the newly created NFT.
524    #[allow(clippy::too_many_arguments)]
525    pub fn esdt_nft_create<T: codec::TopEncode>(
526        &self,
527        token: &TokenIdentifier<A>,
528        amount: &BigUint<A>,
529        name: &ManagedBuffer<A>,
530        royalties: &BigUint<A>,
531        hash: &ManagedBuffer<A>,
532        attributes: &T,
533        uris: &ManagedVec<A, ManagedBuffer<A>>,
534    ) -> u64 {
535        Tx::new_tx_from_sc()
536            .to(ToSelf)
537            .gas(GasLeft)
538            .typed(system_proxy::UserBuiltinProxy)
539            .esdt_nft_create(token, amount, name, royalties, hash, attributes, uris)
540            .returns(ReturnsResult)
541            .sync_call()
542    }
543
544    /// Creates a new NFT token of a certain type (determined by `token_identifier`).
545    ///
546    /// `attributes` can be any serializable custom struct.
547    ///
548    /// This is a built-in function, so the smart contract execution is resumed after.
549    /// Must have ESDTNftCreate role set, or this will fail with "action is not allowed".
550    ///
551    /// Returns the nonce of the newly created NFT.
552    ///
553    /// If the amount is 0, it returns without error.
554    #[allow(clippy::too_many_arguments)]
555    pub fn esdt_non_zero_nft_create<T: codec::TopEncode>(
556        &self,
557        token: &TokenIdentifier<A>,
558        amount: &BigUint<A>,
559        name: &ManagedBuffer<A>,
560        royalties: &BigUint<A>,
561        hash: &ManagedBuffer<A>,
562        attributes: &T,
563        uris: &ManagedVec<A, ManagedBuffer<A>>,
564    ) -> u64 {
565        if amount == &0 {
566            0
567        } else {
568            self.esdt_nft_create(token, amount, name, royalties, hash, attributes, uris)
569        }
570    }
571
572    /// Quick way of creating a new NFT token instance.
573    ///
574    /// Returns the new NFT nonce.
575    #[inline]
576    pub fn esdt_nft_create_compact<T: codec::TopEncode>(
577        &self,
578        token: &TokenIdentifier<A>,
579        amount: &BigUint<A>,
580        attributes: &T,
581    ) -> u64 {
582        self.esdt_nft_create_compact_named(token, amount, &ManagedBuffer::new(), attributes)
583    }
584
585    /// Quick way of creating a new NFT token instance, with custom name.
586    ///
587    /// Returns the new NFT nonce.
588    pub fn esdt_nft_create_compact_named<T: codec::TopEncode>(
589        &self,
590        token: &TokenIdentifier<A>,
591        amount: &BigUint<A>,
592        name: &ManagedBuffer<A>,
593        attributes: &T,
594    ) -> u64 {
595        let big_zero = BigUint::zero();
596        let empty_buffer = ManagedBuffer::new();
597
598        // sneakily reuses the same handle
599        let empty_vec = unsafe { ManagedRef::wrap_handle(empty_buffer.get_handle()) };
600
601        self.esdt_nft_create(
602            token,
603            amount,
604            name,
605            &big_zero,
606            &empty_buffer,
607            attributes,
608            &empty_vec,
609        )
610    }
611
612    /// Quick way of creating a new NFT token instance.
613    ///
614    /// Returns the new NFT nonce.
615    ///
616    /// If the amount is 0, it returns without error.
617    #[inline]
618    pub fn esdt_non_zero_nft_create_compact<T: codec::TopEncode>(
619        &self,
620        token: &TokenIdentifier<A>,
621        amount: &BigUint<A>,
622        attributes: &T,
623    ) -> u64 {
624        self.esdt_non_zero_nft_create_compact_named(
625            token,
626            amount,
627            &ManagedBuffer::new(),
628            attributes,
629        )
630    }
631
632    /// Quick way of creating a new NFT token instance, with custom name.
633    ///
634    /// Returns the new NFT nonce.
635    ///
636    /// If the amount is 0, it returns without error.
637    pub fn esdt_non_zero_nft_create_compact_named<T: codec::TopEncode>(
638        &self,
639        token: &TokenIdentifier<A>,
640        amount: &BigUint<A>,
641        name: &ManagedBuffer<A>,
642        attributes: &T,
643    ) -> u64 {
644        if amount == &0 {
645            0
646        } else {
647            self.esdt_nft_create_compact_named(token, amount, name, attributes)
648        }
649    }
650
651    /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator.
652    ///
653    /// Returns the payment amount left after sending royalties.
654    #[allow(clippy::too_many_arguments)]
655    pub fn sell_nft(
656        &self,
657        nft_id: &TokenIdentifier<A>,
658        nft_nonce: u64,
659        nft_amount: &BigUint<A>,
660        buyer: &ManagedAddress<A>,
661        payment_token: &EgldOrEsdtTokenIdentifier<A>,
662        payment_nonce: u64,
663        payment_amount: &BigUint<A>,
664    ) -> BigUint<A> {
665        let nft_token_data = BlockchainWrapper::<A>::new().get_esdt_token_data(
666            &BlockchainWrapper::<A>::new().get_sc_address(),
667            nft_id,
668            nft_nonce,
669        );
670        let royalties_amount = payment_amount.clone() * nft_token_data.royalties / PERCENTAGE_TOTAL;
671
672        self.send_raw_wrapper().transfer_esdt_nft_execute(
673            buyer,
674            nft_id,
675            nft_nonce,
676            nft_amount,
677            0,
678            &ManagedBuffer::new(),
679            &ManagedArgBuffer::new(),
680        );
681
682        if royalties_amount > 0u32 {
683            self.direct(
684                &nft_token_data.creator,
685                payment_token,
686                payment_nonce,
687                &royalties_amount,
688            );
689
690            payment_amount.clone() - royalties_amount
691        } else {
692            payment_amount.clone()
693        }
694    }
695
696    /// Sends the NFTs to the buyer address and calculates and sends the required royalties to the NFT creator.
697    ///
698    /// Returns the payment amount left after sending royalties.
699    ///
700    /// If the nft_amount or the payment_amount is 0 returns without error
701    #[allow(clippy::too_many_arguments)]
702    pub fn sell_nft_non_zero(
703        &self,
704        nft_id: &TokenIdentifier<A>,
705        nft_nonce: u64,
706        nft_amount: &BigUint<A>,
707        buyer: &ManagedAddress<A>,
708        payment_token: &EgldOrEsdtTokenIdentifier<A>,
709        payment_nonce: u64,
710        payment_amount: &BigUint<A>,
711    ) -> BigUint<A> {
712        if nft_amount == &0 || payment_amount == &0 {
713            payment_amount.clone()
714        } else {
715            self.sell_nft(
716                nft_id,
717                nft_nonce,
718                nft_amount,
719                buyer,
720                payment_token,
721                payment_nonce,
722                payment_amount,
723            )
724        }
725    }
726
727    /// Adds a new URI to an NFT, via a synchronous builtin function call.
728    pub fn nft_add_uri(
729        &self,
730        token_id: &TokenIdentifier<A>,
731        nft_nonce: u64,
732        new_uri: ManagedBuffer<A>,
733    ) {
734        self.nft_add_multiple_uri(token_id, nft_nonce, &ManagedVec::from_single_item(new_uri));
735    }
736
737    /// Adds a multiple URIs to an NFT, via a synchronous builtin function call.
738    pub fn nft_add_multiple_uri(
739        &self,
740        token_id: &TokenIdentifier<A>,
741        nft_nonce: u64,
742        new_uris: &ManagedVec<A, ManagedBuffer<A>>,
743    ) {
744        if new_uris.is_empty() {
745            return;
746        }
747
748        Tx::new_tx_from_sc()
749            .to(ToSelf)
750            .gas(GasLeft)
751            .typed(system_proxy::UserBuiltinProxy)
752            .nft_add_multiple_uri(token_id, nft_nonce, new_uris)
753            .sync_call()
754    }
755
756    /// Changes attributes of an NFT, via a synchronous builtin function call.
757    pub fn nft_update_attributes<T: codec::TopEncode>(
758        &self,
759        token_id: &TokenIdentifier<A>,
760        nft_nonce: u64,
761        new_attributes: &T,
762    ) {
763        Tx::new_tx_from_sc()
764            .to(ToSelf)
765            .gas(GasLeft)
766            .typed(system_proxy::UserBuiltinProxy)
767            .nft_update_attributes(token_id, nft_nonce, new_attributes)
768            .sync_call()
769    }
770
771    /// Modifies royalties for a specific token.
772    pub fn esdt_modify_royalties(
773        &self,
774        token_id: &TokenIdentifier<A>,
775        nonce: u64,
776        new_royalty: u64,
777    ) {
778        Tx::new_tx_from_sc()
779            .to(ToSelf)
780            .gas(GasLeft)
781            .typed(system_proxy::UserBuiltinProxy)
782            .esdt_modify_royalties(token_id, nonce, new_royalty)
783            .sync_call()
784    }
785
786    /// Sets new uris for a specific token.
787    pub fn esdt_nft_set_new_uris(
788        &self,
789        token_id: &TokenIdentifier<A>,
790        nonce: u64,
791        uris: &ManagedVec<A, ManagedBuffer<A>>,
792    ) {
793        Tx::new_tx_from_sc()
794            .to(ToSelf)
795            .gas(GasLeft)
796            .typed(system_proxy::UserBuiltinProxy)
797            .esdt_nft_set_new_uris(token_id, nonce, uris)
798            .sync_call()
799    }
800
801    /// Changes the creator of a specific token into the caller.
802    pub fn esdt_nft_modify_creator(&self, token_id: &TokenIdentifier<A>, nonce: u64) {
803        Tx::new_tx_from_sc()
804            .to(ToSelf)
805            .gas(GasLeft)
806            .typed(system_proxy::UserBuiltinProxy)
807            .esdt_nft_modify_creator(token_id, nonce)
808            .sync_call()
809    }
810
811    /// Recreates an ESDT token with the newly specified attributes.
812    #[allow(clippy::too_many_arguments)]
813    pub fn esdt_metadata_recreate<T: codec::TopEncode>(
814        &self,
815        token_id: TokenIdentifier<A>,
816        nonce: u64,
817        name: ManagedBuffer<A>,
818        royalties: u64,
819        hash: ManagedBuffer<A>,
820        new_attributes: &T,
821        uris: ManagedVec<A, ManagedBuffer<A>>,
822    ) {
823        Tx::new_tx_from_sc()
824            .to(ToSelf)
825            .gas(GasLeft)
826            .typed(system_proxy::UserBuiltinProxy)
827            .esdt_metadata_recreate(token_id, nonce, name, royalties, hash, new_attributes, uris)
828            .sync_call()
829    }
830
831    /// Updates an ESDT token with the newly specified attributes.
832    #[allow(clippy::too_many_arguments)]
833    pub fn esdt_metadata_update<T: codec::TopEncode>(
834        &self,
835        token_id: TokenIdentifier<A>,
836        nonce: u64,
837        name: ManagedBuffer<A>,
838        royalties: u64,
839        hash: ManagedBuffer<A>,
840        new_attributes: &T,
841        uris: ManagedVec<A, ManagedBuffer<A>>,
842    ) {
843        Tx::new_tx_from_sc()
844            .to(ToSelf)
845            .gas(GasLeft)
846            .typed(system_proxy::UserBuiltinProxy)
847            .esdt_metadata_update(token_id, nonce, name, royalties, hash, new_attributes, uris)
848            .sync_call()
849    }
850}