git.delta.rocks / unique-network / refs/commits / 4a0df43d0b40

difftreelog

fieat: add repair_item extrinsic + test

Daniel Shiposha2022-12-14parent: #9465eb9.patch.diff
in: master

15 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1815,6 +1815,9 @@
 
 	/// The price of setting approval for all
 	fn set_allowance_for_all() -> Weight;
+
+	/// The price of repairing an item.
+	fn repair_item() -> Weight;
 }
 
 /// Weight info extension trait for refungible pallet.
@@ -2136,6 +2139,9 @@
 
 	/// Tells whether the given `owner` approves the `operator`.
 	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;
+
+	/// Repairs a possibly broken item.
+	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;
 }
 
 /// Extension for RFT collection.
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -111,6 +111,10 @@
 	fn set_allowance_for_all() -> Weight {
 		Weight::zero()
 	}
+
+	fn repair_item() -> Weight {
+		Weight::zero()
+	}
 }
 
 /// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
@@ -441,4 +445,9 @@
 	fn allowance_for_all(&self, _owner: T::CrossAccountId, _operator: T::CrossAccountId) -> bool {
 		false
 	}
+
+	/// Repairs a possibly broken item.
+	fn repair_item(&self, _token: TokenId) -> DispatchResultWithPostInfo {
+		fail!(<Error<T>>::FungibleTokensAreAlwaysValid)
+	}
 }
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -129,6 +129,8 @@
 		SettingPropertiesNotAllowed,
 		/// Setting allowance for all is not allowed.
 		SettingAllowanceForAllNotAllowed,
+		/// Only a fungible collection could be possibly broken; any fungible token is valid.
+		FungibleTokensAreAlwaysValid,
 	}
 
 	#[pallet::config]
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -236,4 +236,12 @@
 			operator: cross_sub;
 		};
 	}: {<Pallet<T>>::allowance_for_all(&collection, &owner, &operator)}
+
+	repair_item {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub;
+		};
+		let item = create_max_item(&collection, &owner, owner.clone())?;
+	}: {<Pallet<T>>::repair_item(&collection, item)?}
 }
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -126,6 +126,10 @@
 	fn set_allowance_for_all() -> Weight {
 		<SelfWeightOf<T>>::set_allowance_for_all()
 	}
+
+	fn repair_item() -> Weight {
+		<SelfWeightOf<T>>::repair_item()
+	}
 }
 
 fn map_create_data<T: Config>(
@@ -532,4 +536,11 @@
 	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
 		<Pallet<T>>::allowance_for_all(self, &owner, &operator)
 	}
+
+	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {
+		with_weight(
+			<Pallet<T>>::repair_item(self, token),
+			<CommonWeights<T>>::repair_item(),
+		)
+	}
 }
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -1398,4 +1398,12 @@
 	) -> bool {
 		<CollectionAllowance<T>>::get((collection.id, owner, operator))
 	}
