multiversx_sc_modules/token_merge/
merged_token_setup.rs1multiversx_sc::imports!();
2
3use super::{
4 custom_merged_token_attributes::MergedTokenAttributesCreator,
5 merged_token_instances::{MergedTokenInstances, MAX_MERGED_TOKENS},
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<TokenIdentifier>) {
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(&self, tokens: MultiValueEncoded<TokenIdentifier>) {
40 let mut whitelist = self.mergeable_tokens_whitelist();
41 for token in tokens {
42 let _ = whitelist.swap_remove(&token);
43 }
44 }
45
46 fn create_merged_token<AttributesCreator: MergedTokenAttributesCreator<ScType = Self>>(
47 &self,
48 merged_token_id: TokenIdentifier,
49 merged_instances: &MergedTokenInstances<Self::Api>,
50 attr_creator: &AttributesCreator,
51 ) -> EsdtTokenPayment<Self::Api> {
52 let nft_amount = BigUint::from(NFT_AMOUNT);
53 let empty_buffer = ManagedBuffer::new();
54
55 let all_token_data = self.collect_token_data(merged_instances);
56 self.require_all_parts_same_creator(&all_token_data);
57
58 let royalties = self.get_max_royalties(&all_token_data);
59 let uri = self.create_uri_for_merged_token(merged_instances);
60 let attributes =
61 attr_creator.get_merged_token_attributes(self, &merged_token_id, merged_instances);
62 let merged_token_nonce = self.send().esdt_nft_create(
63 &merged_token_id,
64 &nft_amount,
65 &empty_buffer,
66 &royalties,
67 &empty_buffer,
68 &attributes,
69 &ManagedVec::from_single_item(uri),
70 );
71
72 EsdtTokenPayment::new(merged_token_id, merged_token_nonce, nft_amount)
73 }
74
75 fn create_uri_for_merged_token(
76 &self,
77 merged_instances: &MergedTokenInstances<Self::Api>,
78 ) -> ManagedBuffer {
79 let mut tokens_list = ManagedVec::<Self::Api, _>::new();
80 for inst in merged_instances.get_instances() {
81 tokens_list.push(inst.clone());
82 }
83
84 let mut encoded = ManagedBuffer::new();
85 let _ = tokens_list.top_encode(&mut encoded);
86
87 encoded
88 }
89
90 fn collect_token_data(
91 &self,
92 merged_instances: &MergedTokenInstances<Self::Api>,
93 ) -> ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS> {
94 let mut all_token_data = ArrayVec::new();
95 let own_sc_address = self.blockchain().get_sc_address();
96 for inst in merged_instances.get_instances() {
97 let token_data = self.blockchain().get_esdt_token_data(
98 &own_sc_address,
99 &inst.token_identifier,
100 inst.token_nonce,
101 );
102 unsafe {
103 all_token_data.push_unchecked(token_data);
104 }
105 }
106
107 all_token_data
108 }
109
110 fn require_all_parts_same_creator(
111 &self,
112 all_token_data: &ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS>,
113 ) {
114 if all_token_data.is_empty() {
115 return;
116 }
117
118 let first_creator = unsafe { &all_token_data.get_unchecked(0).creator };
119 for token_data in &all_token_data.as_slice()[1..] {
120 require!(
121 &token_data.creator == first_creator,
122 DIFFERENT_CREATOR_ERR_MSG
123 );
124 }
125 }
126
127 fn get_max_royalties(
128 &self,
129 all_token_data: &ArrayVec<EsdtTokenData<Self::Api>, MAX_MERGED_TOKENS>,
130 ) -> BigUint {
131 let zero = BigUint::zero();
132 let mut max_ref = &zero;
133 for token_data in all_token_data {
134 if &token_data.royalties > max_ref {
135 max_ref = &token_data.royalties;
136 }
137 }
138
139 max_ref.clone()
140 }
141
142 #[view(getMergedTokenId)]
143 #[storage_mapper("mergedToken")]
144 fn merged_token(&self) -> NonFungibleTokenMapper;
145
146 #[view(getMergeableTokensWhitelist)]
147 #[storage_mapper("mergeableTokensWhitelist")]
148 fn mergeable_tokens_whitelist(&self) -> UnorderedSetMapper<TokenIdentifier>;
149}