From c79585d7107116fc8b7535cae9847cf885d5abda Mon Sep 17 00:00:00 2001 From: Damian Date: Mon, 1 May 2023 08:52:03 +0300 Subject: [PATCH 1/3] upgrade to 0.40.1 --- Cargo.lock | 36 ++- Cargo.toml | 4 +- meta/Cargo.lock | 28 ++- meta/Cargo.toml | 4 +- src/lib.rs | 656 ++++++++++++++++++++++++------------------------ wasm/Cargo.lock | 12 +- wasm/Cargo.toml | 2 +- 7 files changed, 387 insertions(+), 355 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15c9f80..958e0e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,6 +186,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cpufeatures" version = "0.2.2" @@ -526,9 +535,9 @@ dependencies = [ [[package]] name = "multiversx-chain-vm" -version = "0.1.7" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090b068fea4a7b3142226293f511e7e510fa3ae5eac6df079adc5b99cd01827e" +checksum = "d9c6b7a8bc4f7064280645ba00c340d6ad0fd678643a3979a68f08175b63d9d9" dependencies = [ "bech32", "ed25519-dalek", @@ -549,9 +558,9 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" +checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" dependencies = [ "bitflags", "hashbrown 0.13.2", @@ -587,9 +596,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" +checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" dependencies = [ "hex", "proc-macro2", @@ -600,13 +609,14 @@ dependencies = [ [[package]] name = "multiversx-sc-meta" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fc78a71e8ccd4baa3ef5167a352fc514550fc065205a2315e14b435c57f9de" +checksum = "3438341c7282c13897b91375f34ce268c5afde56859583a0ae4366b0483ce7fa" dependencies = [ "clap", "colored", "common-path", + "convert_case", "lazy_static", "multiversx-sc", "pathdiff", @@ -619,9 +629,9 @@ dependencies = [ [[package]] name = "multiversx-sc-scenario" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1445663553b6d63c8ff01bbd1f7b23212a3a68615a19f128022096c1895680" +checksum = "42b8d90eecb55302c77bd7289032292beb5463cfe855e08606fb7ac360219f86" dependencies = [ "colored", "hex", @@ -1075,6 +1085,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 486a728..b727c6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum" path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.39.7" +version = "0.40.1" [dev-dependencies.multiversx-sc-scenario] -version = "0.39.7" +version = "0.40.1" diff --git a/meta/Cargo.lock b/meta/Cargo.lock index 11afd59..cdc06f9 100644 --- a/meta/Cargo.lock +++ b/meta/Cargo.lock @@ -149,6 +149,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "datanftmint" version = "1.0.0" @@ -355,9 +364,9 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "multiversx-sc" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" +checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" dependencies = [ "bitflags", "hashbrown 0.13.2", @@ -393,9 +402,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" +checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" dependencies = [ "hex", "proc-macro2", @@ -406,13 +415,14 @@ dependencies = [ [[package]] name = "multiversx-sc-meta" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fc78a71e8ccd4baa3ef5167a352fc514550fc065205a2315e14b435c57f9de" +checksum = "3438341c7282c13897b91375f34ce268c5afde56859583a0ae4366b0483ce7fa" dependencies = [ "clap", "colored", "common-path", + "convert_case", "lazy_static", "multiversx-sc", "pathdiff", @@ -696,6 +706,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/meta/Cargo.toml b/meta/Cargo.toml index 4968750..6b8cb3e 100644 --- a/meta/Cargo.toml +++ b/meta/Cargo.toml @@ -11,7 +11,7 @@ authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum" path = ".." [dependencies.multiversx-sc] -version = "0.39.7" +version = "0.40.1" [dependencies.multiversx-sc-meta] -version = "0.39.7" +version = "0.40.1" diff --git a/src/lib.rs b/src/lib.rs index a84518c..bcb2354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,328 +1,328 @@ -#![no_std] - -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); - -use crate::{ - callbacks::CallbackProxy, - errors::{ - ERR_ALREADY_IN_WHITELIST, ERR_CONTRACT_ALREADY_INITIALIZED, ERR_DATA_STREAM_IS_EMPTY, - ERR_ISSUE_COST, ERR_NOT_IN_WHITELIST, ERR_WHITELIST_IS_EMPTY, ERR_WRONG_AMOUNT_OF_PAYMENT, - }, - storage::DataNftAttributes, -}; - -pub mod callbacks; -pub mod collection_management; -pub mod errors; -pub mod events; -pub mod nft_mint_utils; -pub mod requirements; -pub mod storage; -pub mod views; -#[multiversx_sc::contract] -pub trait DataNftMint: - storage::StorageModule - + events::EventsModule - + requirements::RequirementsModule - + nft_mint_utils::NftMintUtils - + views::ViewsModule - + callbacks::Callbacks - + collection_management::CollectionManagement -{ - // When the smart contract is deployed or upgraded, minting is automatically paused, whitelisting is enabled and default values are set - #[init] - fn init(&self) { - self.is_paused().set(true); - self.mint_pause_toggle_event(&true); - - self.whitelist_enabled().set(true); - self.whitelist_enable_toggle_event(&true); - - self.min_royalties().set_if_empty(BigUint::from(0u64)); - self.max_royalties().set_if_empty(BigUint::from(8000u64)); - - self.set_royalties_limits_event(&self.min_royalties().get(), &self.max_royalties().get()); - - self.max_supply().set_if_empty(&BigUint::from(20u64)); - - self.set_max_supply_event(&self.max_supply().get()); - } - - // Endpoint used by the owner in the first place to initialize the contract with all the data needed for the SFT token creation - #[only_owner] - #[payable("EGLD")] - #[endpoint(initializeContract)] - fn initialize_contract( - &self, - collection_name: ManagedBuffer, - token_ticker: ManagedBuffer, - anti_spam_tax_token: &EgldOrEsdtTokenIdentifier, - anti_spam_tax_value: BigUint, - mint_time_limit: u64, - treasury_address: ManagedAddress, - ) { - require!(self.token_id().is_empty(), ERR_CONTRACT_ALREADY_INITIALIZED); - let issue_cost = self.call_value().egld_value(); - require!( - issue_cost == BigUint::from(5u64) * BigUint::from(10u64).pow(16u32), - ERR_ISSUE_COST - ); - - self.set_anti_spam_tax_event(&anti_spam_tax_token, &anti_spam_tax_value); - self.anti_spam_tax(anti_spam_tax_token) - .set(anti_spam_tax_value); - - self.set_mint_time_limit_event(&mint_time_limit); - self.mint_time_limit().set(mint_time_limit); - self.treasury_address().set(&treasury_address); - // Collection issuing - self.send() - .esdt_system_sc_proxy() - .issue_semi_fungible( - issue_cost, - &collection_name, - &token_ticker, - SemiFungibleTokenProperties { - can_freeze: true, - can_wipe: true, - can_pause: true, - can_change_owner: true, - can_upgrade: true, - can_add_special_roles: true, - can_transfer_create_role: true, - }, - ) - .async_call() - .with_callback(self.callbacks().issue_callback()) - .call_and_exit(); - } - - // Endpoint used by the owner to set the special roles to the contract - #[only_owner] - #[endpoint(setLocalRoles)] - fn set_local_roles(&self) { - self.require_token_issued(); - - self.send() - .esdt_system_sc_proxy() - .set_special_roles( - &self.blockchain().get_sc_address(), - &self.token_id().get_token_id(), - [ - EsdtLocalRole::NftCreate, - EsdtLocalRole::NftBurn, - EsdtLocalRole::NftAddQuantity, - ][..] - .iter() - .cloned(), - ) - .async_call() - .with_callback(self.callbacks().set_local_roles_callback()) - .call_and_exit(); - } - - // Public endpoint used to mint Data NFT-FTs. - #[payable("*")] - #[endpoint(mint)] - fn mint_token( - &self, - name: ManagedBuffer, - media: ManagedBuffer, - metadata: ManagedBuffer, - data_marshal: ManagedBuffer, - data_stream: ManagedBuffer, - data_preview: ManagedBuffer, - royalties: BigUint, - supply: BigUint, - title: ManagedBuffer, - description: ManagedBuffer, - ) -> DataNftAttributes { - self.require_ready_for_minting_and_burning(); - require!(!data_stream.is_empty(), ERR_DATA_STREAM_IS_EMPTY); - - self.require_url_is_valid(&data_marshal); - self.require_url_is_valid(&data_preview); - self.require_url_is_valid(&media); - self.require_url_is_valid(&metadata); - - self.require_title_description_are_valid(&title, &description); - self.require_sft_is_valid(&royalties, &supply); - - let caller = self.blockchain().get_caller(); - let current_time = self.blockchain().get_block_timestamp(); - self.require_minting_is_allowed(&caller, current_time); - self.last_mint_time(&caller).set(current_time); - - let payment = self.call_value().egld_or_single_esdt(); - let price = self.anti_spam_tax(&payment.token_identifier).get(); - // The contract will panic if the user tries to use a token which is has not been set as buyable by the owner. - self.require_value_is_positive(&payment.amount); - require!(&payment.amount == &price, ERR_WRONG_AMOUNT_OF_PAYMENT); - - let one_token = BigUint::from(1u64); - self.minted_per_address(&caller) - .update(|n| *n += &one_token); - - self.minted_tokens().update(|n| *n += &one_token); - - let attributes: DataNftAttributes = DataNftAttributes { - creation_time: current_time, - creator: caller.clone(), - data_marshal_url: data_marshal.clone(), - data_stream_url: data_stream.clone(), - data_preview_url: data_preview, - title, - description, - }; - - let token_identifier = self.token_id().get_token_id(); - - self.mint_event(&caller, &one_token, &payment.token_identifier, &price); - - let nonce = self.send().esdt_nft_create( - &token_identifier, - &supply, - &name, - &royalties, - &self.create_hash_buffer(&data_marshal, &data_stream), - &attributes, - &self.create_uris(media, metadata), - ); - - self.send() - .direct_esdt(&caller, &token_identifier, nonce, &supply); - - let treasury_address = self.treasury_address().get(); - - self.send().direct( - &treasury_address, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); - - attributes - } - - // Endpoint used to burn Data NFT-FTs. - #[payable("*")] - #[endpoint(burn)] - fn burn_token(&self) { - self.require_ready_for_minting_and_burning(); - let caller = self.blockchain().get_caller(); - let payment = self.call_value().single_esdt(); - self.token_id() - .require_same_token(&payment.token_identifier); - self.require_value_is_positive(&payment.amount); - self.token_id() - .nft_burn(payment.token_nonce, &payment.amount); - self.burn_event( - &caller, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); - } - - // Endpoint used to set the treasury address. - #[only_owner] - #[endpoint(setTreasuryAddress)] - fn set_treasury_address(&self, address: ManagedAddress) { - self.treasury_address_event(&address); - self.treasury_address().set(&address); - } - - // Endpoint that will be used by privileged address to change the contract pause value. - #[endpoint(setIsPaused)] - fn set_is_paused(&self, is_paused: bool) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.mint_pause_toggle_event(&is_paused); - self.is_paused().set(is_paused); - } - - // Endpoint that will be used by privileged address to set the anti spam tax for a specific token identifier. - #[endpoint(setAntiSpamTax)] - fn set_anti_spam_tax(&self, token_id: EgldOrEsdtTokenIdentifier, tax: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.set_anti_spam_tax_event(&token_id, &tax); - self.anti_spam_tax(&token_id).set(tax); - } - - // Endpoint that will be used by the owner and privileged address to change the whitelist enable value. - #[endpoint(setWhiteListEnabled)] - fn set_whitelist_enabled(&self, is_enabled: bool) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.whitelist_enable_toggle_event(&is_enabled); - self.whitelist_enabled().set(is_enabled); - } - - // Endpoint that will be used by the owner and privileged address to set whitelist spots. - #[endpoint(setWhiteListSpots)] - fn set_whitelist_spots(&self, whitelist: MultiValueEncoded) { - require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - for item in whitelist.into_iter() { - if self.whitelist().insert(item.clone()) { - self.set_whitelist_spot_event(&item); - } else { - sc_panic!(ERR_ALREADY_IN_WHITELIST); - } - } - } - - // Endpoint that will be used by the owner privileged address to unset whitelist spots. - #[endpoint(removeWhiteListSpots)] - fn remove_whitelist_spots(&self, whitelist: MultiValueEncoded) { - require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - for item in whitelist.into_iter() { - if self.whitelist().remove(&item.clone()) { - self.remove_whitelist_spot_event(&item); - } else { - sc_panic!(ERR_NOT_IN_WHITELIST); - } - } - } - - // Endpoint that will be used by the owner to set mint time limit. - #[only_owner] - #[endpoint(setMintTimeLimit)] - fn set_mint_time_limit(&self, mint_time_limit: u64) { - self.set_mint_time_limit_event(&mint_time_limit); - self.mint_time_limit().set(mint_time_limit); - } - - // Endpoint that will be used by the owner and privileged address to set min and max royalties. - #[endpoint(setRoyaltiesLimits)] - fn set_royalties_limits(&self, min_royalties: BigUint, max_royalties: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.require_royalties_are_valid(&min_royalties, &max_royalties); - self.set_royalties_limits_event(&min_royalties, &max_royalties); - self.min_royalties().set(min_royalties); - self.max_royalties().set(max_royalties); - } - - // Endpoint that will be used by the owner and privileged address to set max supply. - #[endpoint(setMaxSupply)] - fn set_max_supply(&self, max_supply: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.set_max_supply_event(&max_supply); - self.max_supply().set(max_supply); - } - - // Endpoint that will be used by the owner to change the administrator (privileged) address. - #[only_owner] - #[endpoint(setAdministrator)] - fn set_administrator(&self, administrator: ManagedAddress) { - self.set_administrator_event(&administrator); - self.administrator().set(&administrator); - } -} +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::{ + callbacks::CallbackProxy, + errors::{ + ERR_ALREADY_IN_WHITELIST, ERR_CONTRACT_ALREADY_INITIALIZED, ERR_DATA_STREAM_IS_EMPTY, + ERR_ISSUE_COST, ERR_NOT_IN_WHITELIST, ERR_WHITELIST_IS_EMPTY, ERR_WRONG_AMOUNT_OF_PAYMENT, + }, + storage::DataNftAttributes, +}; + +pub mod callbacks; +pub mod collection_management; +pub mod errors; +pub mod events; +pub mod nft_mint_utils; +pub mod requirements; +pub mod storage; +pub mod views; +#[multiversx_sc::contract] +pub trait DataNftMint: + storage::StorageModule + + events::EventsModule + + requirements::RequirementsModule + + nft_mint_utils::NftMintUtils + + views::ViewsModule + + callbacks::Callbacks + + collection_management::CollectionManagement +{ + // When the smart contract is deployed or upgraded, minting is automatically paused, whitelisting is enabled and default values are set + #[init] + fn init(&self) { + self.is_paused().set(true); + self.mint_pause_toggle_event(&true); + + self.whitelist_enabled().set(true); + self.whitelist_enable_toggle_event(&true); + + self.min_royalties().set_if_empty(BigUint::from(0u64)); + self.max_royalties().set_if_empty(BigUint::from(8000u64)); + + self.set_royalties_limits_event(&self.min_royalties().get(), &self.max_royalties().get()); + + self.max_supply().set_if_empty(&BigUint::from(20u64)); + + self.set_max_supply_event(&self.max_supply().get()); + } + + // Endpoint used by the owner in the first place to initialize the contract with all the data needed for the SFT token creation + #[only_owner] + #[payable("EGLD")] + #[endpoint(initializeContract)] + fn initialize_contract( + &self, + collection_name: ManagedBuffer, + token_ticker: ManagedBuffer, + anti_spam_tax_token: &EgldOrEsdtTokenIdentifier, + anti_spam_tax_value: BigUint, + mint_time_limit: u64, + treasury_address: ManagedAddress, + ) { + require!(self.token_id().is_empty(), ERR_CONTRACT_ALREADY_INITIALIZED); + let issue_cost = self.call_value().egld_value().clone_value(); + require!( + issue_cost == BigUint::from(5u64) * BigUint::from(10u64).pow(16u32), + ERR_ISSUE_COST + ); + + self.set_anti_spam_tax_event(&anti_spam_tax_token, &anti_spam_tax_value); + self.anti_spam_tax(anti_spam_tax_token) + .set(anti_spam_tax_value); + + self.set_mint_time_limit_event(&mint_time_limit); + self.mint_time_limit().set(mint_time_limit); + self.treasury_address().set(&treasury_address); + // Collection issuing + self.send() + .esdt_system_sc_proxy() + .issue_semi_fungible( + issue_cost, + &collection_name, + &token_ticker, + SemiFungibleTokenProperties { + can_freeze: true, + can_wipe: true, + can_pause: true, + can_change_owner: true, + can_upgrade: true, + can_add_special_roles: true, + can_transfer_create_role: true, + }, + ) + .async_call() + .with_callback(self.callbacks().issue_callback()) + .call_and_exit(); + } + + // Endpoint used by the owner to set the special roles to the contract + #[only_owner] + #[endpoint(setLocalRoles)] + fn set_local_roles(&self) { + self.require_token_issued(); + + self.send() + .esdt_system_sc_proxy() + .set_special_roles( + &self.blockchain().get_sc_address(), + &self.token_id().get_token_id(), + [ + EsdtLocalRole::NftCreate, + EsdtLocalRole::NftBurn, + EsdtLocalRole::NftAddQuantity, + ][..] + .iter() + .cloned(), + ) + .async_call() + .with_callback(self.callbacks().set_local_roles_callback()) + .call_and_exit(); + } + + // Public endpoint used to mint Data NFT-FTs. + #[payable("*")] + #[endpoint(mint)] + fn mint_token( + &self, + name: ManagedBuffer, + media: ManagedBuffer, + metadata: ManagedBuffer, + data_marshal: ManagedBuffer, + data_stream: ManagedBuffer, + data_preview: ManagedBuffer, + royalties: BigUint, + supply: BigUint, + title: ManagedBuffer, + description: ManagedBuffer, + ) -> DataNftAttributes { + self.require_ready_for_minting_and_burning(); + require!(!data_stream.is_empty(), ERR_DATA_STREAM_IS_EMPTY); + + self.require_url_is_valid(&data_marshal); + self.require_url_is_valid(&data_preview); + self.require_url_is_valid(&media); + self.require_url_is_valid(&metadata); + + self.require_title_description_are_valid(&title, &description); + self.require_sft_is_valid(&royalties, &supply); + + let caller = self.blockchain().get_caller(); + let current_time = self.blockchain().get_block_timestamp(); + self.require_minting_is_allowed(&caller, current_time); + self.last_mint_time(&caller).set(current_time); + + let payment = self.call_value().egld_or_single_esdt(); + let price = self.anti_spam_tax(&payment.token_identifier).get(); + // The contract will panic if the user tries to use a token which is has not been set as buyable by the owner. + self.require_value_is_positive(&payment.amount); + require!(&payment.amount == &price, ERR_WRONG_AMOUNT_OF_PAYMENT); + + let one_token = BigUint::from(1u64); + self.minted_per_address(&caller) + .update(|n| *n += &one_token); + + self.minted_tokens().update(|n| *n += &one_token); + + let attributes: DataNftAttributes = DataNftAttributes { + creation_time: current_time, + creator: caller.clone(), + data_marshal_url: data_marshal.clone(), + data_stream_url: data_stream.clone(), + data_preview_url: data_preview, + title, + description, + }; + + let token_identifier = self.token_id().get_token_id(); + + self.mint_event(&caller, &one_token, &payment.token_identifier, &price); + + let nonce = self.send().esdt_nft_create( + &token_identifier, + &supply, + &name, + &royalties, + &self.create_hash_buffer(&data_marshal, &data_stream), + &attributes, + &self.create_uris(media, metadata), + ); + + self.send() + .direct_esdt(&caller, &token_identifier, nonce, &supply); + + let treasury_address = self.treasury_address().get(); + + self.send().direct( + &treasury_address, + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + + attributes + } + + // Endpoint used to burn Data NFT-FTs. + #[payable("*")] + #[endpoint(burn)] + fn burn_token(&self) { + self.require_ready_for_minting_and_burning(); + let caller = self.blockchain().get_caller(); + let payment = self.call_value().single_esdt(); + self.token_id() + .require_same_token(&payment.token_identifier); + self.require_value_is_positive(&payment.amount); + self.token_id() + .nft_burn(payment.token_nonce, &payment.amount); + self.burn_event( + &caller, + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + + // Endpoint used to set the treasury address. + #[only_owner] + #[endpoint(setTreasuryAddress)] + fn set_treasury_address(&self, address: ManagedAddress) { + self.treasury_address_event(&address); + self.treasury_address().set(&address); + } + + // Endpoint that will be used by privileged address to change the contract pause value. + #[endpoint(setIsPaused)] + fn set_is_paused(&self, is_paused: bool) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.mint_pause_toggle_event(&is_paused); + self.is_paused().set(is_paused); + } + + // Endpoint that will be used by privileged address to set the anti spam tax for a specific token identifier. + #[endpoint(setAntiSpamTax)] + fn set_anti_spam_tax(&self, token_id: EgldOrEsdtTokenIdentifier, tax: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.set_anti_spam_tax_event(&token_id, &tax); + self.anti_spam_tax(&token_id).set(tax); + } + + // Endpoint that will be used by the owner and privileged address to change the whitelist enable value. + #[endpoint(setWhiteListEnabled)] + fn set_whitelist_enabled(&self, is_enabled: bool) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.whitelist_enable_toggle_event(&is_enabled); + self.whitelist_enabled().set(is_enabled); + } + + // Endpoint that will be used by the owner and privileged address to set whitelist spots. + #[endpoint(setWhiteListSpots)] + fn set_whitelist_spots(&self, whitelist: MultiValueEncoded) { + require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + for item in whitelist.into_iter() { + if self.whitelist().insert(item.clone()) { + self.set_whitelist_spot_event(&item); + } else { + sc_panic!(ERR_ALREADY_IN_WHITELIST); + } + } + } + + // Endpoint that will be used by the owner privileged address to unset whitelist spots. + #[endpoint(removeWhiteListSpots)] + fn remove_whitelist_spots(&self, whitelist: MultiValueEncoded) { + require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + for item in whitelist.into_iter() { + if self.whitelist().remove(&item.clone()) { + self.remove_whitelist_spot_event(&item); + } else { + sc_panic!(ERR_NOT_IN_WHITELIST); + } + } + } + + // Endpoint that will be used by the owner to set mint time limit. + #[only_owner] + #[endpoint(setMintTimeLimit)] + fn set_mint_time_limit(&self, mint_time_limit: u64) { + self.set_mint_time_limit_event(&mint_time_limit); + self.mint_time_limit().set(mint_time_limit); + } + + // Endpoint that will be used by the owner and privileged address to set min and max royalties. + #[endpoint(setRoyaltiesLimits)] + fn set_royalties_limits(&self, min_royalties: BigUint, max_royalties: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.require_royalties_are_valid(&min_royalties, &max_royalties); + self.set_royalties_limits_event(&min_royalties, &max_royalties); + self.min_royalties().set(min_royalties); + self.max_royalties().set(max_royalties); + } + + // Endpoint that will be used by the owner and privileged address to set max supply. + #[endpoint(setMaxSupply)] + fn set_max_supply(&self, max_supply: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.set_max_supply_event(&max_supply); + self.max_supply().set(max_supply); + } + + // Endpoint that will be used by the owner to change the administrator (privileged) address. + #[only_owner] + #[endpoint(setAdministrator)] + fn set_administrator(&self, administrator: ManagedAddress) { + self.set_administrator_event(&administrator); + self.administrator().set(&administrator); + } +} diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 79402ef..d72f265 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -99,9 +99,9 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "multiversx-sc" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" +checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" dependencies = [ "bitflags", "hashbrown", @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" +checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" dependencies = [ "hex", "proc-macro2", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.39.7" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f093466105ea4fc5c8ec577830e9af2a7a08aacbbc0dcd104438379455a94c" +checksum = "4914fcfc5c319c1e0027978f68f8611edd3451790c998e0869c082b0cfdf1b5a" dependencies = [ "multiversx-sc", "wee_alloc", diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index bc70db8..4d451a7 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -24,4 +24,4 @@ panic = "abort" path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.39.7" \ No newline at end of file +version = "0.40.1" \ No newline at end of file From af545300dbed1dfdaf213666bcb48477cae9636e Mon Sep 17 00:00:00 2001 From: Damian Date: Mon, 8 May 2023 10:33:58 +0300 Subject: [PATCH 2/3] Revert "upgrade to 0.40.1" This reverts commit c79585d7107116fc8b7535cae9847cf885d5abda. --- Cargo.lock | 36 +-- Cargo.toml | 4 +- meta/Cargo.lock | 28 +-- meta/Cargo.toml | 4 +- src/lib.rs | 656 ++++++++++++++++++++++++------------------------ wasm/Cargo.lock | 12 +- wasm/Cargo.toml | 2 +- 7 files changed, 355 insertions(+), 387 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 958e0e5..15c9f80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,15 +186,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cpufeatures" version = "0.2.2" @@ -535,9 +526,9 @@ dependencies = [ [[package]] name = "multiversx-chain-vm" -version = "0.2.1" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c6b7a8bc4f7064280645ba00c340d6ad0fd678643a3979a68f08175b63d9d9" +checksum = "090b068fea4a7b3142226293f511e7e510fa3ae5eac6df079adc5b99cd01827e" dependencies = [ "bech32", "ed25519-dalek", @@ -558,9 +549,9 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" +checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" dependencies = [ "bitflags", "hashbrown 0.13.2", @@ -596,9 +587,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" +checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" dependencies = [ "hex", "proc-macro2", @@ -609,14 +600,13 @@ dependencies = [ [[package]] name = "multiversx-sc-meta" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3438341c7282c13897b91375f34ce268c5afde56859583a0ae4366b0483ce7fa" +checksum = "e8fc78a71e8ccd4baa3ef5167a352fc514550fc065205a2315e14b435c57f9de" dependencies = [ "clap", "colored", "common-path", - "convert_case", "lazy_static", "multiversx-sc", "pathdiff", @@ -629,9 +619,9 @@ dependencies = [ [[package]] name = "multiversx-sc-scenario" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b8d90eecb55302c77bd7289032292beb5463cfe855e08606fb7ac360219f86" +checksum = "fc1445663553b6d63c8ff01bbd1f7b23212a3a68615a19f128022096c1895680" dependencies = [ "colored", "hex", @@ -1085,12 +1075,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index b727c6e..486a728 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum" path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.40.1" +version = "0.39.7" [dev-dependencies.multiversx-sc-scenario] -version = "0.40.1" +version = "0.39.7" diff --git a/meta/Cargo.lock b/meta/Cargo.lock index cdc06f9..11afd59 100644 --- a/meta/Cargo.lock +++ b/meta/Cargo.lock @@ -149,15 +149,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "datanftmint" version = "1.0.0" @@ -364,9 +355,9 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "multiversx-sc" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" +checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" dependencies = [ "bitflags", "hashbrown 0.13.2", @@ -402,9 +393,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" +checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" dependencies = [ "hex", "proc-macro2", @@ -415,14 +406,13 @@ dependencies = [ [[package]] name = "multiversx-sc-meta" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3438341c7282c13897b91375f34ce268c5afde56859583a0ae4366b0483ce7fa" +checksum = "e8fc78a71e8ccd4baa3ef5167a352fc514550fc065205a2315e14b435c57f9de" dependencies = [ "clap", "colored", "common-path", - "convert_case", "lazy_static", "multiversx-sc", "pathdiff", @@ -706,12 +696,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/meta/Cargo.toml b/meta/Cargo.toml index 6b8cb3e..4968750 100644 --- a/meta/Cargo.toml +++ b/meta/Cargo.toml @@ -11,7 +11,7 @@ authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum" path = ".." [dependencies.multiversx-sc] -version = "0.40.1" +version = "0.39.7" [dependencies.multiversx-sc-meta] -version = "0.40.1" +version = "0.39.7" diff --git a/src/lib.rs b/src/lib.rs index bcb2354..a84518c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,328 +1,328 @@ -#![no_std] - -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); - -use crate::{ - callbacks::CallbackProxy, - errors::{ - ERR_ALREADY_IN_WHITELIST, ERR_CONTRACT_ALREADY_INITIALIZED, ERR_DATA_STREAM_IS_EMPTY, - ERR_ISSUE_COST, ERR_NOT_IN_WHITELIST, ERR_WHITELIST_IS_EMPTY, ERR_WRONG_AMOUNT_OF_PAYMENT, - }, - storage::DataNftAttributes, -}; - -pub mod callbacks; -pub mod collection_management; -pub mod errors; -pub mod events; -pub mod nft_mint_utils; -pub mod requirements; -pub mod storage; -pub mod views; -#[multiversx_sc::contract] -pub trait DataNftMint: - storage::StorageModule - + events::EventsModule - + requirements::RequirementsModule - + nft_mint_utils::NftMintUtils - + views::ViewsModule - + callbacks::Callbacks - + collection_management::CollectionManagement -{ - // When the smart contract is deployed or upgraded, minting is automatically paused, whitelisting is enabled and default values are set - #[init] - fn init(&self) { - self.is_paused().set(true); - self.mint_pause_toggle_event(&true); - - self.whitelist_enabled().set(true); - self.whitelist_enable_toggle_event(&true); - - self.min_royalties().set_if_empty(BigUint::from(0u64)); - self.max_royalties().set_if_empty(BigUint::from(8000u64)); - - self.set_royalties_limits_event(&self.min_royalties().get(), &self.max_royalties().get()); - - self.max_supply().set_if_empty(&BigUint::from(20u64)); - - self.set_max_supply_event(&self.max_supply().get()); - } - - // Endpoint used by the owner in the first place to initialize the contract with all the data needed for the SFT token creation - #[only_owner] - #[payable("EGLD")] - #[endpoint(initializeContract)] - fn initialize_contract( - &self, - collection_name: ManagedBuffer, - token_ticker: ManagedBuffer, - anti_spam_tax_token: &EgldOrEsdtTokenIdentifier, - anti_spam_tax_value: BigUint, - mint_time_limit: u64, - treasury_address: ManagedAddress, - ) { - require!(self.token_id().is_empty(), ERR_CONTRACT_ALREADY_INITIALIZED); - let issue_cost = self.call_value().egld_value().clone_value(); - require!( - issue_cost == BigUint::from(5u64) * BigUint::from(10u64).pow(16u32), - ERR_ISSUE_COST - ); - - self.set_anti_spam_tax_event(&anti_spam_tax_token, &anti_spam_tax_value); - self.anti_spam_tax(anti_spam_tax_token) - .set(anti_spam_tax_value); - - self.set_mint_time_limit_event(&mint_time_limit); - self.mint_time_limit().set(mint_time_limit); - self.treasury_address().set(&treasury_address); - // Collection issuing - self.send() - .esdt_system_sc_proxy() - .issue_semi_fungible( - issue_cost, - &collection_name, - &token_ticker, - SemiFungibleTokenProperties { - can_freeze: true, - can_wipe: true, - can_pause: true, - can_change_owner: true, - can_upgrade: true, - can_add_special_roles: true, - can_transfer_create_role: true, - }, - ) - .async_call() - .with_callback(self.callbacks().issue_callback()) - .call_and_exit(); - } - - // Endpoint used by the owner to set the special roles to the contract - #[only_owner] - #[endpoint(setLocalRoles)] - fn set_local_roles(&self) { - self.require_token_issued(); - - self.send() - .esdt_system_sc_proxy() - .set_special_roles( - &self.blockchain().get_sc_address(), - &self.token_id().get_token_id(), - [ - EsdtLocalRole::NftCreate, - EsdtLocalRole::NftBurn, - EsdtLocalRole::NftAddQuantity, - ][..] - .iter() - .cloned(), - ) - .async_call() - .with_callback(self.callbacks().set_local_roles_callback()) - .call_and_exit(); - } - - // Public endpoint used to mint Data NFT-FTs. - #[payable("*")] - #[endpoint(mint)] - fn mint_token( - &self, - name: ManagedBuffer, - media: ManagedBuffer, - metadata: ManagedBuffer, - data_marshal: ManagedBuffer, - data_stream: ManagedBuffer, - data_preview: ManagedBuffer, - royalties: BigUint, - supply: BigUint, - title: ManagedBuffer, - description: ManagedBuffer, - ) -> DataNftAttributes { - self.require_ready_for_minting_and_burning(); - require!(!data_stream.is_empty(), ERR_DATA_STREAM_IS_EMPTY); - - self.require_url_is_valid(&data_marshal); - self.require_url_is_valid(&data_preview); - self.require_url_is_valid(&media); - self.require_url_is_valid(&metadata); - - self.require_title_description_are_valid(&title, &description); - self.require_sft_is_valid(&royalties, &supply); - - let caller = self.blockchain().get_caller(); - let current_time = self.blockchain().get_block_timestamp(); - self.require_minting_is_allowed(&caller, current_time); - self.last_mint_time(&caller).set(current_time); - - let payment = self.call_value().egld_or_single_esdt(); - let price = self.anti_spam_tax(&payment.token_identifier).get(); - // The contract will panic if the user tries to use a token which is has not been set as buyable by the owner. - self.require_value_is_positive(&payment.amount); - require!(&payment.amount == &price, ERR_WRONG_AMOUNT_OF_PAYMENT); - - let one_token = BigUint::from(1u64); - self.minted_per_address(&caller) - .update(|n| *n += &one_token); - - self.minted_tokens().update(|n| *n += &one_token); - - let attributes: DataNftAttributes = DataNftAttributes { - creation_time: current_time, - creator: caller.clone(), - data_marshal_url: data_marshal.clone(), - data_stream_url: data_stream.clone(), - data_preview_url: data_preview, - title, - description, - }; - - let token_identifier = self.token_id().get_token_id(); - - self.mint_event(&caller, &one_token, &payment.token_identifier, &price); - - let nonce = self.send().esdt_nft_create( - &token_identifier, - &supply, - &name, - &royalties, - &self.create_hash_buffer(&data_marshal, &data_stream), - &attributes, - &self.create_uris(media, metadata), - ); - - self.send() - .direct_esdt(&caller, &token_identifier, nonce, &supply); - - let treasury_address = self.treasury_address().get(); - - self.send().direct( - &treasury_address, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); - - attributes - } - - // Endpoint used to burn Data NFT-FTs. - #[payable("*")] - #[endpoint(burn)] - fn burn_token(&self) { - self.require_ready_for_minting_and_burning(); - let caller = self.blockchain().get_caller(); - let payment = self.call_value().single_esdt(); - self.token_id() - .require_same_token(&payment.token_identifier); - self.require_value_is_positive(&payment.amount); - self.token_id() - .nft_burn(payment.token_nonce, &payment.amount); - self.burn_event( - &caller, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); - } - - // Endpoint used to set the treasury address. - #[only_owner] - #[endpoint(setTreasuryAddress)] - fn set_treasury_address(&self, address: ManagedAddress) { - self.treasury_address_event(&address); - self.treasury_address().set(&address); - } - - // Endpoint that will be used by privileged address to change the contract pause value. - #[endpoint(setIsPaused)] - fn set_is_paused(&self, is_paused: bool) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.mint_pause_toggle_event(&is_paused); - self.is_paused().set(is_paused); - } - - // Endpoint that will be used by privileged address to set the anti spam tax for a specific token identifier. - #[endpoint(setAntiSpamTax)] - fn set_anti_spam_tax(&self, token_id: EgldOrEsdtTokenIdentifier, tax: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.set_anti_spam_tax_event(&token_id, &tax); - self.anti_spam_tax(&token_id).set(tax); - } - - // Endpoint that will be used by the owner and privileged address to change the whitelist enable value. - #[endpoint(setWhiteListEnabled)] - fn set_whitelist_enabled(&self, is_enabled: bool) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.whitelist_enable_toggle_event(&is_enabled); - self.whitelist_enabled().set(is_enabled); - } - - // Endpoint that will be used by the owner and privileged address to set whitelist spots. - #[endpoint(setWhiteListSpots)] - fn set_whitelist_spots(&self, whitelist: MultiValueEncoded) { - require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - for item in whitelist.into_iter() { - if self.whitelist().insert(item.clone()) { - self.set_whitelist_spot_event(&item); - } else { - sc_panic!(ERR_ALREADY_IN_WHITELIST); - } - } - } - - // Endpoint that will be used by the owner privileged address to unset whitelist spots. - #[endpoint(removeWhiteListSpots)] - fn remove_whitelist_spots(&self, whitelist: MultiValueEncoded) { - require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - for item in whitelist.into_iter() { - if self.whitelist().remove(&item.clone()) { - self.remove_whitelist_spot_event(&item); - } else { - sc_panic!(ERR_NOT_IN_WHITELIST); - } - } - } - - // Endpoint that will be used by the owner to set mint time limit. - #[only_owner] - #[endpoint(setMintTimeLimit)] - fn set_mint_time_limit(&self, mint_time_limit: u64) { - self.set_mint_time_limit_event(&mint_time_limit); - self.mint_time_limit().set(mint_time_limit); - } - - // Endpoint that will be used by the owner and privileged address to set min and max royalties. - #[endpoint(setRoyaltiesLimits)] - fn set_royalties_limits(&self, min_royalties: BigUint, max_royalties: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.require_royalties_are_valid(&min_royalties, &max_royalties); - self.set_royalties_limits_event(&min_royalties, &max_royalties); - self.min_royalties().set(min_royalties); - self.max_royalties().set(max_royalties); - } - - // Endpoint that will be used by the owner and privileged address to set max supply. - #[endpoint(setMaxSupply)] - fn set_max_supply(&self, max_supply: BigUint) { - let caller = self.blockchain().get_caller(); - self.require_is_privileged(&caller); - self.set_max_supply_event(&max_supply); - self.max_supply().set(max_supply); - } - - // Endpoint that will be used by the owner to change the administrator (privileged) address. - #[only_owner] - #[endpoint(setAdministrator)] - fn set_administrator(&self, administrator: ManagedAddress) { - self.set_administrator_event(&administrator); - self.administrator().set(&administrator); - } -} +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::{ + callbacks::CallbackProxy, + errors::{ + ERR_ALREADY_IN_WHITELIST, ERR_CONTRACT_ALREADY_INITIALIZED, ERR_DATA_STREAM_IS_EMPTY, + ERR_ISSUE_COST, ERR_NOT_IN_WHITELIST, ERR_WHITELIST_IS_EMPTY, ERR_WRONG_AMOUNT_OF_PAYMENT, + }, + storage::DataNftAttributes, +}; + +pub mod callbacks; +pub mod collection_management; +pub mod errors; +pub mod events; +pub mod nft_mint_utils; +pub mod requirements; +pub mod storage; +pub mod views; +#[multiversx_sc::contract] +pub trait DataNftMint: + storage::StorageModule + + events::EventsModule + + requirements::RequirementsModule + + nft_mint_utils::NftMintUtils + + views::ViewsModule + + callbacks::Callbacks + + collection_management::CollectionManagement +{ + // When the smart contract is deployed or upgraded, minting is automatically paused, whitelisting is enabled and default values are set + #[init] + fn init(&self) { + self.is_paused().set(true); + self.mint_pause_toggle_event(&true); + + self.whitelist_enabled().set(true); + self.whitelist_enable_toggle_event(&true); + + self.min_royalties().set_if_empty(BigUint::from(0u64)); + self.max_royalties().set_if_empty(BigUint::from(8000u64)); + + self.set_royalties_limits_event(&self.min_royalties().get(), &self.max_royalties().get()); + + self.max_supply().set_if_empty(&BigUint::from(20u64)); + + self.set_max_supply_event(&self.max_supply().get()); + } + + // Endpoint used by the owner in the first place to initialize the contract with all the data needed for the SFT token creation + #[only_owner] + #[payable("EGLD")] + #[endpoint(initializeContract)] + fn initialize_contract( + &self, + collection_name: ManagedBuffer, + token_ticker: ManagedBuffer, + anti_spam_tax_token: &EgldOrEsdtTokenIdentifier, + anti_spam_tax_value: BigUint, + mint_time_limit: u64, + treasury_address: ManagedAddress, + ) { + require!(self.token_id().is_empty(), ERR_CONTRACT_ALREADY_INITIALIZED); + let issue_cost = self.call_value().egld_value(); + require!( + issue_cost == BigUint::from(5u64) * BigUint::from(10u64).pow(16u32), + ERR_ISSUE_COST + ); + + self.set_anti_spam_tax_event(&anti_spam_tax_token, &anti_spam_tax_value); + self.anti_spam_tax(anti_spam_tax_token) + .set(anti_spam_tax_value); + + self.set_mint_time_limit_event(&mint_time_limit); + self.mint_time_limit().set(mint_time_limit); + self.treasury_address().set(&treasury_address); + // Collection issuing + self.send() + .esdt_system_sc_proxy() + .issue_semi_fungible( + issue_cost, + &collection_name, + &token_ticker, + SemiFungibleTokenProperties { + can_freeze: true, + can_wipe: true, + can_pause: true, + can_change_owner: true, + can_upgrade: true, + can_add_special_roles: true, + can_transfer_create_role: true, + }, + ) + .async_call() + .with_callback(self.callbacks().issue_callback()) + .call_and_exit(); + } + + // Endpoint used by the owner to set the special roles to the contract + #[only_owner] + #[endpoint(setLocalRoles)] + fn set_local_roles(&self) { + self.require_token_issued(); + + self.send() + .esdt_system_sc_proxy() + .set_special_roles( + &self.blockchain().get_sc_address(), + &self.token_id().get_token_id(), + [ + EsdtLocalRole::NftCreate, + EsdtLocalRole::NftBurn, + EsdtLocalRole::NftAddQuantity, + ][..] + .iter() + .cloned(), + ) + .async_call() + .with_callback(self.callbacks().set_local_roles_callback()) + .call_and_exit(); + } + + // Public endpoint used to mint Data NFT-FTs. + #[payable("*")] + #[endpoint(mint)] + fn mint_token( + &self, + name: ManagedBuffer, + media: ManagedBuffer, + metadata: ManagedBuffer, + data_marshal: ManagedBuffer, + data_stream: ManagedBuffer, + data_preview: ManagedBuffer, + royalties: BigUint, + supply: BigUint, + title: ManagedBuffer, + description: ManagedBuffer, + ) -> DataNftAttributes { + self.require_ready_for_minting_and_burning(); + require!(!data_stream.is_empty(), ERR_DATA_STREAM_IS_EMPTY); + + self.require_url_is_valid(&data_marshal); + self.require_url_is_valid(&data_preview); + self.require_url_is_valid(&media); + self.require_url_is_valid(&metadata); + + self.require_title_description_are_valid(&title, &description); + self.require_sft_is_valid(&royalties, &supply); + + let caller = self.blockchain().get_caller(); + let current_time = self.blockchain().get_block_timestamp(); + self.require_minting_is_allowed(&caller, current_time); + self.last_mint_time(&caller).set(current_time); + + let payment = self.call_value().egld_or_single_esdt(); + let price = self.anti_spam_tax(&payment.token_identifier).get(); + // The contract will panic if the user tries to use a token which is has not been set as buyable by the owner. + self.require_value_is_positive(&payment.amount); + require!(&payment.amount == &price, ERR_WRONG_AMOUNT_OF_PAYMENT); + + let one_token = BigUint::from(1u64); + self.minted_per_address(&caller) + .update(|n| *n += &one_token); + + self.minted_tokens().update(|n| *n += &one_token); + + let attributes: DataNftAttributes = DataNftAttributes { + creation_time: current_time, + creator: caller.clone(), + data_marshal_url: data_marshal.clone(), + data_stream_url: data_stream.clone(), + data_preview_url: data_preview, + title, + description, + }; + + let token_identifier = self.token_id().get_token_id(); + + self.mint_event(&caller, &one_token, &payment.token_identifier, &price); + + let nonce = self.send().esdt_nft_create( + &token_identifier, + &supply, + &name, + &royalties, + &self.create_hash_buffer(&data_marshal, &data_stream), + &attributes, + &self.create_uris(media, metadata), + ); + + self.send() + .direct_esdt(&caller, &token_identifier, nonce, &supply); + + let treasury_address = self.treasury_address().get(); + + self.send().direct( + &treasury_address, + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + + attributes + } + + // Endpoint used to burn Data NFT-FTs. + #[payable("*")] + #[endpoint(burn)] + fn burn_token(&self) { + self.require_ready_for_minting_and_burning(); + let caller = self.blockchain().get_caller(); + let payment = self.call_value().single_esdt(); + self.token_id() + .require_same_token(&payment.token_identifier); + self.require_value_is_positive(&payment.amount); + self.token_id() + .nft_burn(payment.token_nonce, &payment.amount); + self.burn_event( + &caller, + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + + // Endpoint used to set the treasury address. + #[only_owner] + #[endpoint(setTreasuryAddress)] + fn set_treasury_address(&self, address: ManagedAddress) { + self.treasury_address_event(&address); + self.treasury_address().set(&address); + } + + // Endpoint that will be used by privileged address to change the contract pause value. + #[endpoint(setIsPaused)] + fn set_is_paused(&self, is_paused: bool) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.mint_pause_toggle_event(&is_paused); + self.is_paused().set(is_paused); + } + + // Endpoint that will be used by privileged address to set the anti spam tax for a specific token identifier. + #[endpoint(setAntiSpamTax)] + fn set_anti_spam_tax(&self, token_id: EgldOrEsdtTokenIdentifier, tax: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.set_anti_spam_tax_event(&token_id, &tax); + self.anti_spam_tax(&token_id).set(tax); + } + + // Endpoint that will be used by the owner and privileged address to change the whitelist enable value. + #[endpoint(setWhiteListEnabled)] + fn set_whitelist_enabled(&self, is_enabled: bool) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.whitelist_enable_toggle_event(&is_enabled); + self.whitelist_enabled().set(is_enabled); + } + + // Endpoint that will be used by the owner and privileged address to set whitelist spots. + #[endpoint(setWhiteListSpots)] + fn set_whitelist_spots(&self, whitelist: MultiValueEncoded) { + require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + for item in whitelist.into_iter() { + if self.whitelist().insert(item.clone()) { + self.set_whitelist_spot_event(&item); + } else { + sc_panic!(ERR_ALREADY_IN_WHITELIST); + } + } + } + + // Endpoint that will be used by the owner privileged address to unset whitelist spots. + #[endpoint(removeWhiteListSpots)] + fn remove_whitelist_spots(&self, whitelist: MultiValueEncoded) { + require!(!whitelist.is_empty(), ERR_WHITELIST_IS_EMPTY); + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + for item in whitelist.into_iter() { + if self.whitelist().remove(&item.clone()) { + self.remove_whitelist_spot_event(&item); + } else { + sc_panic!(ERR_NOT_IN_WHITELIST); + } + } + } + + // Endpoint that will be used by the owner to set mint time limit. + #[only_owner] + #[endpoint(setMintTimeLimit)] + fn set_mint_time_limit(&self, mint_time_limit: u64) { + self.set_mint_time_limit_event(&mint_time_limit); + self.mint_time_limit().set(mint_time_limit); + } + + // Endpoint that will be used by the owner and privileged address to set min and max royalties. + #[endpoint(setRoyaltiesLimits)] + fn set_royalties_limits(&self, min_royalties: BigUint, max_royalties: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.require_royalties_are_valid(&min_royalties, &max_royalties); + self.set_royalties_limits_event(&min_royalties, &max_royalties); + self.min_royalties().set(min_royalties); + self.max_royalties().set(max_royalties); + } + + // Endpoint that will be used by the owner and privileged address to set max supply. + #[endpoint(setMaxSupply)] + fn set_max_supply(&self, max_supply: BigUint) { + let caller = self.blockchain().get_caller(); + self.require_is_privileged(&caller); + self.set_max_supply_event(&max_supply); + self.max_supply().set(max_supply); + } + + // Endpoint that will be used by the owner to change the administrator (privileged) address. + #[only_owner] + #[endpoint(setAdministrator)] + fn set_administrator(&self, administrator: ManagedAddress) { + self.set_administrator_event(&administrator); + self.administrator().set(&administrator); + } +} diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index d72f265..79402ef 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -99,9 +99,9 @@ checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "multiversx-sc" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e871400697b360bb69c6bf8af4aa77af75b45927d9c0a71fa0e158d33bd6b52" +checksum = "75218a09f6b77f272f6a74689c0abc6152588674f7aa264368156cd661245c98" dependencies = [ "bitflags", "hashbrown", @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b5f11df0270850a81a6d413228f68de332c58dd00350dee16e376a24340351" +checksum = "768007b88e43df8120efa562bf4e79846b97043db92b860877fa3b7e9af5f771" dependencies = [ "hex", "proc-macro2", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.40.1" +version = "0.39.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4914fcfc5c319c1e0027978f68f8611edd3451790c998e0869c082b0cfdf1b5a" +checksum = "59f093466105ea4fc5c8ec577830e9af2a7a08aacbbc0dcd104438379455a94c" dependencies = [ "multiversx-sc", "wee_alloc", diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 4d451a7..bc70db8 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -24,4 +24,4 @@ panic = "abort" path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.40.1" \ No newline at end of file +version = "0.39.7" \ No newline at end of file From 480c2227489316ea37eda2106d9990452e739cb5 Mon Sep 17 00:00:00 2001 From: Damian Date: Sat, 6 Apr 2024 23:04:19 +0300 Subject: [PATCH 3/3] feat: extra assets on tokens --- src/events.rs | 1 + src/lib.rs | 6 ++++-- src/nft_mint_utils.rs | 2 ++ tests/minter_state/minter_state.rs | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/events.rs b/src/events.rs index 76a4a2c..8fe303a 100644 --- a/src/events.rs +++ b/src/events.rs @@ -129,6 +129,7 @@ pub trait EventsModule { #[indexed] token: &EgldOrEsdtTokenIdentifier, #[indexed] price: &BigUint, #[indexed] bond_amount: &BigUint, + #[indexed] extra_assets: &ManagedVec ); #[event("setWithdrawalAddress")] diff --git a/src/lib.rs b/src/lib.rs index 2be9e56..7e2faac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,6 +148,7 @@ pub trait DataNftMint: title: ManagedBuffer, description: ManagedBuffer, lock_period_sec: u64, + extra_assets: MultiValueEncoded, ) -> DataNftAttributes { self.require_ready_for_minting_and_burning(); require!(!data_stream.is_empty(), ERR_DATA_STREAM_IS_EMPTY); @@ -205,13 +206,14 @@ pub trait DataNftMint: }; let token_identifier = self.token_id().get_token_id(); - + let extra_assets_vec = extra_assets.into_vec_of_buffers(); self.mint_event( &caller, &one_token, &payment.token_identifier, &price, &payment.amount, + &extra_assets_vec ); let nonce = self.send().esdt_nft_create( @@ -221,7 +223,7 @@ pub trait DataNftMint: &royalties, &self.create_hash_buffer(&data_marshal, &data_stream), &attributes, - &self.create_uris(media, metadata), + &self.create_uris(media, metadata, extra_assets_vec), ); self.send_bond( diff --git a/src/nft_mint_utils.rs b/src/nft_mint_utils.rs index bbe07e5..5820c18 100644 --- a/src/nft_mint_utils.rs +++ b/src/nft_mint_utils.rs @@ -18,10 +18,12 @@ pub trait NftMintUtils: crate::storage::StorageModule { &self, media: ManagedBuffer, metadata: ManagedBuffer, + extra_assets: ManagedVec, ) -> ManagedVec { let mut uris = ManagedVec::new(); uris.push(media); uris.push(metadata); + uris.append_vec(extra_assets); uris } } diff --git a/tests/minter_state/minter_state.rs b/tests/minter_state/minter_state.rs index ed70780..c54aae0 100644 --- a/tests/minter_state/minter_state.rs +++ b/tests/minter_state/minter_state.rs @@ -565,6 +565,7 @@ impl ContractsState { title, description, lock_period, + MultiValueEncoded::new() )) .expect(expect.unwrap_or(TxExpect::ok())), );