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
149 ))149 ))
150 }150 }
151
152 pub fn save(self) -> DispatchResult {151 pub fn save(self) -> Result<(), DispatchError> {
152 self.check_is_read_only()?;
153 <CollectionById<T>>::insert(self.id, self.collection);153 <CollectionById<T>>::insert(self.id, self.collection);
154 Ok(())154 Ok(())
155 }155 }
156156
157 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {157 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {
158 self.check_is_read_only()?;
158 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);159 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
160 Ok(())
159 }161 }
160162
161 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {163 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {
164 self.check_is_read_only()?;
165
162 if self.collection.sponsorship.pending_sponsor() != Some(sender) {166 if self.collection.sponsorship.pending_sponsor() != Some(sender) {
163 return false;167 return Ok(false);
164 };168 }
165169
166 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());170 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
167 true171 Ok(true)
168 }172 }
173
174 pub fn check_is_read_only(&self) -> DispatchResult {
175 if self.read_only {
176 return Err(<Error<T>>::CollectionNotFound)?;
177 }
178
179 Ok(())
180 }
169}181}
170182
171impl<T: Config> Deref for CollectionHandle<T> {183impl<T: Config> Deref for CollectionHandle<T> {
435 /// Empty property keys are forbidden447 /// Empty property keys are forbidden
436 EmptyPropertyKey,448 EmptyPropertyKey,
449
450 /// Collection is read only
451 CollectionIsReadOnly,
437 }452 }
438453
439 #[pallet::storage]454 #[pallet::storage]
669 sponsorship,684 sponsorship,
670 limits,685 limits,
671 permissions,686 permissions,
687 read_only,
672 } = <CollectionById<T>>::get(collection)?;688 } = <CollectionById<T>>::get(collection)?;
673689
674 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)690 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)
698 permissions,714 permissions,
699 token_property_permissions,715 token_property_permissions,
700 properties,716 properties,
717 read_only,
701 })718 })
702 }719 }
703}720}
778 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)795 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)
779 })796 })
780 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,797 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,
798 read_only: false,
781 };799 };
782800
783 let mut collection_properties = up_data_structs::CollectionProperties::get();801 let mut collection_properties = up_data_structs::CollectionProperties::get();
834 collection: CollectionHandle<T>,852 collection: CollectionHandle<T>,
835 sender: &T::CrossAccountId,853 sender: &T::CrossAccountId,
836 ) -> DispatchResult {854 ) -> DispatchResult {
855 collection.check_is_read_only()?;
837 ensure!(856 ensure!(
838 collection.limits.owner_can_destroy(),857 collection.limits.owner_can_destroy(),
839 <Error<T>>::NoPermission,858 <Error<T>>::NoPermission,
863 sender: &T::CrossAccountId,882 sender: &T::CrossAccountId,
864 property: Property,883 property: Property,
865 ) -> DispatchResult {884 ) -> DispatchResult {
885 collection.check_is_read_only()?;
866 collection.check_is_owner_or_admin(sender)?;886 collection.check_is_owner_or_admin(sender)?;
867887
868 CollectionProperties::<T>::try_mutate(collection.id, |properties| {888 CollectionProperties::<T>::try_mutate(collection.id, |properties| {
908 sender: &T::CrossAccountId,928 sender: &T::CrossAccountId,
909 properties: Vec<Property>,929 properties: Vec<Property>,
910 ) -> DispatchResult {930 ) -> DispatchResult {
931 collection.check_is_read_only()?;
932
911 for property in properties {933 for property in properties {
912 Self::set_collection_property(collection, sender, property)?;934 Self::set_collection_property(collection, sender, property)?;
920 sender: &T::CrossAccountId,942 sender: &T::CrossAccountId,
921 property_key: PropertyKey,943 property_key: PropertyKey,
922 ) -> DispatchResult {944 ) -> DispatchResult {
945 collection.check_is_read_only()?;
923 collection.check_is_owner_or_admin(sender)?;946 collection.check_is_owner_or_admin(sender)?;
924947
925 CollectionProperties::<T>::try_mutate(collection.id, |properties| {948 CollectionProperties::<T>::try_mutate(collection.id, |properties| {
941 sender: &T::CrossAccountId,964 sender: &T::CrossAccountId,
942 property_keys: Vec<PropertyKey>,965 property_keys: Vec<PropertyKey>,
943 ) -> DispatchResult {966 ) -> DispatchResult {
967 collection.check_is_read_only()?;
968
944 for key in property_keys {969 for key in property_keys {
945 Self::delete_collection_property(collection, sender, key)?;970 Self::delete_collection_property(collection, sender, key)?;
965 sender: &T::CrossAccountId,990 sender: &T::CrossAccountId,
966 property_permission: PropertyKeyPermission,991 property_permission: PropertyKeyPermission,
967 ) -> DispatchResult {992 ) -> DispatchResult {
993 collection.check_is_read_only()?;
968 collection.check_is_owner_or_admin(sender)?;994 collection.check_is_owner_or_admin(sender)?;
969995
970 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);996 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);
996 sender: &T::CrossAccountId,1022 sender: &T::CrossAccountId,
997 property_permissions: Vec<PropertyKeyPermission>,1023 property_permissions: Vec<PropertyKeyPermission>,
998 ) -> DispatchResult {1024 ) -> DispatchResult {
1025 collection.check_is_read_only()?;
1026
999 for prop_pemission in property_permissions {1027 for prop_pemission in property_permissions {
1000 Self::set_property_permission(collection, sender, prop_pemission)?;1028 Self::set_property_permission(collection, sender, prop_pemission)?;
1083 user: &T::CrossAccountId,1111 user: &T::CrossAccountId,
1084 allowed: bool,1112 allowed: bool,
1085 ) -> DispatchResult {1113 ) -> DispatchResult {
1114 collection.check_is_read_only()?;
1086 collection.check_is_owner_or_admin(sender)?;1115 collection.check_is_owner_or_admin(sender)?;
10871116
1088 // =========1117 // =========
1102 user: &T::CrossAccountId,1131 user: &T::CrossAccountId,
1103 admin: bool,1132 admin: bool,
1104 ) -> DispatchResult {1133 ) -> DispatchResult {
1134 collection.check_is_read_only()?;
1105 collection.check_is_owner_or_admin(sender)?;1135 collection.check_is_owner_or_admin(sender)?;
11061136
1107 let was_admin = <IsAdmin<T>>::get((collection.id, user));1137 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
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -87,6 +87,20 @@
       expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
     });
   });
+
+  it('Create new collection is not read only', async () => {
+    await usingApi(async api => {
+      const alice = privateKey('//Alice');
+      const tx = api.tx.unique.createCollectionEx({
+        readOnly: true
+      });
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateCollectionResult(events);
+
+      const collection = (await getDetailedCollectionInfo(api, result.collectionId))!;
+      expect(collection.readOnly.toHuman()).to.be.false;
+    });
+  });
 });
 
 describe('(!negative test!) integration test: ext. createCollection():', () => {