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#[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 pub fn dcdt_system_sc_proxy(
51 &self,
52 ) -> system_proxy::DCDTSystemSCProxyMethods<TxScEnv<A>, (), DCDTSystemSCAddress, ()> {
53 self.dcdt_system_sc_tx()
54 }
55
56 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 #[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 #[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 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 #[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 #[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 #[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 #[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 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 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 #[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 #[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 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 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 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 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 #[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 #[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 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 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 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 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 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 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 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 #[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 #[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 #[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 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 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 #[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 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 #[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 #[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 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 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 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 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 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 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 #[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 #[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}