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
87 check_is_owner(caller, self)?;87 check_is_owner(caller, self)?;
8888
89 let sponsor = T::CrossAccountId::from_eth(sponsor);89 let sponsor = T::CrossAccountId::from_eth(sponsor);
90 self.set_sponsor(sponsor.as_sub().clone());90 self.set_sponsor(sponsor.as_sub().clone()).map_err(dispatch_to_evm::<T>)?;
91 save(self);91 save(self)
92 Ok(())
93 }92 }
9493
95 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {94 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {
96 let caller = T::CrossAccountId::from_eth(caller);95 let caller = T::CrossAccountId::from_eth(caller);
97 if !self.confirm_sponsorship(caller.as_sub()) {96 if !self.confirm_sponsorship(caller.as_sub()).map_err(dispatch_to_evm::<T>)? {
98 return Err(Error::Revert("Caller is not set as sponsor".into()));97 return Err(Error::Revert("Caller is not set as sponsor".into()));
99 }98 }
100 save(self);99 save(self)
101 Ok(())
102 }100 }
103101
104 #[solidity(rename_selector = "setCollectionLimit")]102 #[solidity(rename_selector = "setCollectionLimit")]
134 }132 }
135 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)133 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
136 .map_err(dispatch_to_evm::<T>)?;134 .map_err(dispatch_to_evm::<T>)?;
137 save(self);135 save(self)
138 Ok(())
139 }136 }
140137
141 #[solidity(rename_selector = "setCollectionLimit")]138 #[solidity(rename_selector = "setCollectionLimit")]
162 }159 }
163 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)160 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
164 .map_err(dispatch_to_evm::<T>)?;161 .map_err(dispatch_to_evm::<T>)?;
165 save(self);162 save(self)
166 Ok(())
167 }163 }
168164
169 fn contract_address(&self, _caller: caller) -> Result<address> {165 fn contract_address(&self, _caller: caller) -> Result<address> {
296 }292 }
297}293}
298294
299fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {295fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<void> {
300 let caller = T::CrossAccountId::from_eth(caller);296 let caller = T::CrossAccountId::from_eth(caller);
301 collection297 collection
302 .check_is_owner(&caller)298 .check_is_owner(&caller)
315 Ok(caller)311 Ok(caller)
316}312}
317313
318fn save<T: Config>(collection: &CollectionHandle<T>) {314fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {
315 collection.check_is_read_only().map_err(dispatch_to_evm::<T>)?;
319 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());316 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());
317 Ok(())
320}318}
321319
322pub fn token_uri_key() -> up_data_structs::PropertyKey {320pub 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
168 owner: &T::CrossAccountId,168 owner: &T::CrossAccountId,
169 amount: u128,169 amount: u128,
170 ) -> DispatchResult {170 ) -> DispatchResult {
171 collection.check_is_read_only()?;
172
171 let total_supply = <TotalSupply<T>>::get(collection.id)173 let total_supply = <TotalSupply<T>>::get(collection.id)
172 .checked_sub(amount)174 .checked_sub(amount)
214 amount: u128,216 amount: u128,
215 nesting_budget: &dyn Budget,217 nesting_budget: &dyn Budget,
216 ) -> DispatchResult {218 ) -> DispatchResult {
219 collection.check_is_read_only()?;
220
217 ensure!(221 ensure!(
218 collection.limits.transfers_enabled(),222 collection.limits.transfers_enabled(),
283 data: BTreeMap<T::CrossAccountId, u128>,287 data: BTreeMap<T::CrossAccountId, u128>,
284 nesting_budget: &dyn Budget,288 nesting_budget: &dyn Budget,
285 ) -> DispatchResult {289 ) -> DispatchResult {
290 collection.check_is_read_only()?;
291
286 if !collection.is_owner_or_admin(sender) {292 if !collection.is_owner_or_admin(sender) {
287 ensure!(293 ensure!(
384 spender: &T::CrossAccountId,390 spender: &T::CrossAccountId,
385 amount: u128,391 amount: u128,
386 ) -> DispatchResult {392 ) -> DispatchResult {
393 collection.check_is_read_only()?;
387 if collection.permissions.access() == AccessMode::AllowList {394 if collection.permissions.access() == AccessMode::AllowList {
388 collection.check_allowlist(owner)?;395 collection.check_allowlist(owner)?;
389 collection.check_allowlist(spender)?;396 collection.check_allowlist(spender)?;
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
336 sender: &T::CrossAccountId,336 sender: &T::CrossAccountId,
337 token: TokenId,337 token: TokenId,
338 ) -> DispatchResult {338 ) -> DispatchResult {
339 collection.check_is_read_only()?;
340
339 let token_data =341 let token_data =
340 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;342 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
456 &property.key,458 &property.key,
457 is_token_create,459 is_token_create,
458 )?;460 )?;
461 collection.check_is_read_only()?;
459462
460 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {463 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
461 let property = property.clone();464 let property = property.clone();
494 property_key: PropertyKey,497 property_key: PropertyKey,
495 ) -> DispatchResult {498 ) -> DispatchResult {
496 Self::check_token_change_permission(collection, sender, token_id, &property_key, false)?;499 Self::check_token_change_permission(collection, sender, token_id, &property_key, false)?;
500 collection.check_is_read_only()?;
497501
498 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {502 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
499 properties.remove(&property_key)503 properties.remove(&property_key)
570 token_id: TokenId,574 token_id: TokenId,
571 property_keys: Vec<PropertyKey>,575 property_keys: Vec<PropertyKey>,
572 ) -> DispatchResult {576 ) -> DispatchResult {
577 collection.check_is_read_only()?;
578
573 for key in property_keys {579 for key in property_keys {
574 Self::delete_token_property(collection, sender, token_id, key)?;580 Self::delete_token_property(collection, sender, token_id, key)?;
616 token: TokenId,622 token: TokenId,
617 nesting_budget: &dyn Budget,623 nesting_budget: &dyn Budget,
618 ) -> DispatchResult {624 ) -> DispatchResult {
625 collection.check_is_read_only()?;
626
619 ensure!(627 ensure!(
620 collection.limits.transfers_enabled(),628 collection.limits.transfers_enabled(),
894 token: TokenId,902 token: TokenId,
895 spender: Option<&T::CrossAccountId>,903 spender: Option<&T::CrossAccountId>,
896 ) -> DispatchResult {904 ) -> DispatchResult {
905 collection.check_is_read_only()?;
906
897 if collection.permissions.access() == AccessMode::AllowList {907 if collection.permissions.access() == AccessMode::AllowList {
898 collection.check_allowlist(sender)?;908 collection.check_allowlist(sender)?;
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
234 }234 }
235235
236 pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {236 pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {
237 collection.check_is_read_only()?;
237 let burnt = <TokensBurnt<T>>::get(collection.id)238 let burnt = <TokensBurnt<T>>::get(collection.id)
238 .checked_add(1)239 .checked_add(1)
239 .ok_or(ArithmeticError::Overflow)?;240 .ok_or(ArithmeticError::Overflow)?;
253 token: TokenId,254 token: TokenId,
254 amount: u128,255 amount: u128,
255 ) -> DispatchResult {256 ) -> DispatchResult {
257 collection.check_is_read_only()?;
256 let total_supply = <TotalSupply<T>>::get((collection.id, token))258 let total_supply = <TotalSupply<T>>::get((collection.id, token))
257 .checked_sub(amount)259 .checked_sub(amount)
258 .ok_or(<CommonError<T>>::TokenValueTooLow)?;260 .ok_or(<CommonError<T>>::TokenValueTooLow)?;
325 amount: u128,327 amount: u128,
326 nesting_budget: &dyn Budget,328 nesting_budget: &dyn Budget,
327 ) -> DispatchResult {329 ) -> DispatchResult {
330 collection.check_is_read_only()?;
328 ensure!(331 ensure!(
329 collection.limits.transfers_enabled(),332 collection.limits.transfers_enabled(),
330 <CommonError<T>>::TransferNotAllowed333 <CommonError<T>>::TransferNotAllowed
573 token: TokenId,576 token: TokenId,
574 amount: u128,577 amount: u128,
575 ) -> DispatchResult {578 ) -> DispatchResult {
579 collection.check_is_read_only()?;
576 if collection.permissions.access() == AccessMode::AllowList {580 if collection.permissions.access() == AccessMode::AllowList {
577 collection.check_allowlist(sender)?;581 collection.check_allowlist(sender)?;
578 collection.check_allowlist(spender)?;582 collection.check_allowlist(spender)?;
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
304 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {304 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
305 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);305 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
306 let collection = <CollectionHandle<T>>::try_get(collection_id)?;306 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
307 collection.check_is_read_only()?;
307308
308 // =========309 // =========
309310
406 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);407 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
407408
408 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;409 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
410 target_collection.check_is_read_only()?;
409 target_collection.check_is_owner(&sender)?;411 target_collection.check_is_owner(&sender)?;
410412
411 target_collection.owner = new_owner.clone();413 target_collection.owner = new_owner.clone();
487 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;489 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
488 target_collection.check_is_owner(&sender)?;490 target_collection.check_is_owner(&sender)?;
489491
490 target_collection.set_sponsor(new_sponsor.clone());492 target_collection.set_sponsor(new_sponsor.clone())?;
491493
492 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(494 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(
493 collection_id,495 collection_id,
511513
512 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;514 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
513 ensure!(515 ensure!(
514 target_collection.confirm_sponsorship(&sender),516 target_collection.confirm_sponsorship(&sender)?,
515 Error::<T>::ConfirmUnsetSponsorFail517 Error::<T>::ConfirmUnsetSponsorFail
516 );518 );
517519
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
316 #[version(2.., upper(Default::default()))]316 #[version(2.., upper(Default::default()))]
317 pub permissions: CollectionPermissions,317 pub permissions: CollectionPermissions,
318
319 #[version(2.., upper(false))]
320 pub read_only: bool,
318321
319 #[version(..2)]322 #[version(..2)]
320 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,323 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
340 pub permissions: CollectionPermissions,343 pub permissions: CollectionPermissions,
341 pub token_property_permissions: Vec<PropertyKeyPermission>,344 pub token_property_permissions: Vec<PropertyKeyPermission>,
342 pub properties: Vec<Property>,345 pub properties: Vec<Property>,
346 pub read_only: bool,
343}347}
344348
345#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]349#[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():', () => {