From e7d05caa4220d7c65a81ea175ddecce520ccc802 Mon Sep 17 00:00:00 2001 From: Bucur David Date: Mon, 22 Apr 2024 14:49:58 +0300 Subject: [PATCH 1/4] feat: SFT donation treasury Refs: #81 --- src/errors.rs | 1 + src/events.rs | 13 +++++++++- src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++++++----- src/requirements.rs | 4 +++ src/storage.rs | 8 ++++++ src/views.rs | 3 +++ 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 53a6896..0bf3ea7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -38,3 +38,4 @@ pub const ERR_ONLY_WITHDRAWAL_ADDRESS_CAN_WITHDRAW: &str = pub const ERR_WITHDRAWAL_ADDRESS_NOT_SET: &str = "Withdrawal address not set"; pub const ERR_WRONG_AMOUNT_OF_FUNDS: &str = "Wrong amount of funds"; pub const ERR_WRONG_BOND_PERIOD: &str = "Wrong bond period"; +pub const ERR_PERCENTAGE_TOO_HIGH: &str = "Percentage too high"; diff --git a/src/events.rs b/src/events.rs index 8fe303a..6e79975 100644 --- a/src/events.rs +++ b/src/events.rs @@ -11,6 +11,17 @@ pub trait EventsModule { #[event("setTreasuryAddress")] fn treasury_address_event(&self, #[indexed] treasury_address: &ManagedAddress); + // Emitted whenever donation treasury address is set + #[event("setDonationTreasuryAddress")] + fn donation_treasury_address_event( + &self, + #[indexed] donation_treasury_address: &ManagedAddress, + ); + + // Emitted whenever max donation percentage is set + #[event("setMaxDonationPercentage")] + fn max_donation_percentage_event(&self, #[indexed] max_donation_percentage: &u64); + // Emitted whenever whitelist enabling changes value #[event("whitelistEnableToggle")] fn whitelist_enable_toggle_event(&self, #[indexed] enable_value: &bool); @@ -129,7 +140,7 @@ pub trait EventsModule { #[indexed] token: &EgldOrEsdtTokenIdentifier, #[indexed] price: &BigUint, #[indexed] bond_amount: &BigUint, - #[indexed] extra_assets: &ManagedVec + #[indexed] extra_assets: &ManagedVec, ); #[event("setWithdrawalAddress")] diff --git a/src/lib.rs b/src/lib.rs index 7e2faac..3813528 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,8 @@ 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_FUNDS, - ERR_WRONG_BOND_PERIOD, + ERR_ISSUE_COST, ERR_NOT_IN_WHITELIST, ERR_PERCENTAGE_TOO_HIGH, ERR_WHITELIST_IS_EMPTY, + ERR_WRONG_AMOUNT_OF_FUNDS, ERR_WRONG_BOND_PERIOD, }, storage::DataNftAttributes, }; @@ -148,6 +148,7 @@ pub trait DataNftMint: title: ManagedBuffer, description: ManagedBuffer, lock_period_sec: u64, + donation_percentage: u64, extra_assets: MultiValueEncoded, ) -> DataNftAttributes { self.require_ready_for_minting_and_burning(); @@ -161,6 +162,23 @@ pub trait DataNftMint: self.require_title_description_are_valid(&title, &description); self.require_sft_is_valid(&royalties, &supply); + sc_print!("donation percentage: {} ", donation_percentage.clone()); + + let donation_supply = if donation_percentage > 0 { + require!( + donation_percentage <= self.max_donation_percentage().get(), + ERR_PERCENTAGE_TOO_HIGH + ); + + let donation_supply = + &supply * &BigUint::from(donation_percentage) / BigUint::from(10_000u64); + donation_supply + } else { + BigUint::zero() + }; + + sc_print!("donation supply:{}", donation_supply); + let caller = self.blockchain().get_caller(); let current_time = self.blockchain().get_block_timestamp(); self.require_minting_is_allowed(&caller, current_time); @@ -206,14 +224,14 @@ pub trait DataNftMint: }; let token_identifier = self.token_id().get_token_id(); - let extra_assets_vec = extra_assets.into_vec_of_buffers(); + 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 + &extra_assets_vec, ); let nonce = self.send().esdt_nft_create( @@ -234,8 +252,24 @@ pub trait DataNftMint: payment, ); - self.send() - .direct_esdt(&caller, &token_identifier, nonce, &supply); + if donation_supply > BigUint::zero() { + let donation_treasury_address = self.donation_treasury_address().get(); + self.send().direct_esdt( + &donation_treasury_address, + &token_identifier, + nonce, + &donation_supply, + ); + self.send().direct_esdt( + &caller, + &token_identifier, + nonce, + &(&supply - &donation_supply), + ); + } else { + self.send() + .direct_esdt(&caller, &token_identifier, nonce, &supply); + } attributes } @@ -268,6 +302,21 @@ pub trait DataNftMint: self.treasury_address().set(&address); } + #[endpoint(setDonationTreasuryAddress)] + fn set_donation_treasury_address(&self, address: ManagedAddress) { + self.require_is_privileged(&self.blockchain().get_caller()); + self.donation_treasury_address_event(&address); + self.donation_treasury_address().set(&address); + } + + #[endpoint(setMaxDonationPercentage)] + fn set_max_donation_percentage(&self, percentage: u64) { + self.require_is_privileged(&self.blockchain().get_caller()); + require!(percentage <= 10_000, ERR_PERCENTAGE_TOO_HIGH); + self.max_donation_percentage_event(&percentage); + self.max_donation_percentage().set(percentage); + } + // Endpoint that will be used by privileged address to change the contract pause value. #[endpoint(setIsPaused)] fn set_is_paused(&self, is_paused: bool) { diff --git a/src/requirements.rs b/src/requirements.rs index de5fdc3..6b55c94 100644 --- a/src/requirements.rs +++ b/src/requirements.rs @@ -26,6 +26,7 @@ pub trait RequirementsModule: crate::storage::StorageModule { if self.treasury_address().is_empty() { is_mint_ready = false; } + if self.bond_contract_address().is_empty() { is_mint_ready = false; } @@ -35,6 +36,9 @@ pub trait RequirementsModule: crate::storage::StorageModule { if self.bond_contract_address().is_empty() { is_mint_ready = false; } + if self.donation_treasury_address().is_empty() { + is_mint_ready = false; + } require!(is_mint_ready, ERR_MINTING_AND_BURNING_NOT_ALLOWED); } diff --git a/src/storage.rs b/src/storage.rs index d850da3..9746d11 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -25,6 +25,14 @@ pub trait StorageModule { #[storage_mapper("treasury_address")] fn treasury_address(&self) -> SingleValueMapper; + #[view(getDonationTreasuryAddress)] + #[storage_mapper("donation_treasury_address")] + fn donation_treasury_address(&self) -> SingleValueMapper; + + #[view(getMaxDonationPercentage)] + #[storage_mapper("max_donation_percentage")] + fn max_donation_percentage(&self) -> SingleValueMapper; + #[view(getWithdrawalAddress)] #[storage_mapper("withdrawal_address")] fn withdrawal_address(&self) -> SingleValueMapper; diff --git a/src/views.rs b/src/views.rs index 953d3d8..63b86f3 100644 --- a/src/views.rs +++ b/src/views.rs @@ -18,6 +18,7 @@ pub struct UserDataOut { pub total_minted: BigUint, pub frozen: bool, pub frozen_nonces: ManagedVec, + pub max_donation_percentage: u64, } //Module that handles read-only endpoints (views) for the smart contract @@ -47,6 +48,7 @@ pub trait ViewsModule: crate::storage::StorageModule { .frozen_sfts_per_address(&address) .iter() .collect::>(); + let max_donation_percentage = self.max_donation_percentage().get(); let user_data = UserDataOut { anti_spam_tax_value, @@ -62,6 +64,7 @@ pub trait ViewsModule: crate::storage::StorageModule { total_minted, frozen, frozen_nonces, + max_donation_percentage, }; user_data } From 0c8e26282dc1787ccba7c64ef3ae58f8430a290b Mon Sep 17 00:00:00 2001 From: Bucur David Date: Mon, 22 Apr 2024 14:50:19 +0300 Subject: [PATCH 2/4] test: SFT donation treasury feature tests Refs: #81 --- tests/endpoints/burn.rs | 1 + tests/endpoints/mint.rs | 171 ++++++++++++++++++++++++++++- tests/minter_state/minter_state.rs | 46 +++++++- tests/unit_test.rs | 6 + wasm/src/lib.rs | 8 +- 5 files changed, 227 insertions(+), 5 deletions(-) diff --git a/tests/endpoints/burn.rs b/tests/endpoints/burn.rs index 61ca39b..74c462d 100644 --- a/tests/endpoints/burn.rs +++ b/tests/endpoints/burn.rs @@ -44,6 +44,7 @@ fn burn_token_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 100u64 + 100u64, + 0u64, None, ); diff --git a/tests/endpoints/mint.rs b/tests/endpoints/mint.rs index c7887e5..6dd660e 100644 --- a/tests/endpoints/mint.rs +++ b/tests/endpoints/mint.rs @@ -9,7 +9,7 @@ use crate::minter_state::minter_state::{ ContractsState, BONDING_CONTRACT_ADDRESS_EXPR, BONDING_OWNER_ADDRESS_EXPR, DATA_NFT_IDENTIFIER_EXPR, FIRST_USER_ADDRESS_EXPR, ITHEUM_TOKEN_IDENTIFIER, ITHEUM_TOKEN_IDENTIFIER_EXPR, MINTER_CONTRACT_ADDRESS_EXPR, MINTER_OWNER_ADDRESS_EXPR, - TREAASURY_ADDRESS_EXPR, + SECOND_USER_ADDRESS_EXPR, TREAASURY_ADDRESS_EXPR, }; #[test] @@ -34,6 +34,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Minting and burning not allowed")), ); @@ -57,6 +58,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Data Stream is empty")), ); @@ -76,6 +78,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL must start with https://")), ); @@ -95,6 +98,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL is empty")), ); @@ -114,6 +118,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL length is too small")), ); @@ -133,6 +138,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL length is too big")), ); @@ -152,6 +158,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL must start with https://")), ); @@ -171,6 +178,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:URL must start with https://")), ); @@ -190,6 +198,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Field is empty")), ); @@ -209,6 +218,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Field is empty")), ); @@ -228,6 +238,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Too many characters")), ); @@ -247,6 +258,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Too many characters")), ); @@ -266,6 +278,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error( "str:Royalties are bigger than max royalties", )), @@ -287,6 +300,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Max supply exceeded")), ); @@ -306,6 +320,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error( "str:You need to wait more time before minting again", )), @@ -331,6 +346,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:You are not whitelisted")), ); @@ -354,6 +370,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 0u64, + 0u64, Some(TxExpect::user_error("str:Wrong bond period")), ); @@ -375,6 +392,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 10 + 100u64, + 0u64, Some(TxExpect::user_error("str:Wrong amount of funds")), ); @@ -394,6 +412,7 @@ fn mint_test_without_anti_spam_tax_test() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 100u64, + 0u64, None, ); @@ -449,6 +468,7 @@ fn mint_with_anti_spam_tax_test_and_whitelist() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 100u64, + 0u64, Some(TxExpect::user_error("str:Wrong amount of funds")), ); @@ -468,6 +488,7 @@ fn mint_with_anti_spam_tax_test_and_whitelist() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 99u64 + 100u64, + 0u64, Some(TxExpect::user_error("str:Wrong amount of funds")), ); @@ -487,6 +508,7 @@ fn mint_with_anti_spam_tax_test_and_whitelist() { ITHEUM_TOKEN_IDENTIFIER, 0u64, 100u64 + 100u64, + 0u64, None, ); @@ -531,3 +553,150 @@ fn mint_with_anti_spam_tax_test_and_whitelist() { ), ); } + +#[test] +fn mint_with_donation_to_treasury() { + let mut state = ContractsState::new(); + let treasury_address = state.treasury.clone(); + let first_user_address = state.first_user.clone(); + let second_user_address = state.second_user.clone(); + + state + .world + .set_state_step(SetStateStep::new().block_timestamp(0u64)); + + state + .mock_minter_initialized(ITHEUM_TOKEN_IDENTIFIER, 100u64, 10u64) + .unpause_minter_contract(MINTER_OWNER_ADDRESS_EXPR, None) + .bond_contract_default_deploy_and_set(10u64, 100u64) + .bond_unpause_contract(BONDING_OWNER_ADDRESS_EXPR, None) + .minter_set_donation_treasury_address( + MINTER_OWNER_ADDRESS_EXPR, + treasury_address.clone(), + None, + ) + .minter_disable_whitelist(MINTER_OWNER_ADDRESS_EXPR, None) + .minter_set_mint_time_limit(MINTER_OWNER_ADDRESS_EXPR, 0u64, None) + .minter_set_max_supply(MINTER_OWNER_ADDRESS_EXPR, 1_000u64, None) + .minter_set_donation_max_percentage(MINTER_OWNER_ADDRESS_EXPR, 1_000, None); + + state.minter_mint( + FIRST_USER_ADDRESS_EXPR, + "Test", + "https://test.com/test", + "https://test.com/test", + "https://test.com/test", + "random-url-encoded-here", + "https://test.com/test", + 1000u64, + 100u64, + &"Test title".repeat(1), + &"Test description".repeat(1), + 10u64, + ITHEUM_TOKEN_IDENTIFIER, + 0u64, + 100u64 + 100u64, + 5_000u64, // 1% + Some(TxExpect::user_error("str:Percentage too high")), + ); + + state.minter_mint( + FIRST_USER_ADDRESS_EXPR, + "Test", + "https://test.com/test", + "https://test.com/test", + "https://test.com/test", + "random-url-encoded-here", + "https://test.com/test", + 1000u64, + 100u64, + &"Test title".repeat(1), + &"Test description".repeat(1), + 10u64, + ITHEUM_TOKEN_IDENTIFIER, + 0u64, + 100u64 + 100u64, + 0, + None, + ); + + let data_nft_attributes: DataNftAttributes = DataNftAttributes { + data_stream_url: managed_buffer!(b"random-url-encoded-here"), + data_preview_url: managed_buffer!(b"https://test.com/test"), + data_marshal_url: managed_buffer!(b"https://test.com/test"), + creator: managed_address!(&first_user_address), + creation_time: 0u64, + title: managed_buffer!(b"Test title"), + description: managed_buffer!(b"Test description"), + }; + + state + .world + .check_state_step(CheckStateStep::new().put_account( + FIRST_USER_ADDRESS_EXPR, + CheckAccount::new().esdt_nft_balance_and_attributes( + DATA_NFT_IDENTIFIER_EXPR, + 1u64, + "100", + Some(data_nft_attributes.clone()), + ), + )); + + state + .world + .set_state_step(SetStateStep::new().block_timestamp(1u64)); + + state.minter_mint( + SECOND_USER_ADDRESS_EXPR, + "Test", + "https://test.com/test", + "https://test.com/test", + "https://test.com/test", + "random-url-encoded-here", + "https://test.com/test", + 1000u64, + 100u64, + &"Test title".repeat(1), + &"Test description".repeat(1), + 10u64, + ITHEUM_TOKEN_IDENTIFIER, + 0u64, + 100u64 + 100u64, + 100u64, + None, + ); + + let data_nft_attributes: DataNftAttributes = DataNftAttributes { + data_stream_url: managed_buffer!(b"random-url-encoded-here"), + data_preview_url: managed_buffer!(b"https://test.com/test"), + data_marshal_url: managed_buffer!(b"https://test.com/test"), + creator: managed_address!(&second_user_address), + creation_time: 1u64, + title: managed_buffer!(b"Test title"), + description: managed_buffer!(b"Test description"), + }; + + state + .world + .check_state_step(CheckStateStep::new().put_account( + SECOND_USER_ADDRESS_EXPR, + CheckAccount::new().esdt_nft_balance_and_attributes( + DATA_NFT_IDENTIFIER_EXPR, + 2u64, + "99", + Some(data_nft_attributes.clone()), + ), + )); + + state + .world + .check_state_step(CheckStateStep::new().put_account( + TREAASURY_ADDRESS_EXPR, + CheckAccount::new().esdt_nft_balance_and_attributes( + DATA_NFT_IDENTIFIER_EXPR, + 2u64, + "1", + Some(data_nft_attributes.clone()), + ), + )); +} diff --git a/tests/minter_state/minter_state.rs b/tests/minter_state/minter_state.rs index c54aae0..78af845 100644 --- a/tests/minter_state/minter_state.rs +++ b/tests/minter_state/minter_state.rs @@ -287,6 +287,41 @@ impl ContractsState { self } + pub fn minter_set_donation_treasury_address( + &mut self, + caller: &str, + address: Address, + expect: Option, + ) -> &mut Self { + let tx_expect = expect.unwrap_or(TxExpect::ok()); + self.world.sc_call( + ScCallStep::new() + .from(caller) + .call(self.minter_contract.set_donation_treasury_address(address)) + .expect(tx_expect), + ); + self + } + + pub fn minter_set_donation_max_percentage( + &mut self, + caller: &str, + max_donation_percentage: u64, + expect: Option, + ) -> &mut Self { + let tx_expect = expect.unwrap_or(TxExpect::ok()); + self.world.sc_call( + ScCallStep::new() + .from(caller) + .call( + self.minter_contract + .set_max_donation_percentage(max_donation_percentage), + ) + .expect(tx_expect), + ); + self + } + pub fn pause_minter_contract(&mut self, caller: &str, expect: Option) -> &mut Self { let tx_expect = expect.unwrap_or(TxExpect::ok()); self.world.sc_call( @@ -543,6 +578,7 @@ impl ContractsState { payment_token_identifier: &[u8], payment_token_nonce: u64, payment_amount: u64, + donation_percentage: u64, expect: Option, ) -> &mut Self { self.world.sc_call( @@ -565,7 +601,8 @@ impl ContractsState { title, description, lock_period, - MultiValueEncoded::new() + donation_percentage, + MultiValueEncoded::new(), )) .expect(expect.unwrap_or(TxExpect::ok())), ); @@ -654,7 +691,12 @@ impl ContractsState { self.minter_set_royalties_limits(MINTER_OWNER_ADDRESS_EXPR, 0u64, 8000u64, None); self.minter_set_administarator(MINTER_OWNER_ADDRESS_EXPR, admin, None); self.minter_set_bond_contract_address(MINTER_OWNER_ADDRESS_EXPR, None); - self.minter_set_treasury_address(MINTER_OWNER_ADDRESS_EXPR, treasury_address, None); + self.minter_set_treasury_address(MINTER_OWNER_ADDRESS_EXPR, treasury_address.clone(), None); + self.minter_set_donation_treasury_address( + MINTER_ADMIN_ADDRESS_EXPR, + treasury_address, + None, + ); self.minter_set_anti_spam_tax_token_and_amount( MINTER_OWNER_ADDRESS_EXPR, anti_spam_tax_token, diff --git a/tests/unit_test.rs b/tests/unit_test.rs index 5ba0653..4af854a 100644 --- a/tests/unit_test.rs +++ b/tests/unit_test.rs @@ -140,6 +140,12 @@ fn minter_contract_ready_test() { minter_contract.roles_are_set().set(true); + minter_contract + .donation_treasury_address() + .set(managed_address!( + &AddressValue::from("address:donation").to_address() + )); + minter_contract.require_ready_for_minting_and_burning(); }); diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 0fc1b9a..a8ad5ad 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 48 +// Endpoints: 52 // Async Callback: 1 -// Total number of exported functions: 50 +// Total number of exported functions: 54 #![no_std] #![allow(internal_features)] @@ -26,6 +26,8 @@ multiversx_sc_wasm_adapter::endpoints! { mint => mint_token burn => burn_token setTreasuryAddress => set_treasury_address + setDonationTreasuryAddress => set_donation_treasury_address + setMaxDonationPercentage => set_max_donation_percentage setIsPaused => set_is_paused setWhiteListEnabled => set_whitelist_enabled setAntiSpamTax => set_anti_spam_tax @@ -40,6 +42,8 @@ multiversx_sc_wasm_adapter::endpoints! { withdraw => withdraw getTokenId => token_id getTreasuryAddress => treasury_address + getDonationTreasuryAddress => donation_treasury_address + getMaxDonationPercentage => max_donation_percentage getWithdrawalAddress => withdrawal_address getMintedTokens => minted_tokens getAntiSpamTax => anti_spam_tax From 2a0aadc4ec2616b428e791d826ea4b5860d43e3c Mon Sep 17 00:00:00 2001 From: Bucur David Date: Tue, 23 Apr 2024 15:37:42 +0300 Subject: [PATCH 3/4] chore: devnet snippets for donation feature Refs: #81 --- interaction/devnet.snippets.sh | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/interaction/devnet.snippets.sh b/interaction/devnet.snippets.sh index e678433..5c65a77 100644 --- a/interaction/devnet.snippets.sh +++ b/interaction/devnet.snippets.sh @@ -382,6 +382,42 @@ setAdministrator(){ --send || return } + +setDonationTreasuryAddress(){ + + # $1 = address + + address="0x$(mxpy wallet bech32 --decode ${1})" + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --pem=${WALLET} \ + --gas-limit=6000000 \ + --function "setDonationTreasuryAddress" \ + --arguments $address \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --send || return + +} + + +setMaxDonationPercentage(){ + + # $1 = max donation percentage value (1% -> 100 ; 100% -> 10000) + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --pem=${WALLET} \ + --gas-limit=6000000 \ + --function "setMaxDonationPercentage" \ + --arguments ${1} \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --send || return + +} + mintTokenUsingEsdt(){ # $1 = amount of esdt to send # $2 = name From 1cc95ebeb65844ab6067497e91c9c0ad23cdf96f Mon Sep 17 00:00:00 2001 From: Mark Paul Date: Wed, 24 Apr 2024 00:23:45 +1000 Subject: [PATCH 4/4] chore: remove print lines from code, built using reproducible builds and confirmed all works. ready for launch if QA passes --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 +-- interaction/devnet.snippets.sh | 67 +++++++++++++++------------------ interaction/mainnet.snippets.sh | 33 ++++++++++++++++ meta/Cargo.lock | 4 +- meta/Cargo.toml | 2 +- src/lib.rs | 4 -- wasm/Cargo.lock | 2 +- 9 files changed, 73 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2806029..a77c492 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,7 +390,7 @@ dependencies = [ [[package]] name = "datanftmint" -version = "3.0.0" +version = "4.0.0" dependencies = [ "core-mx-life-bonding-sc", "multiversx-sc", diff --git a/Cargo.toml b/Cargo.toml index 71878ef..2d97d3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "datanftmint" -version = "3.0.0" +version = "4.0.0" edition = "2021" publish = false authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum"] diff --git a/README.md b/README.md index b5a588d..6233bdd 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ This smart contract aims to offer the MultiversX community an audited NFT minter ### Setting up dev environment (project development bootstrap) + how to build (and upgrade) -- Uses `multiversx-sc-* 0.39.4` (In v3.0.0, we used 0.47.5) SDK libs (see Cargo.toml) -- Building requires minimum **mxpy 6.1.1** (In v2.0.0, we used mxpy 9.5.1). Check version using `mxpy --version` +- Uses `multiversx-sc-* 0.39.4` (In v3.0.0 and v4.0.0, we used 0.47.5) SDK libs (see Cargo.toml) +- Building requires minimum **mxpy 6.1.1** (In >v2.0.0, we used mxpy 9.5.1). Check version using `mxpy --version` - To build the project, requires minimum Rust version `1.76.0-nightly` (In v3.0.0, we used 1.76.0-nightly). Check your Rust version by running `rustc --version`. To update your Rust, run `rustup update`. To set to nightly run `rustup default nightly`. Note that `mxpy deps install rust --overwrite` also brings in it's own compatible rust version so running `rustup default nightly` might have a higher rust version than what is used via `mxpy deps install rust --overwrite`. - After you make sure you have the minimum Rust version you can then begin development. After you clone repo and before you run build, deploy or run the tests - follow these steps (most likely only needed the 1st time) - [Upgrades] Note that when we upgrade smart contract, we should again follow the steps below too as lib version may have changed (but for upgrade I skipped the rustup default nightly cmd and did the others) @@ -116,7 +116,7 @@ Once the main commit is locked in, we can then produce the code hash and build t Note that if you already have a output-docker from a previous build and deploy then delete this folder. -Also note that if you are upgrading you may need to use a newer docker `sdk-rust-contract-builder` version. You can see the tags here https://hub.docker.com/r/multiversx/sdk-rust-contract-builder/tags. In v2.0.0, we used v5.3.0 and for v3.0.0, we used v6.1.1 for the build to upgrade to. We tested this on devnet before doing it on mainnet. +Also note that if you are upgrading you may need to use a newer docker `sdk-rust-contract-builder` version. You can see the tags here https://hub.docker.com/r/multiversx/sdk-rust-contract-builder/tags. In v2.0.0, we used v5.3.0 and for v3.0.0, v4.0.0, we used v6.1.1 for the build to upgrade to. We tested this on devnet before doing it on mainnet. This process may take some time. After it's done you should see "Docker build ran successfully!". An output-docker folder will be created containing the WASM files built in a reproducible way and artifacts.json containing the code hash of the WASM files. diff --git a/interaction/devnet.snippets.sh b/interaction/devnet.snippets.sh index 5c65a77..b4b66a1 100644 --- a/interaction/devnet.snippets.sh +++ b/interaction/devnet.snippets.sh @@ -382,42 +382,6 @@ setAdministrator(){ --send || return } - -setDonationTreasuryAddress(){ - - # $1 = address - - address="0x$(mxpy wallet bech32 --decode ${1})" - - mxpy --verbose contract call ${ADDRESS} \ - --recall-nonce \ - --pem=${WALLET} \ - --gas-limit=6000000 \ - --function "setDonationTreasuryAddress" \ - --arguments $address \ - --proxy ${PROXY} \ - --chain ${CHAIN_ID} \ - --send || return - -} - - -setMaxDonationPercentage(){ - - # $1 = max donation percentage value (1% -> 100 ; 100% -> 10000) - - mxpy --verbose contract call ${ADDRESS} \ - --recall-nonce \ - --pem=${WALLET} \ - --gas-limit=6000000 \ - --function "setMaxDonationPercentage" \ - --arguments ${1} \ - --proxy ${PROXY} \ - --chain ${CHAIN_ID} \ - --send || return - -} - mintTokenUsingEsdt(){ # $1 = amount of esdt to send # $2 = name @@ -554,3 +518,34 @@ setBondContractAddress(){ --chain ${CHAIN_ID} \ --send || return } + +# v4.0.0 +setMaxDonationPercentage(){ + # $1 = max donation percentage value (1% -> 100 ; 100% -> 10000) + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --pem=${WALLET} \ + --gas-limit=6000000 \ + --function "setMaxDonationPercentage" \ + --arguments ${1} \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --send || return +} + +setDonationTreasuryAddress(){ + # $1 = address + + address="0x$(mxpy wallet bech32 --decode ${1})" + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --pem=${WALLET} \ + --gas-limit=6000000 \ + --function "setDonationTreasuryAddress" \ + --arguments $address \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --send || return +} diff --git a/interaction/mainnet.snippets.sh b/interaction/mainnet.snippets.sh index 9b9e049..15f1c47 100644 --- a/interaction/mainnet.snippets.sh +++ b/interaction/mainnet.snippets.sh @@ -522,3 +522,36 @@ setBondContractAddressMainnet(){ --ledger-address-index 0 \ --send || return } + +# v4.0.0 +setMaxDonationPercentageMainnet(){ + # $1 = max donation percentage value (1% -> 100 ; 100% -> 10000) + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --gas-limit=6000000 \ + --function "setMaxDonationPercentage" \ + --arguments ${1} \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --ledger \ + --ledger-address-index 0 \ + --send || return +} + +setDonationTreasuryAddressMainnet(){ + # $1 = address + + address="0x$(mxpy wallet bech32 --decode ${1})" + + mxpy --verbose contract call ${ADDRESS} \ + --recall-nonce \ + --gas-limit=6000000 \ + --function "setDonationTreasuryAddress" \ + --arguments $address \ + --proxy ${PROXY} \ + --chain ${CHAIN_ID} \ + --ledger \ + --ledger-address-index 0 \ + --send || return +} diff --git a/meta/Cargo.lock b/meta/Cargo.lock index 29d6b18..c1c580a 100644 --- a/meta/Cargo.lock +++ b/meta/Cargo.lock @@ -303,14 +303,14 @@ dependencies = [ [[package]] name = "datanftmint" -version = "3.0.0" +version = "4.0.0" dependencies = [ "multiversx-sc", ] [[package]] name = "datanftmint-meta" -version = "3.0.0" +version = "4.0.0" dependencies = [ "datanftmint", "multiversx-sc", diff --git a/meta/Cargo.toml b/meta/Cargo.toml index 21ab852..d9d1668 100644 --- a/meta/Cargo.toml +++ b/meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "datanftmint-meta" -version = "3.0.0" +version = "4.0.0" edition = "2021" publish = false authors = [ "Ovidiu Damian - Itheum","Bucur David - Itheum","Mark Paul - Itheum"] diff --git a/src/lib.rs b/src/lib.rs index 3813528..e4e68c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,8 +162,6 @@ pub trait DataNftMint: self.require_title_description_are_valid(&title, &description); self.require_sft_is_valid(&royalties, &supply); - sc_print!("donation percentage: {} ", donation_percentage.clone()); - let donation_supply = if donation_percentage > 0 { require!( donation_percentage <= self.max_donation_percentage().get(), @@ -177,8 +175,6 @@ pub trait DataNftMint: BigUint::zero() }; - sc_print!("donation supply:{}", donation_supply); - let caller = self.blockchain().get_caller(); let current_time = self.blockchain().get_block_timestamp(); self.require_minting_is_allowed(&caller, current_time); diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 3288287..3ac8f9e 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -22,7 +22,7 @@ checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "datanftmint" -version = "3.0.0" +version = "4.0.0" dependencies = [ "multiversx-sc", ]