multiversx_sc_modules/token_merge/
merged_token_setup.rs

1multiversx_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}