+
+	pub fn repair_item(collection: &NonfungibleHandle<T>, token: TokenId) -> DispatchResult {
+		<TokenProperties<T>>::mutate((collection.id, token), |properties| {
+			properties.recompute_consumed_space();
+		});
+
+		Ok(())
+	}
 }
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
before · pallets/nonfungible/src/weights.rs
1// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs23//! Autogenerated weights for pallet_nonfungible4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 102489// Executed Command:10// target/release/unique-collator11// benchmark12// pallet13// --pallet14// pallet-nonfungible15// --wasm-execution16// compiled17// --extrinsic18// *19// --template20// .maintain/frame-weight-template.hbs21// --steps=5022// --repeat=8023// --heap-pages=409624// --output=./pallets/nonfungible/src/weights.rs2526#![cfg_attr(rustfmt, rustfmt_skip)]27#![allow(unused_parens)]28#![allow(unused_imports)]29#![allow(missing_docs)]30#![allow(clippy::unnecessary_cast)]3132use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};33use sp_std::marker::PhantomData;3435/// Weight functions needed for pallet_nonfungible.36pub trait WeightInfo {37	fn create_item() -> Weight;38	fn create_multiple_items(b: u32, ) -> Weight;39	fn create_multiple_items_ex(b: u32, ) -> Weight;40	fn burn_item() -> Weight;41	fn burn_recursively_self_raw() -> Weight;42	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight;43	fn transfer() -> Weight;44	fn approve() -> Weight;45	fn transfer_from() -> Weight;46	fn burn_from() -> Weight;47	fn set_token_property_permissions(b: u32, ) -> Weight;48	fn set_token_properties(b: u32, ) -> Weight;49	fn delete_token_properties(b: u32, ) -> Weight;50	fn token_owner() -> Weight;51	fn set_allowance_for_all() -> Weight;52	fn allowance_for_all() -> Weight;53}5455/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.56pub struct SubstrateWeight<T>(PhantomData<T>);57impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {58	// Storage: Nonfungible TokensMinted (r:1 w:1)59	// Storage: Nonfungible AccountBalance (r:1 w:1)60	// Storage: Nonfungible TokenData (r:0 w:1)61	// Storage: Nonfungible Owned (r:0 w:1)62	fn create_item() -> Weight {63		Weight::from_ref_time(25_905_000)64			.saturating_add(T::DbWeight::get().reads(2 as u64))65			.saturating_add(T::DbWeight::get().writes(4 as u64))66	}67	// Storage: Nonfungible TokensMinted (r:1 w:1)68	// Storage: Nonfungible AccountBalance (r:1 w:1)69	// Storage: Nonfungible TokenData (r:0 w:4)70	// Storage: Nonfungible Owned (r:0 w:4)71	fn create_multiple_items(b: u32, ) -> Weight {72		Weight::from_ref_time(24_955_000)73			// Standard Error: 3_00074			.saturating_add(Weight::from_ref_time(5_340_000).saturating_mul(b as u64))75			.saturating_add(T::DbWeight::get().reads(2 as u64))76			.saturating_add(T::DbWeight::get().writes(2 as u64))77			.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(b as u64)))78	}79	// Storage: Nonfungible TokensMinted (r:1 w:1)80	// Storage: Nonfungible AccountBalance (r:4 w:4)81	// Storage: Nonfungible TokenData (r:0 w:4)82	// Storage: Nonfungible Owned (r:0 w:4)83	fn create_multiple_items_ex(b: u32, ) -> Weight {84		Weight::from_ref_time(13_666_000)85			// Standard Error: 5_00086			.saturating_add(Weight::from_ref_time(8_299_000).saturating_mul(b as u64))87			.saturating_add(T::DbWeight::get().reads(1 as u64))88			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64)))89			.saturating_add(T::DbWeight::get().writes(1 as u64))90			.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(b as u64)))91	}92	// Storage: Nonfungible TokenData (r:1 w:1)93	// Storage: Nonfungible TokenChildren (r:1 w:0)94	// Storage: Nonfungible TokensBurnt (r:1 w:1)95	// Storage: Nonfungible AccountBalance (r:1 w:1)96	// Storage: Nonfungible Allowance (r:1 w:0)97	// Storage: Nonfungible Owned (r:0 w:1)98	// Storage: Nonfungible TokenProperties (r:0 w:1)99	fn burn_item() -> Weight {100		Weight::from_ref_time(36_205_000)101			.saturating_add(T::DbWeight::get().reads(5 as u64))102			.saturating_add(T::DbWeight::get().writes(5 as u64))103	}104	// Storage: Nonfungible TokenChildren (r:1 w:0)105	// Storage: Nonfungible TokenData (r:1 w:1)106	// Storage: Nonfungible TokensBurnt (r:1 w:1)107	// Storage: Nonfungible AccountBalance (r:1 w:1)108	// Storage: Nonfungible Allowance (r:1 w:0)109	// Storage: Nonfungible Owned (r:0 w:1)110	// Storage: Nonfungible TokenProperties (r:0 w:1)111	fn burn_recursively_self_raw() -> Weight {112		Weight::from_ref_time(44_550_000)113			.saturating_add(T::DbWeight::get().reads(5 as u64))114			.saturating_add(T::DbWeight::get().writes(5 as u64))115	}116	// Storage: Nonfungible TokenChildren (r:1 w:0)117	// Storage: Nonfungible TokenData (r:1 w:1)118	// Storage: Nonfungible TokensBurnt (r:1 w:1)119	// Storage: Nonfungible AccountBalance (r:1 w:1)120	// Storage: Nonfungible Allowance (r:1 w:0)121	// Storage: Nonfungible Owned (r:0 w:1)122	// Storage: Nonfungible TokenProperties (r:0 w:1)123	// Storage: Common CollectionById (r:1 w:0)124	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {125		(Weight::from_ref_time(0))126			// Standard Error: 1_536_000127			.saturating_add(Weight::from_ref_time(312_125_000).saturating_mul(b as u64))128			.saturating_add(T::DbWeight::get().reads(7 as u64))129			.saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(b as u64)))130			.saturating_add(T::DbWeight::get().writes(6 as u64))131			.saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(b as u64)))132	}133	// Storage: Nonfungible TokenData (r:1 w:1)134	// Storage: Nonfungible AccountBalance (r:2 w:2)135	// Storage: Nonfungible Allowance (r:1 w:0)136	// Storage: Nonfungible Owned (r:0 w:2)137	fn transfer() -> Weight {138		Weight::from_ref_time(31_116_000)139			.saturating_add(T::DbWeight::get().reads(4 as u64))140			.saturating_add(T::DbWeight::get().writes(5 as u64))141	}142	// Storage: Nonfungible TokenData (r:1 w:0)143	// Storage: Nonfungible Allowance (r:1 w:1)144	fn approve() -> Weight {145		Weight::from_ref_time(20_802_000)146			.saturating_add(T::DbWeight::get().reads(2 as u64))147			.saturating_add(T::DbWeight::get().writes(1 as u64))148	}149	// Storage: Nonfungible Allowance (r:1 w:1)150	// Storage: Nonfungible TokenData (r:1 w:1)151	// Storage: Nonfungible AccountBalance (r:2 w:2)152	// Storage: Nonfungible Owned (r:0 w:2)153	fn transfer_from() -> Weight {154		Weight::from_ref_time(36_083_000)155			.saturating_add(T::DbWeight::get().reads(4 as u64))156			.saturating_add(T::DbWeight::get().writes(6 as u64))157	}158	// Storage: Nonfungible Allowance (r:1 w:1)159	// Storage: Nonfungible TokenData (r:1 w:1)160	// Storage: Nonfungible TokenChildren (r:1 w:0)161	// Storage: Nonfungible TokensBurnt (r:1 w:1)162	// Storage: Nonfungible AccountBalance (r:1 w:1)163	// Storage: Nonfungible Owned (r:0 w:1)164	// Storage: Nonfungible TokenProperties (r:0 w:1)165	fn burn_from() -> Weight {166		Weight::from_ref_time(41_781_000)167			.saturating_add(T::DbWeight::get().reads(5 as u64))168			.saturating_add(T::DbWeight::get().writes(6 as u64))169	}170	// Storage: Common CollectionPropertyPermissions (r:1 w:1)171	fn set_token_property_permissions(b: u32, ) -> Weight {172		(Weight::from_ref_time(0))173			// Standard Error: 58_000174			.saturating_add(Weight::from_ref_time(15_705_000).saturating_mul(b as u64))175			.saturating_add(T::DbWeight::get().reads(1 as u64))176			.saturating_add(T::DbWeight::get().writes(1 as u64))177	}178	// Storage: Common CollectionPropertyPermissions (r:1 w:0)179	// Storage: Nonfungible TokenProperties (r:1 w:1)180	fn set_token_properties(b: u32, ) -> Weight {181		(Weight::from_ref_time(0))182			// Standard Error: 3_595_000183			.saturating_add(Weight::from_ref_time(590_344_000).saturating_mul(b as u64))184			.saturating_add(T::DbWeight::get().reads(2 as u64))185			.saturating_add(T::DbWeight::get().writes(1 as u64))186	}187	// Storage: Common CollectionPropertyPermissions (r:1 w:0)188	// Storage: Nonfungible TokenProperties (r:1 w:1)189	fn delete_token_properties(b: u32, ) -> Weight {190		(Weight::from_ref_time(0))191			// Standard Error: 3_664_000192			.saturating_add(Weight::from_ref_time(605_836_000).saturating_mul(b as u64))193			.saturating_add(T::DbWeight::get().reads(2 as u64))194			.saturating_add(T::DbWeight::get().writes(1 as u64))195	}196	// Storage: Nonfungible TokenData (r:1 w:0)197	fn token_owner() -> Weight {198		Weight::from_ref_time(4_366_000)199			.saturating_add(T::DbWeight::get().reads(1 as u64))200	}201	// Storage: Nonfungible WalletOperator (r:0 w:1)202	fn set_allowance_for_all() -> Weight {203		Weight::from_ref_time(16_231_000 as u64)204			.saturating_add(T::DbWeight::get().writes(1 as u64))205	}206	// Storage: Nonfungible WalletOperator (r:1 w:0)207	fn allowance_for_all() -> Weight {208		Weight::from_ref_time(6_161_000 as u64)209			.saturating_add(T::DbWeight::get().reads(1 as u64))210	}211}212213// For backwards compatibility and tests214impl WeightInfo for () {215	// Storage: Nonfungible TokensMinted (r:1 w:1)216	// Storage: Nonfungible AccountBalance (r:1 w:1)217	// Storage: Nonfungible TokenData (r:0 w:1)218	// Storage: Nonfungible Owned (r:0 w:1)219	fn create_item() -> Weight {220		Weight::from_ref_time(25_905_000)221			.saturating_add(RocksDbWeight::get().reads(2 as u64))222			.saturating_add(RocksDbWeight::get().writes(4 as u64))223	}224	// Storage: Nonfungible TokensMinted (r:1 w:1)225	// Storage: Nonfungible AccountBalance (r:1 w:1)226	// Storage: Nonfungible TokenData (r:0 w:4)227	// Storage: Nonfungible Owned (r:0 w:4)228	fn create_multiple_items(b: u32, ) -> Weight {229		Weight::from_ref_time(24_955_000)230			// Standard Error: 3_000231			.saturating_add(Weight::from_ref_time(5_340_000).saturating_mul(b as u64))232			.saturating_add(RocksDbWeight::get().reads(2 as u64))233			.saturating_add(RocksDbWeight::get().writes(2 as u64))234			.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(b as u64)))235	}236	// Storage: Nonfungible TokensMinted (r:1 w:1)237	// Storage: Nonfungible AccountBalance (r:4 w:4)238	// Storage: Nonfungible TokenData (r:0 w:4)239	// Storage: Nonfungible Owned (r:0 w:4)240	fn create_multiple_items_ex(b: u32, ) -> Weight {241		Weight::from_ref_time(13_666_000)242			// Standard Error: 5_000243			.saturating_add(Weight::from_ref_time(8_299_000).saturating_mul(b as u64))244			.saturating_add(RocksDbWeight::get().reads(1 as u64))245			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(b as u64)))246			.saturating_add(RocksDbWeight::get().writes(1 as u64))247			.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(b as u64)))248	}249	// Storage: Nonfungible TokenData (r:1 w:1)250	// Storage: Nonfungible TokenChildren (r:1 w:0)251	// Storage: Nonfungible TokensBurnt (r:1 w:1)252	// Storage: Nonfungible AccountBalance (r:1 w:1)253	// Storage: Nonfungible Allowance (r:1 w:0)254	// Storage: Nonfungible Owned (r:0 w:1)255	// Storage: Nonfungible TokenProperties (r:0 w:1)256	fn burn_item() -> Weight {257		Weight::from_ref_time(36_205_000)258			.saturating_add(RocksDbWeight::get().reads(5 as u64))259			.saturating_add(RocksDbWeight::get().writes(5 as u64))260	}261	// Storage: Nonfungible TokenChildren (r:1 w:0)262	// Storage: Nonfungible TokenData (r:1 w:1)263	// Storage: Nonfungible TokensBurnt (r:1 w:1)264	// Storage: Nonfungible AccountBalance (r:1 w:1)265	// Storage: Nonfungible Allowance (r:1 w:0)266	// Storage: Nonfungible Owned (r:0 w:1)267	// Storage: Nonfungible TokenProperties (r:0 w:1)268	fn burn_recursively_self_raw() -> Weight {269		Weight::from_ref_time(44_550_000)270			.saturating_add(RocksDbWeight::get().reads(5 as u64))271			.saturating_add(RocksDbWeight::get().writes(5 as u64))272	}273	// Storage: Nonfungible TokenChildren (r:1 w:0)274	// Storage: Nonfungible TokenData (r:1 w:1)275	// Storage: Nonfungible TokensBurnt (r:1 w:1)276	// Storage: Nonfungible AccountBalance (r:1 w:1)277	// Storage: Nonfungible Allowance (r:1 w:0)278	// Storage: Nonfungible Owned (r:0 w:1)279	// Storage: Nonfungible TokenProperties (r:0 w:1)280	// Storage: Common CollectionById (r:1 w:0)281	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {282		(Weight::from_ref_time(0))283			// Standard Error: 1_536_000284			.saturating_add(Weight::from_ref_time(312_125_000).saturating_mul(b as u64))285			.saturating_add(RocksDbWeight::get().reads(7 as u64))286			.saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(b as u64)))287			.saturating_add(RocksDbWeight::get().writes(6 as u64))288			.saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(b as u64)))289	}290	// Storage: Nonfungible TokenData (r:1 w:1)291	// Storage: Nonfungible AccountBalance (r:2 w:2)292	// Storage: Nonfungible Allowance (r:1 w:0)293	// Storage: Nonfungible Owned (r:0 w:2)294	fn transfer() -> Weight {295		Weight::from_ref_time(31_116_000)296			.saturating_add(RocksDbWeight::get().reads(4 as u64))297			.saturating_add(RocksDbWeight::get().writes(5 as u64))298	}299	// Storage: Nonfungible TokenData (r:1 w:0)300	// Storage: Nonfungible Allowance (r:1 w:1)301	fn approve() -> Weight {302		Weight::from_ref_time(20_802_000)303			.saturating_add(RocksDbWeight::get().reads(2 as u64))304			.saturating_add(RocksDbWeight::get().writes(1 as u64))305	}306	// Storage: Nonfungible Allowance (r:1 w:1)307	// Storage: Nonfungible TokenData (r:1 w:1)308	// Storage: Nonfungible AccountBalance (r:2 w:2)309	// Storage: Nonfungible Owned (r:0 w:2)310	fn transfer_from() -> Weight {311		Weight::from_ref_time(36_083_000)312			.saturating_add(RocksDbWeight::get().reads(4 as u64))313			.saturating_add(RocksDbWeight::get().writes(6 as u64))314	}315	// Storage: Nonfungible Allowance (r:1 w:1)316	// Storage: Nonfungible TokenData (r:1 w:1)317	// Storage: Nonfungible TokenChildren (r:1 w:0)318	// Storage: Nonfungible TokensBurnt (r:1 w:1)319	// Storage: Nonfungible AccountBalance (r:1 w:1)320	// Storage: Nonfungible Owned (r:0 w:1)321	// Storage: Nonfungible TokenProperties (r:0 w:1)322	fn burn_from() -> Weight {323		Weight::from_ref_time(41_781_000)324			.saturating_add(RocksDbWeight::get().reads(5 as u64))325			.saturating_add(RocksDbWeight::get().writes(6 as u64))326	}327	// Storage: Common CollectionPropertyPermissions (r:1 w:1)328	fn set_token_property_permissions(b: u32, ) -> Weight {329		(Weight::from_ref_time(0))330			// Standard Error: 58_000331			.saturating_add(Weight::from_ref_time(15_705_000).saturating_mul(b as u64))332			.saturating_add(RocksDbWeight::get().reads(1 as u64))333			.saturating_add(RocksDbWeight::get().writes(1 as u64))334	}335	// Storage: Common CollectionPropertyPermissions (r:1 w:0)336	// Storage: Nonfungible TokenProperties (r:1 w:1)337	fn set_token_properties(b: u32, ) -> Weight {338		(Weight::from_ref_time(0))339			// Standard Error: 3_595_000340			.saturating_add(Weight::from_ref_time(590_344_000).saturating_mul(b as u64))341			.saturating_add(RocksDbWeight::get().reads(2 as u64))342			.saturating_add(RocksDbWeight::get().writes(1 as u64))343	}344	// Storage: Common CollectionPropertyPermissions (r:1 w:0)345	// Storage: Nonfungible TokenProperties (r:1 w:1)346	fn delete_token_properties(b: u32, ) -> Weight {347		(Weight::from_ref_time(0))348			// Standard Error: 3_664_000349			.saturating_add(Weight::from_ref_time(605_836_000).saturating_mul(b as u64))350			.saturating_add(RocksDbWeight::get().reads(2 as u64))351			.saturating_add(RocksDbWeight::get().writes(1 as u64))352	}353	// Storage: Nonfungible TokenData (r:1 w:0)354	fn token_owner() -> Weight {355		Weight::from_ref_time(4_366_000)356			.saturating_add(RocksDbWeight::get().reads(1 as u64))357	}358	// Storage: Nonfungible WalletOperator (r:0 w:1)359	fn set_allowance_for_all() -> Weight {360		Weight::from_ref_time(16_231_000 as u64)361			.saturating_add(RocksDbWeight::get().writes(1 as u64))362	}363	// Storage: Nonfungible WalletOperator (r:1 w:0)364	fn allowance_for_all() -> Weight {365		Weight::from_ref_time(6_161_000 as u64)366			.saturating_add(RocksDbWeight::get().reads(1 as u64))367	}368}
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -304,4 +304,12 @@
 			operator: cross_sub;
 		};
 	}: {<Pallet<T>>::allowance_for_all(&collection, &owner, &operator)}
