diff --git a/src/lib.rs b/src/lib.rs index e43b7a1..48c9101 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,8 +383,13 @@ pub trait DataMarket: let mut offer = self.try_get_offer(offer_id); + let address_limit = self.max_quantity_per_address(&offer.owner, offer_id).get(); + if offer.max_quantity > BigUint::zero() { - require!(quantity <= offer.max_quantity, ERR_MAX_QUANTITY_EXCEEDED); + require!( + &quantity + &address_limit <= offer.max_quantity, + ERR_MAX_QUANTITY_EXCEEDED + ); } let payment = self.call_value().egld_or_single_esdt(); diff --git a/src/storage.rs b/src/storage.rs index 780e2e5..827ee7d 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -78,6 +78,7 @@ pub struct OfferOut { pub wanted_token_nonce: u64, pub wanted_token_amount: BigUint, pub quantity: BigUint, + pub max_quantity_per_address: BigUint, } #[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, PartialEq, Clone, Debug, TypeAbi)] @@ -191,6 +192,14 @@ pub trait StorageModule { #[storage_mapper("max_default_quantity")] fn max_default_quantity(&self) -> SingleValueMapper; + #[view(getMaxQuantityPerAddress)] + #[storage_mapper("max_quantity_per_address")] + fn max_quantity_per_address( + &self, + address: &ManagedAddress, + offer_id: u64, + ) -> SingleValueMapper; + #[view(getRoyaltiesClaimToken)] #[storage_mapper("royalties_accepted_token")] fn royalties_claim_token(&self) -> SingleValueMapper; diff --git a/src/views.rs b/src/views.rs index f443757..5a8cd0c 100644 --- a/src/views.rs +++ b/src/views.rs @@ -136,6 +136,7 @@ pub trait ViewsModule: crate::storage::StorageModule { wanted_token_amount: offer.wanted_token.amount * (fee + &BigUint::from(10000u64)) / BigUint::from(10000u64), quantity: offer.quantity, + max_quantity_per_address: offer.max_quantity, } } } diff --git a/tests/rust_tests.rs b/tests/rust_tests.rs index c4331da..7450366 100644 --- a/tests/rust_tests.rs +++ b/tests/rust_tests.rs @@ -1821,6 +1821,7 @@ fn cancel_offer_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(1u64), + max_quantity_per_address: managed_biguint!(0u64), }; let view_cancelled_offer = sc @@ -1942,6 +1943,7 @@ fn cancel_offer_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(5u64), + max_quantity_per_address: managed_biguint!(0u64), }; let view_offer = sc.view_offer(3u64).unwrap(); @@ -1999,6 +2001,7 @@ fn cancel_offer_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(3u64), + max_quantity_per_address: managed_biguint!(0u64), }; let correct_remaining_offer: OfferOut = OfferOut { @@ -2011,6 +2014,7 @@ fn cancel_offer_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(2u64), + max_quantity_per_address: managed_biguint!(0u64), }; let view_remained_offer = sc.view_offer(3u64).unwrap(); @@ -2076,6 +2080,7 @@ fn cancel_offer_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(5u64), + max_quantity_per_address: managed_biguint!(0u64), }; let is_listed = sc @@ -3207,6 +3212,7 @@ fn views_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(1u64), + max_quantity_per_address: managed_biguint!(0u64), }; let offer_out = sc.view_offer(1u64).unwrap(); @@ -3263,6 +3269,7 @@ fn views_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(1u64), + max_quantity_per_address: managed_biguint!(0u64), }; let offer_mock_2 = OfferOut:: { @@ -3275,6 +3282,7 @@ fn views_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(4u64), + max_quantity_per_address: managed_biguint!(0u64), }; let offers = sc.view_paged_offers(0u64, 1u64, OptionalValue::None); @@ -3455,6 +3463,7 @@ fn views_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(1u64), + max_quantity_per_address: managed_biguint!(0u64), }; let offers_4 = sc.view_user_listed_offers(&managed_address!(first_user_address)); @@ -3480,6 +3489,7 @@ fn views_test() { wanted_token_nonce: 0u64, wanted_token_amount: managed_biguint!(204u64), quantity: managed_biguint!(4u64), + max_quantity_per_address: managed_biguint!(0u64), }; let offers_5 = sc.view_user_listed_offers(&managed_address!(second_user_address)); diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 9b1726b..d118d63 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 44 +// Endpoints: 46 // Async Callback (empty): 1 -// Total number of exported functions: 46 +// Total number of exported functions: 48 #![no_std] #![allow(internal_features)] @@ -20,6 +20,7 @@ multiversx_sc_wasm_adapter::endpoints! { data_market ( init => init + upgrade => upgrade initializeContract => initialize_contract setDiscounts => set_discounts setFees => set_fees @@ -53,6 +54,7 @@ multiversx_sc_wasm_adapter::endpoints! { getTreasuryAddress => treasury_address getClaimsAddress => claims_address getMaxDefaultQuantity => max_default_quantity + getMaxQuantityPerAddress => max_quantity_per_address getRoyaltiesClaimToken => royalties_claim_token getAdministrator => administrator getClaimIsEnabled => claim_is_enabled