git.delta.rocks / unique-network / refs/commits / 469576010118

difftreelog

CORE-390 Add read only flag

Trubnikov Sergey2022-06-03parent: #1009216.patch.diff
in: master

8 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -87,18 +87,16 @@
 		check_is_owner(caller, self)?;
 
 		let sponsor = T::CrossAccountId::from_eth(sponsor);
-		self.set_sponsor(sponsor.as_sub().clone());
-		save(self);
-		Ok(())
+		self.set_sponsor(sponsor.as_sub().clone()).map_err(dispatch_to_evm::<T>)?;
+		save(self)
 	}
 
 	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		if !self.confirm_sponsorship(caller.as_sub()) {
+		if !self.confirm_sponsorship(caller.as_sub()).map_err(dispatch_to_evm::<T>)? {
 			return Err(Error::Revert("Caller is not set as sponsor".into()));
 		}
-		save(self);
-		Ok(())
+		save(self)
 	}
 
 	#[solidity(rename_selector = "setCollectionLimit")]
@@ -134,8 +132,7 @@
 		}
 		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
 			.map_err(dispatch_to_evm::<T>)?;
-		save(self);
-		Ok(())
+		save(self)
 	}
 
 	#[solidity(rename_selector = "setCollectionLimit")]
@@ -162,8 +159,7 @@
 		}
 		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
 			.map_err(dispatch_to_evm::<T>)?;
-		save(self);
-		Ok(())
+		save(self)
 	}
 
 	fn contract_address(&self, _caller: caller) -> Result<address> {
@@ -296,7 +292,7 @@
 	}
 }
 
-fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {
+fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<void> {
 	let caller = T::CrossAccountId::from_eth(caller);
 	collection
 		.check_is_owner(&caller)
@@ -315,8 +311,10 @@
 	Ok(caller)
 }
 
-fn save<T: Config>(collection: &CollectionHandle<T>) {
+fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {
+	collection.check_is_read_only().map_err(dispatch_to_evm::<T>)?;
 	<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());
+	Ok(())
 }
 
 pub fn token_uri_key() -> up_data_structs::PropertyKey {
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -148,23 +148,35 @@
 					.saturating_mul(writes),
 			))
 	}
-
-	pub fn save(self) -> DispatchResult {
+	pub fn save(self) -> Result<(), DispatchError> {
+		self.check_is_read_only()?;
 		<CollectionById<T>>::insert(self.id, self.collection);
 		Ok(())
 	}
 
-	pub fn set_sponsor(&mut self, sponsor: T::AccountId) {
+	pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {
+		self.check_is_read_only()?;
 		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
+		Ok(())
 	}
 
-	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {
+	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {
+		self.check_is_read_only()?;
+
 		if self.collection.sponsorship.pending_sponsor() != Some(sender) {
-			return false;
-		};
+			return Ok(false);
+		}
 
 		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
-		true
+		Ok(true)
+	}
+
+	pub fn check_is_read_only(&self) -> DispatchResult {
+		if self.read_only {
+			return Err(<Error<T>>::CollectionNotFound)?;
+		}
+		
+		Ok(())
 	}
 }
 
@@ -434,6 +446,9 @@
 
 		/// Empty property keys are forbidden
 		EmptyPropertyKey,
+
+		/// Collection is read only
+		CollectionIsReadOnly,
 	}
 
 	#[pallet::storage]
@@ -669,6 +684,7 @@
 			sponsorship,
 			limits,
 			permissions,
+			read_only,
 		} = <CollectionById<T>>::get(collection)?;
 
 		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)
@@ -698,6 +714,7 @@
 			permissions,
 			token_property_permissions,
 			properties,
+			read_only,
 		})
 	}
 }
@@ -778,6 +795,7 @@
 					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)
 				})
 				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,
+			read_only: false,
 		};
 
 		let mut collection_properties = up_data_structs::CollectionProperties::get();