+
+	repair_item {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub;
+		};
+		let item = create_max_item(&collection, &owner, [(owner.clone(), 100)])?;
+	}: {<Pallet<T>>::repair_item(&collection, item)?}
 }
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -156,6 +156,10 @@
 	fn set_allowance_for_all() -> Weight {
 		<SelfWeightOf<T>>::set_allowance_for_all()
 	}
+
+	fn repair_item() -> Weight {
+		<SelfWeightOf<T>>::repair_item()
+	}
 }
 
 fn map_create_data<T: Config>(
@@ -536,6 +540,13 @@
 	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
 		<Pallet<T>>::allowance_for_all(self, &owner, &operator)
 	}
+
+	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {
+		with_weight(
+			<Pallet<T>>::repair_item(self, token),
+			<CommonWeights<T>>::repair_item(),
+		)
+	}
 }
 
 impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -1461,4 +1461,12 @@
 	) -> bool {
 		<CollectionAllowance<T>>::get((collection.id, owner, operator))
 	}
+
+	pub fn repair_item(collection: &RefungibleHandle<T>, token: TokenId) -> DispatchResult {
+		<TokenProperties<T>>::mutate((collection.id, token), |properties| {
+			properties.recompute_consumed_space();
+		});
+
+		Ok(())
+	}
 }
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -57,6 +57,7 @@
 	fn token_owner() -> Weight;
 	fn set_allowance_for_all() -> Weight;
 	fn allowance_for_all() -> Weight;
