multiversx_sc_modules/token_merge/
merged_token_setup.rs1multiversx_sc::imports!();
2
3use super::{
4 custom_merged_token_attributes::MergedTokenAttributesCreator,
5 merged_token_instances::{MAX_MERGED_TOKENS, MergedTokenInstances},
6};
7
8const NFT_AMOUNT: u64 = 1;
9pub static DIFFERENT_CREATOR_ERR_MSG: &[u8] = b"All merged tokens must have the same creator";
10
11#[multiversx_sc::module]
12pub trait MergedTokenSetupModule {
13 #[only_owner]
14 #[payable("EGLD")]
15 #[endpoint(issueMergedToken)]
16 fn issue_merged_token(&self, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer) {
17 let payment_amount = self.call_value().egld();
18 self.merged_token().issue_and_set_all_roles(
19 EsdtTokenType::NonFungible,
20 payment_amount.clone(),
21 token_display_name,
22 token_ticker,
23 0,
24 None,
25 );
26 }
27
28 #[only_owner]
29 #[endpoint(addMergeableTokensToWhitelist)]
30 fn add_mergeable_tokens_to_whitelist(&self, tokens: MultiValueEncoded<EsdtTokenIdentifier>) {
31 let mut whitelist = self.mergeable_tokens_whitelist();
32 for token in tokens {
33 let _ = whitelist.insert(token);
34 }
35 }
36
37 #[only_owner]
38 #[endpoint(removeMergeableTokensFromWhitelist)]
39 fn remove_mergeable_tokens_from_whitelist(
40 &self,
41 tokens: MultiValueEncoded<EsdtTokenIdentifier>,
42 ) {
43 let mut whitelist = self.mergeable_tokens_whitelist();
44 for token in tokens {
45 let _ = whitelist.swap_remove(&token);
46 }
47 }
48
49 fn create_merged_token<AttributesCreator: MergedTokenAttributesCreator<ScType = Self>>(
50 &self,
51 merged_token_id: EsdtTokenIdentifier,
52 merged_instances: &MergedTokenInstances<Self::Api>,
53 attr_creator: &AttributesCreator,
54 ) -> EsdtTokenPayment<Self::Api> {
55 let nft_amount = BigUint::from(NFT_AMOUNT);
56 let empty_buffer = ManagedBuffer::new();
57
58 let all_token_data = self.collect_token_data(merged_instances);
59 self.require_all_parts_same_creator(&all_token_data);
60
61 let royalties = self.get_max_royalties(&all_token_data);
62 let uri = self.create_uri_for_merged_token(merged_instances);
63 let attributes =
64 attr_creator.get_merged_token_attributes(self, &merged_token_id, merged_instances);
65 let merged_token_nonce = self.send().esdt_nft_create(
66 &merged_token_id,
67 &nft_amount,
68 &empty_buffer,
69 &royalties,
70 &empty_buffer,
71 &attributes,
72 &ManagedVec::from_single_item(uri),
73 );
74
75 EsdtTokenPayment::new(merged_token_id, merged_token_nonce, nft_amount)
76 }
77
78 fn create_uri_for_merged_token(
79 &self,
80 merged_instances: &MergedTokenInstances<Self::Api>,
81 ) -> ManagedBuffer {
82 let mut tokens_list = ManagedVec::<Self::Api, _>::new();
83 for inst in merged_instances.get_instances() {
84 tokens_list.push(inst.clone());
85 }
86
87 let mut encoded = ManagedBuffer::new();
88 let _ = tokens_list.top_encode(&mut encoded);
89
90 encoded
91 }
92
93 fn collect_token_data(
94 &self,
95 merged_instances: &MergedTokenInstances<Self::Api>,
96 ) -> ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS> {
97 let mut all_token_data = ArrayVec::new();
98 let own_sc_address = self.blockchain().get_sc_address();
99 for inst in merged_instances.get_instances() {
100 let token_data = self.blockchain().get_esdt_token_data(
101 &own_sc_address,
102 &inst.token_identifier,
103 inst.token_nonce,
104 );
105 unsafe {
106 all_token_data.push_unchecked(token_data);
107 }
108 }
109
110 all_token_data
111 }
112
113 fn require_all_parts_same_creator(
114 &self,
115 all_token_data: &ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS>,
116 ) {
117 if all_token_data.is_empty() {
118 return;
119 }
120
121 let first_creator = unsafe { &all_token_data.get_unchecked(0).creator };
122 for token_data in &all_token_data.as_slice()[1..] {
123 require!(
124 &token_data.creator == first_creator,
125 DIFFERENT_CREATOR_ERR_MSG
126 );
127 }
128 }
129
130 fn get_max_royalties(
131 &self,
132 all_token_data: &ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS>,
133 ) -> BigUint {
134 let zero = BigUint::zero();
135 let mut max_ref = &zero;
136 for token_data in all_token_data {
137 if &token_data.royalties > max_ref {
138 max_ref = &token_data.royalties;
139 }
140 }
141
142 max_ref.clone()
143 }
144
145 #[view(getMergedTokenId)]
146 #[storage_mapper("mergedToken")]
147 fn merged_token(&self) -> NonFungibleTokenMapper;
148
149 #[view(getMergeableTokensWhitelist)]
150 #[storage_mapper("mergeableTokensWhitelist")]
151 fn mergeable_tokens_whitelist(&self) -> UnorderedSetMapper<EsdtTokenIdentifier>;
152}