@@ -834,6 +852,7 @@
 		collection: CollectionHandle<T>,
 		sender: &T::CrossAccountId,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		ensure!(
 			collection.limits.owner_can_destroy(),
 			<Error<T>>::NoPermission,
@@ -863,6 +882,7 @@
 		sender: &T::CrossAccountId,
 		property: Property,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		collection.check_is_owner_or_admin(sender)?;
 
 		CollectionProperties::<T>::try_mutate(collection.id, |properties| {
@@ -908,6 +928,8 @@
 		sender: &T::CrossAccountId,
 		properties: Vec<Property>,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		for property in properties {
 			Self::set_collection_property(collection, sender, property)?;
 		}
@@ -920,6 +942,7 @@
 		sender: &T::CrossAccountId,
 		property_key: PropertyKey,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		collection.check_is_owner_or_admin(sender)?;
 
 		CollectionProperties::<T>::try_mutate(collection.id, |properties| {
@@ -941,6 +964,8 @@
 		sender: &T::CrossAccountId,
 		property_keys: Vec<PropertyKey>,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		for key in property_keys {
 			Self::delete_collection_property(collection, sender, key)?;
 		}
@@ -965,6 +990,7 @@
 		sender: &T::CrossAccountId,
 		property_permission: PropertyKeyPermission,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		collection.check_is_owner_or_admin(sender)?;
 
 		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);
@@ -996,6 +1022,8 @@
 		sender: &T::CrossAccountId,
 		property_permissions: Vec<PropertyKeyPermission>,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		for prop_pemission in property_permissions {
 			Self::set_property_permission(collection, sender, prop_pemission)?;
 		}
@@ -1083,6 +1111,7 @@
 		user: &T::CrossAccountId,
 		allowed: bool,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		collection.check_is_owner_or_admin(sender)?;
 
 		// =========
@@ -1102,6 +1131,7 @@
 		user: &T::CrossAccountId,
 		admin: bool,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		collection.check_is_owner_or_admin(sender)?;
 
 		let was_admin = <IsAdmin<T>>::get((collection.id, user));
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -168,6 +168,8 @@
 		owner: &T::CrossAccountId,
 		amount: u128,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		let total_supply = <TotalSupply<T>>::get(collection.id)
 			.checked_sub(amount)
 			.ok_or(<CommonError<T>>::TokenValueTooLow)?;
@@ -214,6 +216,8 @@
 		amount: u128,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		ensure!(
 			collection.limits.transfers_enabled(),
 			<CommonError<T>>::TransferNotAllowed,
@@ -283,6 +287,8 @@
 		data: BTreeMap<T::CrossAccountId, u128>,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		if !collection.is_owner_or_admin(sender) {
 			ensure!(
 				collection.permissions.mint_mode(),
@@ -384,6 +390,7 @@
 		spender: &T::CrossAccountId,
 		amount: u128,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		if collection.permissions.access() == AccessMode::AllowList {
 			collection.check_allowlist(owner)?;
 			collection.check_allowlist(spender)?;
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -336,6 +336,8 @@
 		sender: &T::CrossAccountId,
 		token: TokenId,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		let token_data =
 			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
 		ensure!(
@@ -456,6 +458,7 @@
 			&property.key,
 			is_token_create,
 		)?;
+		collection.check_is_read_only()?;
 
 		<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
 			let property = property.clone();
@@ -494,6 +497,7 @@
 		property_key: PropertyKey,
 	) -> DispatchResult {
 		Self::check_token_change_permission(collection, sender, token_id, &property_key, false)?;
+		collection.check_is_read_only()?;
 
 		<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
 			properties.remove(&property_key)
@@ -570,6 +574,8 @@
 		token_id: TokenId,
 		property_keys: Vec<PropertyKey>,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		for key in property_keys {
 			Self::delete_token_property(collection, sender, token_id, key)?;
 		}
@@ -616,6 +622,8 @@
 		token: TokenId,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+
 		ensure!(
 			collection.limits.transfers_enabled(),
 			<CommonError<T>>::TransferNotAllowed
@@ -894,6 +902,8 @@
 		token: TokenId,
 		spender: Option<&T::CrossAccountId>,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
+		
 		if collection.permissions.access() == AccessMode::AllowList {
 			collection.check_allowlist(sender)?;
 			if let Some(spender) = spender {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -234,6 +234,7 @@
 	}
 
 	pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {
+		collection.check_is_read_only()?;
 		let burnt = <TokensBurnt<T>>::get(collection.id)
 			.checked_add(1)
 			.ok_or(ArithmeticError::Overflow)?;
@@ -253,6 +254,7 @@
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		let total_supply = <TotalSupply<T>>::get((collection.id, token))
 			.checked_sub(amount)
 			.ok_or(<CommonError<T>>::TokenValueTooLow)?;
@@ -325,6 +327,7 @@
 		amount: u128,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		ensure!(
 			collection.limits.transfers_enabled(),
 			<CommonError<T>>::TransferNotAllowed
@@ -573,6 +576,7 @@
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResult {
+		collection.check_is_read_only()?;
 		if collection.permissions.access() == AccessMode::AllowList {
 			collection.check_allowlist(sender)?;
 			collection.check_allowlist(spender)?;
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -304,6 +304,7 @@
 		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
+			collection.check_is_read_only()?;
 
 			// =========
 
@@ -406,6 +407,7 @@
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
+			target_collection.check_is_read_only()?;
 			target_collection.check_is_owner(&sender)?;
 
 			target_collection.owner = new_owner.clone();
@@ -487,7 +489,7 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner(&sender)?;
 
-			target_collection.set_sponsor(new_sponsor.clone());
+			target_collection.set_sponsor(new_sponsor.clone())?;
 
 			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(
 				collection_id,
@@ -511,7 +513,7 @@
 
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			ensure!(
-				target_collection.confirm_sponsorship(&sender),
+				target_collection.confirm_sponsorship(&sender)?,
 				Error::<T>::ConfirmUnsetSponsorFail
 			);
 
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -316,6 +316,9 @@
 	#[version(2.., upper(Default::default()))]
 	pub permissions: CollectionPermissions,
 
+	#[version(2.., upper(false))]
+	pub read_only: bool,
+
 	#[version(..2)]
 	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
 
@@ -340,6 +343,7 @@
 	pub permissions: CollectionPermissions,
 	pub token_property_permissions: Vec<PropertyKeyPermission>,
 	pub properties: Vec<Property>,
+	pub read_only: bool,
 }
 
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
88 });88 });
89 });89 });
90
91 it('Create new collection is not read only', async () => {
92 await usingApi(async api => {
93 const alice = privateKey('//Alice');
94 const tx = api.tx.unique.createCollectionEx({
95 readOnly: true
96 });
97 const events = await submitTransactionAsync(alice, tx);
98 const result = getCreateCollectionResult(events);
99
100 const collection = (await getDetailedCollectionInfo(api, result.collectionId))!;
101 expect(collection.readOnly.toHuman()).to.be.false;
102 });
103 });
90});104});
91105
92describe('(!negative test!) integration test: ext. createCollection():', () => {106describe('(!negative test!) integration test: ext. createCollection():', () => {