+	fn repair_item() -> Weight;
 }
 
 /// Weights for pallet_refungible using the Substrate node and recommended hardware.
@@ -272,6 +273,12 @@
 		Weight::from_ref_time(5_901_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 	}
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn repair_item() -> Weight {
+		Weight::from_ref_time(5_489_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
+			.saturating_add(T::DbWeight::get().writes(1 as u64))
+	}
 }
 
 // For backwards compatibility and tests
@@ -486,4 +493,10 @@
 		Weight::from_ref_time(5_901_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 	}
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn repair_item() -> Weight {
+		Weight::from_ref_time(5_489_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
+			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+	}
 }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -982,6 +982,23 @@
 				d.set_allowance_for_all(sender, operator, approve)
 			})
 		}
+
+		/// Repairs a broken item
+		///
+		/// # Arguments
+		///
+		/// * `collection_id`: ID of the collection the item belongs to.
+		/// * `item_id`: ID of the item.
+		#[weight = T::CommonWeightInfo::repair_item()]
+		pub fn repair_item(
+			_origin,
+			collection_id: CollectionId,
+			item_id: TokenId,
+		) -> DispatchResultWithPostInfo {
+			dispatch_tx::<T, _>(collection_id, |d| {
+				d.repair_item(item_id)
+			})
+		}
 	}
 }
 
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -1218,6 +1218,10 @@
 
 		Ok(())
 	}
