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