+
+	pub fn values(&self) -> impl Iterator<Item = &Value> {
+		self.0.values()
+	}
 }
 
 impl<Value> IntoIterator for PropertiesMap<Value> {
@@ -1290,6 +1294,12 @@
 	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {
 		self.map.get(key)
 	}
+
+	/// Recomputes the consumed space for the current properties state.
+	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).
+	pub fn recompute_consumed_space(&mut self) {
+		self.consumed_space = self.map.values().map(|value| value.len() as u32).sum();
+	}
 }
 
 impl IntoIterator for Properties {
modifiedruntime/common/weights.rsdiffbeforeafterboth
--- a/runtime/common/weights.rs
+++ b/runtime/common/weights.rs
@@ -124,6 +124,10 @@
 	fn set_allowance_for_all() -> Weight {
 		max_weight_of!(set_allowance_for_all())
 	}
+
+	fn repair_item() -> Weight {
+		max_weight_of!(repair_item())
+	}
 }
 
 #[cfg(feature = "refungible")]
modifiedtests/src/nesting/tokenProperties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/tokenProperties.test.ts
+++ b/tests/src/nesting/tokenProperties.test.ts
@@ -28,7 +28,7 @@
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       const donor = await privateKey({filename: __filename});
-      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+      [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
     });
 
     permissions = [
@@ -401,6 +401,39 @@
       consumedSpace = await token.getTokenPropertiesConsumedSpace();
       expect(consumedSpace).to.be.equal(originalSpace);
     }));
+
+  [
+    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, 
+  ].map(testCase =>
+    itSub.ifWithPallets(`repair_item preserves valid consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+      const token = await (
+        testCase.pieces
+          ? collection.mintToken(alice, testCase.pieces)
+          : collection.mintToken(alice)
+      );
+
+      const propDataSize = 4096;
+      const propData = 'a'.repeat(propDataSize);
+
+      await token.setProperties(alice, [{key: propKey, value: propData}]);
+      const originalSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(originalSpace).to.be.equal(propDataSize);
+
+      await helper.executeExtrinsic(alice, 'api.tx.unique.repairItem', [token.collectionId, token.tokenId], true);
+      const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(recomputedSpace).to.be.equal(originalSpace);
+    }));
 });
 
 describe('Negative Integration Test: Token Properties', () => {