difftreelog
Merge pull request #422 from UniqueNetwork/feature/CORE-410
in: master
Feature/core 410 Properties for RFT
21 files changed
Cargo.lockdiffbeforeafterboth632063206321[[package]]6321[[package]]6322name = "pallet-refungible"6322name = "pallet-refungible"6323version = "0.1.0"6323version = "0.1.1"6324dependencies = [6324dependencies = [6325 "frame-benchmarking",6325 "frame-benchmarking",6326 "frame-support",6326 "frame-support",127331273312734[[package]]12734[[package]]12735name = "up-data-structs"12735name = "up-data-structs"12736version = "0.1.0"12736version = "0.1.1"12737dependencies = [12737dependencies = [12738 "derivative",12738 "derivative",12739 "frame-support",12739 "frame-support",pallets/common/src/lib.rsdiffbeforeafterboth966 ),966 ),967 );967 );968 <T as Config>::Currency::settle(968 <T as Config>::Currency::settle(969 &owner.as_sub(),969 owner.as_sub(),970 imbalance,970 imbalance,971 WithdrawReasons::TRANSFER,971 WithdrawReasons::TRANSFER,972 ExistenceRequirement::KeepAlive,972 ExistenceRequirement::KeepAlive,pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth183 value: property_value(),183 value: property_value(),184 }).collect::<Vec<_>>();184 }).collect::<Vec<_>>();185 let item = create_max_item(&collection, &owner, owner.clone())?;185 let item = create_max_item(&collection, &owner, owner.clone())?;186 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?}186 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}187187188 delete_token_properties {188 delete_token_properties {189 let b in 0..MAX_PROPERTIES_PER_ITEM;189 let b in 0..MAX_PROPERTIES_PER_ITEM;205 value: property_value(),205 value: property_value(),206 }).collect::<Vec<_>>();206 }).collect::<Vec<_>>();207 let item = create_max_item(&collection, &owner, owner.clone())?;207 let item = create_max_item(&collection, &owner, owner.clone())?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;209 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();209 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();210 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete, &Unlimited)?}210 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}211}211}212212pallets/nonfungible/src/weights.rsdiffbeforeafterboth3//! Autogenerated weights for pallet_nonfungible3//! Autogenerated weights for pallet_nonfungible4//!4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-06-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024889// Executed Command:9// Executed Command:56 // Storage: Nonfungible TokenData (r:0 w:1)56 // Storage: Nonfungible TokenData (r:0 w:1)57 // Storage: Nonfungible Owned (r:0 w:1)57 // Storage: Nonfungible Owned (r:0 w:1)58 fn create_item() -> Weight {58 fn create_item() -> Weight {59 (24_135_000 as Weight)59 (20_328_000 as Weight)60 .saturating_add(T::DbWeight::get().reads(2 as Weight))60 .saturating_add(T::DbWeight::get().reads(2 as Weight))61 .saturating_add(T::DbWeight::get().writes(4 as Weight))61 .saturating_add(T::DbWeight::get().writes(4 as Weight))62 }62 }65 // Storage: Nonfungible TokenData (r:0 w:4)65 // Storage: Nonfungible TokenData (r:0 w:4)66 // Storage: Nonfungible Owned (r:0 w:4)66 // Storage: Nonfungible Owned (r:0 w:4)67 fn create_multiple_items(b: u32, ) -> Weight {67 fn create_multiple_items(b: u32, ) -> Weight {68 (21_952_000 as Weight)68 (10_134_000 as Weight)69 // Standard Error: 5_00069 // Standard Error: 3_00070 .saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))70 .saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))71 .saturating_add(T::DbWeight::get().reads(2 as Weight))71 .saturating_add(T::DbWeight::get().reads(2 as Weight))72 .saturating_add(T::DbWeight::get().writes(2 as Weight))72 .saturating_add(T::DbWeight::get().writes(2 as Weight))73 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))73 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))77 // Storage: Nonfungible TokenData (r:0 w:4)77 // Storage: Nonfungible TokenData (r:0 w:4)78 // Storage: Nonfungible Owned (r:0 w:4)78 // Storage: Nonfungible Owned (r:0 w:4)79 fn create_multiple_items_ex(b: u32, ) -> Weight {79 fn create_multiple_items_ex(b: u32, ) -> Weight {80 (10_432_000 as Weight)80 (5_710_000 as Weight)81 // Standard Error: 6_00081 // Standard Error: 4_00082 .saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))82 .saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))83 .saturating_add(T::DbWeight::get().reads(1 as Weight))83 .saturating_add(T::DbWeight::get().reads(1 as Weight))84 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))84 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))85 .saturating_add(T::DbWeight::get().writes(1 as Weight))85 .saturating_add(T::DbWeight::get().writes(1 as Weight))93 // Storage: Nonfungible Owned (r:0 w:1)93 // Storage: Nonfungible Owned (r:0 w:1)94 // Storage: Nonfungible TokenProperties (r:0 w:1)94 // Storage: Nonfungible TokenProperties (r:0 w:1)95 fn burn_item() -> Weight {95 fn burn_item() -> Weight {96 (29_798_000 as Weight)96 (28_433_000 as Weight)97 .saturating_add(T::DbWeight::get().reads(5 as Weight))97 .saturating_add(T::DbWeight::get().reads(5 as Weight))98 .saturating_add(T::DbWeight::get().writes(5 as Weight))98 .saturating_add(T::DbWeight::get().writes(5 as Weight))99 }99 }105 // Storage: Nonfungible Owned (r:0 w:1)105 // Storage: Nonfungible Owned (r:0 w:1)106 // Storage: Nonfungible TokenProperties (r:0 w:1)106 // Storage: Nonfungible TokenProperties (r:0 w:1)107 fn burn_recursively_self_raw() -> Weight {107 fn burn_recursively_self_raw() -> Weight {108 (37_955_000 as Weight)108 (34_435_000 as Weight)109 .saturating_add(T::DbWeight::get().reads(5 as Weight))109 .saturating_add(T::DbWeight::get().reads(5 as Weight))110 .saturating_add(T::DbWeight::get().writes(5 as Weight))110 .saturating_add(T::DbWeight::get().writes(5 as Weight))111 }111 }119 // Storage: Common CollectionById (r:1 w:0)119 // Storage: Common CollectionById (r:1 w:0)120 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {120 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {121 (0 as Weight)121 (0 as Weight)122 // Standard Error: 1_349_000122 // Standard Error: 1_539_000123 .saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))123 .saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))124 .saturating_add(T::DbWeight::get().reads(7 as Weight))124 .saturating_add(T::DbWeight::get().reads(7 as Weight))125 .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))125 .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))126 .saturating_add(T::DbWeight::get().writes(6 as Weight))126 .saturating_add(T::DbWeight::get().writes(6 as Weight))131 // Storage: Nonfungible Allowance (r:1 w:0)131 // Storage: Nonfungible Allowance (r:1 w:0)132 // Storage: Nonfungible Owned (r:0 w:2)132 // Storage: Nonfungible Owned (r:0 w:2)133 fn transfer() -> Weight {133 fn transfer() -> Weight {134 (27_867_000 as Weight)134 (24_376_000 as Weight)135 .saturating_add(T::DbWeight::get().reads(4 as Weight))135 .saturating_add(T::DbWeight::get().reads(4 as Weight))136 .saturating_add(T::DbWeight::get().writes(5 as Weight))136 .saturating_add(T::DbWeight::get().writes(5 as Weight))137 }137 }138 // Storage: Nonfungible TokenData (r:1 w:0)138 // Storage: Nonfungible TokenData (r:1 w:0)139 // Storage: Nonfungible Allowance (r:1 w:1)139 // Storage: Nonfungible Allowance (r:1 w:1)140 fn approve() -> Weight {140 fn approve() -> Weight {141 (18_824_000 as Weight)141 (15_890_000 as Weight)142 .saturating_add(T::DbWeight::get().reads(2 as Weight))142 .saturating_add(T::DbWeight::get().reads(2 as Weight))143 .saturating_add(T::DbWeight::get().writes(1 as Weight))143 .saturating_add(T::DbWeight::get().writes(1 as Weight))144 }144 }147 // Storage: Nonfungible AccountBalance (r:2 w:2)147 // Storage: Nonfungible AccountBalance (r:2 w:2)148 // Storage: Nonfungible Owned (r:0 w:2)148 // Storage: Nonfungible Owned (r:0 w:2)149 fn transfer_from() -> Weight {149 fn transfer_from() -> Weight {150 (32_879_000 as Weight)150 (28_634_000 as Weight)151 .saturating_add(T::DbWeight::get().reads(4 as Weight))151 .saturating_add(T::DbWeight::get().reads(4 as Weight))152 .saturating_add(T::DbWeight::get().writes(6 as Weight))152 .saturating_add(T::DbWeight::get().writes(6 as Weight))153 }153 }159 // Storage: Nonfungible Owned (r:0 w:1)159 // Storage: Nonfungible Owned (r:0 w:1)160 // Storage: Nonfungible TokenProperties (r:0 w:1)160 // Storage: Nonfungible TokenProperties (r:0 w:1)161 fn burn_from() -> Weight {161 fn burn_from() -> Weight {162 (37_061_000 as Weight)162 (32_201_000 as Weight)163 .saturating_add(T::DbWeight::get().reads(5 as Weight))163 .saturating_add(T::DbWeight::get().reads(5 as Weight))164 .saturating_add(T::DbWeight::get().writes(6 as Weight))164 .saturating_add(T::DbWeight::get().writes(6 as Weight))165 }165 }166 // Storage: Common CollectionPropertyPermissions (r:1 w:1)166 // Storage: Common CollectionPropertyPermissions (r:1 w:1)167 fn set_token_property_permissions(b: u32, ) -> Weight {167 fn set_token_property_permissions(b: u32, ) -> Weight {168 (0 as Weight)168 (0 as Weight)169 // Standard Error: 57_000169 // Standard Error: 57_000170 .saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))170 .saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))173 }173 }174 // Storage: Common CollectionPropertyPermissions (r:1 w:0)174 // Storage: Common CollectionPropertyPermissions (r:1 w:0)175 // Storage: Nonfungible TokenData (r:1 w:0)176 // Storage: Nonfungible TokenProperties (r:1 w:1)175 // Storage: Nonfungible TokenProperties (r:1 w:1)177 fn set_token_properties(b: u32, ) -> Weight {176 fn set_token_properties(b: u32, ) -> Weight {178 (0 as Weight)177 (0 as Weight)179 // Standard Error: 2_278_000178 // Standard Error: 1_648_000180 .saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))179 .saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))181 .saturating_add(T::DbWeight::get().reads(3 as Weight))180 .saturating_add(T::DbWeight::get().reads(2 as Weight))182 .saturating_add(T::DbWeight::get().writes(1 as Weight))181 .saturating_add(T::DbWeight::get().writes(1 as Weight))183 }182 }184 // Storage: Common CollectionPropertyPermissions (r:1 w:0)183 // Storage: Common CollectionPropertyPermissions (r:1 w:0)185 // Storage: Nonfungible TokenData (r:1 w:0)186 // Storage: Nonfungible TokenProperties (r:1 w:1)184 // Storage: Nonfungible TokenProperties (r:1 w:1)187 fn delete_token_properties(b: u32, ) -> Weight {185 fn delete_token_properties(b: u32, ) -> Weight {188 (0 as Weight)186 (0 as Weight)189 // Standard Error: 2_234_000187 // Standard Error: 1_632_000190 .saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))188 .saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))191 .saturating_add(T::DbWeight::get().reads(3 as Weight))189 .saturating_add(T::DbWeight::get().reads(2 as Weight))192 .saturating_add(T::DbWeight::get().writes(1 as Weight))190 .saturating_add(T::DbWeight::get().writes(1 as Weight))193 }191 }194}192}200 // Storage: Nonfungible TokenData (r:0 w:1)198 // Storage: Nonfungible TokenData (r:0 w:1)201 // Storage: Nonfungible Owned (r:0 w:1)199 // Storage: Nonfungible Owned (r:0 w:1)202 fn create_item() -> Weight {200 fn create_item() -> Weight {203 (24_135_000 as Weight)201 (20_328_000 as Weight)204 .saturating_add(RocksDbWeight::get().reads(2 as Weight))202 .saturating_add(RocksDbWeight::get().reads(2 as Weight))205 .saturating_add(RocksDbWeight::get().writes(4 as Weight))203 .saturating_add(RocksDbWeight::get().writes(4 as Weight))206 }204 }209 // Storage: Nonfungible TokenData (r:0 w:4)207 // Storage: Nonfungible TokenData (r:0 w:4)210 // Storage: Nonfungible Owned (r:0 w:4)208 // Storage: Nonfungible Owned (r:0 w:4)211 fn create_multiple_items(b: u32, ) -> Weight {209 fn create_multiple_items(b: u32, ) -> Weight {212 (21_952_000 as Weight)210 (10_134_000 as Weight)213 // Standard Error: 5_000211 // Standard Error: 3_000214 .saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))212 .saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))215 .saturating_add(RocksDbWeight::get().reads(2 as Weight))213 .saturating_add(RocksDbWeight::get().reads(2 as Weight))216 .saturating_add(RocksDbWeight::get().writes(2 as Weight))214 .saturating_add(RocksDbWeight::get().writes(2 as Weight))217 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))215 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))221 // Storage: Nonfungible TokenData (r:0 w:4)219 // Storage: Nonfungible TokenData (r:0 w:4)222 // Storage: Nonfungible Owned (r:0 w:4)220 // Storage: Nonfungible Owned (r:0 w:4)223 fn create_multiple_items_ex(b: u32, ) -> Weight {221 fn create_multiple_items_ex(b: u32, ) -> Weight {224 (10_432_000 as Weight)222 (5_710_000 as Weight)225 // Standard Error: 6_000223 // Standard Error: 4_000226 .saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))224 .saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))227 .saturating_add(RocksDbWeight::get().reads(1 as Weight))225 .saturating_add(RocksDbWeight::get().reads(1 as Weight))228 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))226 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))229 .saturating_add(RocksDbWeight::get().writes(1 as Weight))227 .saturating_add(RocksDbWeight::get().writes(1 as Weight))237 // Storage: Nonfungible Owned (r:0 w:1)235 // Storage: Nonfungible Owned (r:0 w:1)238 // Storage: Nonfungible TokenProperties (r:0 w:1)236 // Storage: Nonfungible TokenProperties (r:0 w:1)239 fn burn_item() -> Weight {237 fn burn_item() -> Weight {240 (29_798_000 as Weight)238 (28_433_000 as Weight)241 .saturating_add(RocksDbWeight::get().reads(5 as Weight))239 .saturating_add(RocksDbWeight::get().reads(5 as Weight))242 .saturating_add(RocksDbWeight::get().writes(5 as Weight))240 .saturating_add(RocksDbWeight::get().writes(5 as Weight))243 }241 }249 // Storage: Nonfungible Owned (r:0 w:1)247 // Storage: Nonfungible Owned (r:0 w:1)250 // Storage: Nonfungible TokenProperties (r:0 w:1)248 // Storage: Nonfungible TokenProperties (r:0 w:1)251 fn burn_recursively_self_raw() -> Weight {249 fn burn_recursively_self_raw() -> Weight {252 (37_955_000 as Weight)250 (34_435_000 as Weight)253 .saturating_add(RocksDbWeight::get().reads(5 as Weight))251 .saturating_add(RocksDbWeight::get().reads(5 as Weight))254 .saturating_add(RocksDbWeight::get().writes(5 as Weight))252 .saturating_add(RocksDbWeight::get().writes(5 as Weight))255 }253 }263 // Storage: Common CollectionById (r:1 w:0)261 // Storage: Common CollectionById (r:1 w:0)264 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {262 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {265 (0 as Weight)263 (0 as Weight)266 // Standard Error: 1_349_000264 // Standard Error: 1_539_000267 .saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))265 .saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))268 .saturating_add(RocksDbWeight::get().reads(7 as Weight))266 .saturating_add(RocksDbWeight::get().reads(7 as Weight))269 .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))267 .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))270 .saturating_add(RocksDbWeight::get().writes(6 as Weight))268 .saturating_add(RocksDbWeight::get().writes(6 as Weight))275 // Storage: Nonfungible Allowance (r:1 w:0)273 // Storage: Nonfungible Allowance (r:1 w:0)276 // Storage: Nonfungible Owned (r:0 w:2)274 // Storage: Nonfungible Owned (r:0 w:2)277 fn transfer() -> Weight {275 fn transfer() -> Weight {278 (27_867_000 as Weight)276 (24_376_000 as Weight)279 .saturating_add(RocksDbWeight::get().reads(4 as Weight))277 .saturating_add(RocksDbWeight::get().reads(4 as Weight))280 .saturating_add(RocksDbWeight::get().writes(5 as Weight))278 .saturating_add(RocksDbWeight::get().writes(5 as Weight))281 }279 }282 // Storage: Nonfungible TokenData (r:1 w:0)280 // Storage: Nonfungible TokenData (r:1 w:0)283 // Storage: Nonfungible Allowance (r:1 w:1)281 // Storage: Nonfungible Allowance (r:1 w:1)284 fn approve() -> Weight {282 fn approve() -> Weight {285 (18_824_000 as Weight)283 (15_890_000 as Weight)286 .saturating_add(RocksDbWeight::get().reads(2 as Weight))284 .saturating_add(RocksDbWeight::get().reads(2 as Weight))287 .saturating_add(RocksDbWeight::get().writes(1 as Weight))285 .saturating_add(RocksDbWeight::get().writes(1 as Weight))288 }286 }291 // Storage: Nonfungible AccountBalance (r:2 w:2)289 // Storage: Nonfungible AccountBalance (r:2 w:2)292 // Storage: Nonfungible Owned (r:0 w:2)290 // Storage: Nonfungible Owned (r:0 w:2)293 fn transfer_from() -> Weight {291 fn transfer_from() -> Weight {294 (32_879_000 as Weight)292 (28_634_000 as Weight)295 .saturating_add(RocksDbWeight::get().reads(4 as Weight))293 .saturating_add(RocksDbWeight::get().reads(4 as Weight))296 .saturating_add(RocksDbWeight::get().writes(6 as Weight))294 .saturating_add(RocksDbWeight::get().writes(6 as Weight))297 }295 }303 // Storage: Nonfungible Owned (r:0 w:1)301 // Storage: Nonfungible Owned (r:0 w:1)304 // Storage: Nonfungible TokenProperties (r:0 w:1)302 // Storage: Nonfungible TokenProperties (r:0 w:1)305 fn burn_from() -> Weight {303 fn burn_from() -> Weight {306 (37_061_000 as Weight)304 (32_201_000 as Weight)307 .saturating_add(RocksDbWeight::get().reads(5 as Weight))305 .saturating_add(RocksDbWeight::get().reads(5 as Weight))308 .saturating_add(RocksDbWeight::get().writes(6 as Weight))306 .saturating_add(RocksDbWeight::get().writes(6 as Weight))309 }307 }310 // Storage: Common CollectionPropertyPermissions (r:1 w:1)308 // Storage: Common CollectionPropertyPermissions (r:1 w:1)311 fn set_token_property_permissions(b: u32, ) -> Weight {309 fn set_token_property_permissions(b: u32, ) -> Weight {312 (0 as Weight)310 (0 as Weight)313 // Standard Error: 57_000311 // Standard Error: 57_000314 .saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))312 .saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))315 .saturating_add(RocksDbWeight::get().reads(1 as Weight))313 .saturating_add(RocksDbWeight::get().reads(1 as Weight))316 .saturating_add(RocksDbWeight::get().writes(1 as Weight))314 .saturating_add(RocksDbWeight::get().writes(1 as Weight))317 }315 }318 // Storage: Common CollectionPropertyPermissions (r:1 w:0)316 // Storage: Common CollectionPropertyPermissions (r:1 w:0)319 // Storage: Nonfungible TokenData (r:1 w:0)320 // Storage: Nonfungible TokenProperties (r:1 w:1)317 // Storage: Nonfungible TokenProperties (r:1 w:1)321 fn set_token_properties(b: u32, ) -> Weight {318 fn set_token_properties(b: u32, ) -> Weight {322 (0 as Weight)319 (0 as Weight)323 // Standard Error: 2_278_000320 // Standard Error: 1_648_000324 .saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))321 .saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))325 .saturating_add(RocksDbWeight::get().reads(3 as Weight))322 .saturating_add(RocksDbWeight::get().reads(2 as Weight))326 .saturating_add(RocksDbWeight::get().writes(1 as Weight))323 .saturating_add(RocksDbWeight::get().writes(1 as Weight))327 }324 }328 // Storage: Common CollectionPropertyPermissions (r:1 w:0)325 // Storage: Common CollectionPropertyPermissions (r:1 w:0)329 // Storage: Nonfungible TokenData (r:1 w:0)330 // Storage: Nonfungible TokenProperties (r:1 w:1)326 // Storage: Nonfungible TokenProperties (r:1 w:1)331 fn delete_token_properties(b: u32, ) -> Weight {327 fn delete_token_properties(b: u32, ) -> Weight {332 (0 as Weight)328 (0 as Weight)333 // Standard Error: 2_234_000329 // Standard Error: 1_632_000334 .saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))330 .saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))335 .saturating_add(RocksDbWeight::get().reads(3 as Weight))331 .saturating_add(RocksDbWeight::get().reads(2 as Weight))336 .saturating_add(RocksDbWeight::get().writes(1 as Weight))332 .saturating_add(RocksDbWeight::get().writes(1 as Weight))337 }333 }338}334}pallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.1.0"3version = "0.1.1"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/Changelog.mddiffbeforeafterbothno changes
pallets/refungible/src/benchmarking.rsdiffbeforeafterboth18use crate::{Pallet, Config, RefungibleHandle};18use crate::{Pallet, Config, RefungibleHandle};191920use sp_std::prelude::*;20use sp_std::prelude::*;21use pallet_common::benchmarking::{create_collection_raw, create_data};21use pallet_common::benchmarking::{create_collection_raw, property_key, property_value, create_data};22use frame_benchmarking::{benchmarks, account};22use frame_benchmarking::{benchmarks, account};23use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, CUSTOM_DATA_LIMIT, budget::Unlimited};23use up_data_structs::{24 CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT,25 budget::Unlimited,26};24use pallet_common::bench_init;27use pallet_common::bench_init;25use core::convert::TryInto;28use core::convert::TryInto;38 .collect::<BTreeMap<_, _>>()41 .collect::<BTreeMap<_, _>>()39 .try_into()42 .try_into()40 .unwrap(),43 .unwrap(),44 properties: Default::default(),41 }45 }42}46}43fn create_max_item<T: Config>(47fn create_max_item<T: Config>(204 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;208 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;205 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}209 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}210211 set_token_property_permissions {212 let b in 0..MAX_PROPERTIES_PER_ITEM;213 bench_init!{214 owner: sub; collection: collection(owner);215 owner: cross_from_sub;216 };217 let perms = (0..b).map(|k| PropertyKeyPermission {218 key: property_key(k as usize),219 permission: PropertyPermission {220 mutable: false,221 collection_admin: false,222 token_owner: false,223 },224 }).collect::<Vec<_>>();225 }: {<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?}226227 set_token_properties {228 let b in 0..MAX_PROPERTIES_PER_ITEM;229 bench_init!{230 owner: sub; collection: collection(owner);231 owner: cross_from_sub;232 };233 let perms = (0..b).map(|k| PropertyKeyPermission {234 key: property_key(k as usize),235 permission: PropertyPermission {236 mutable: false,237 collection_admin: true,238 token_owner: true,239 },240 }).collect::<Vec<_>>();241 <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;242 let props = (0..b).map(|k| Property {243 key: property_key(k as usize),244 value: property_value(),245 }).collect::<Vec<_>>();246 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;247 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}248249 delete_token_properties {250 let b in 0..MAX_PROPERTIES_PER_ITEM;251 bench_init!{252 owner: sub; collection: collection(owner);253 owner: cross_from_sub;254 };255 let perms = (0..b).map(|k| PropertyKeyPermission {256 key: property_key(k as usize),257 permission: PropertyPermission {258 mutable: true,259 collection_admin: true,260 token_owner: true,261 },262 }).collect::<Vec<_>>();263 <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;264 let props = (0..b).map(|k| Property {265 key: property_key(k as usize),266 value: property_value(),267 }).collect::<Vec<_>>();268 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;269 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;270 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();271 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}206272207 repartition_item {273 repartition_item {208 bench_init!{274 bench_init!{pallets/refungible/src/common.rsdiffbeforeafterboth20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};21use up_data_structs::{21use up_data_structs::{22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,23 PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData,23 PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData, CollectionPropertiesVec,24};24};25use pallet_common::{CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight};25use pallet_common::{26 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,27 weights::WeightInfo as _,28};26use pallet_structure::Error as StructureError;29use pallet_structure::Error as StructureError;27use sp_runtime::{DispatchError};30use sp_runtime::{DispatchError};41 };44 };42}45}4647fn properties_weight<T: Config>(properties: &CollectionPropertiesVec) -> u64 {48 if properties.len() > 0 {49 <CommonWeights<T>>::set_token_properties(properties.len() as u32)50 } else {51 052 }53}435444pub struct CommonWeights<T: Config>(PhantomData<T>);55pub struct CommonWeights<T: Config>(PhantomData<T>);45impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {56impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {48 }59 }496050 fn create_multiple_items(data: &[CreateItemData]) -> Weight {61 fn create_multiple_items(data: &[CreateItemData]) -> Weight {51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)62 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(63 data.iter()64 .map(|data| match data {65 CreateItemData::ReFungible(rft_data) => {66 properties_weight::<T>(&rft_data.properties)67 }68 _ => 0,69 })70 .fold(0, |a, b| a.saturating_add(b)),71 )52 }72 }537354 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {74 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {55 match call {75 match call {56 CreateItemExData::RefungibleMultipleOwners(i) => {76 CreateItemExData::RefungibleMultipleOwners(i) => {57 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)77 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)78 .saturating_add(properties_weight::<T>(&i.properties))58 }79 }59 CreateItemExData::RefungibleMultipleItems(i) => {80 CreateItemExData::RefungibleMultipleItems(i) => {60 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)81 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)82 .saturating_add(83 i.iter()84 .map(|d| properties_weight::<T>(&d.properties))85 .fold(0, |a, b| a.saturating_add(b)),86 )61 }87 }62 _ => 0,88 _ => 0,63 }89 }67 max_weight_of!(burn_item_partial(), burn_item_fully())93 max_weight_of!(burn_item_partial(), burn_item_fully())68 }94 }699570 fn set_collection_properties(_amount: u32) -> Weight {96 fn set_collection_properties(amount: u32) -> Weight {71 // Error97 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)72 073 }98 }749975 fn delete_collection_properties(_amount: u32) -> Weight {100 fn delete_collection_properties(amount: u32) -> Weight {76 // Error101 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)77 078 }102 }7910380 fn set_token_properties(_amount: u32) -> Weight {104 fn set_token_properties(amount: u32) -> Weight {81 // Error105 <SelfWeightOf<T>>::set_token_properties(amount)82 083 }106 }8410785 fn delete_token_properties(_amount: u32) -> Weight {108 fn delete_token_properties(amount: u32) -> Weight {86 // Error109 <SelfWeightOf<T>>::delete_token_properties(amount)87 088 }110 }8911190 fn set_token_property_permissions(_amount: u32) -> Weight {112 fn set_token_property_permissions(amount: u32) -> Weight {91 // Error113 <SelfWeightOf<T>>::set_token_property_permissions(amount)92 093 }114 }9411595 fn transfer() -> Weight {116 fn transfer() -> Weight {140 out.insert(to.clone(), data.pieces);161 out.insert(to.clone(), data.pieces);141 out.try_into().expect("limit > 0")162 out.try_into().expect("limit > 0")142 },163 },164 properties: data.properties,143 }),165 }),144 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),166 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),145 }167 }297319298 fn set_collection_properties(320 fn set_collection_properties(299 &self,321 &self,300 _sender: T::CrossAccountId,322 sender: T::CrossAccountId,301 _property: Vec<Property>,323 properties: Vec<Property>,302 ) -> DispatchResultWithPostInfo {324 ) -> DispatchResultWithPostInfo {325 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);326303 fail!(<Error<T>>::SettingPropertiesNotAllowed)327 with_weight(328 <Pallet<T>>::set_collection_properties(self, &sender, properties),329 weight,330 )304 }331 }305332306 fn delete_collection_properties(333 fn delete_collection_properties(307 &self,334 &self,308 _sender: &T::CrossAccountId,335 sender: &T::CrossAccountId,309 _property_keys: Vec<PropertyKey>,336 property_keys: Vec<PropertyKey>,310 ) -> DispatchResultWithPostInfo {337 ) -> DispatchResultWithPostInfo {338 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);339311 fail!(<Error<T>>::SettingPropertiesNotAllowed)340 with_weight(341 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),342 weight,343 )312 }344 }313345314 fn set_token_properties(346 fn set_token_properties(315 &self,347 &self,316 _sender: T::CrossAccountId,348 sender: T::CrossAccountId,317 _token_id: TokenId,349 token_id: TokenId,318 _property: Vec<Property>,350 properties: Vec<Property>,319 _nesting_budget: &dyn Budget,351 nesting_budget: &dyn Budget,320 ) -> DispatchResultWithPostInfo {352 ) -> DispatchResultWithPostInfo {353 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);354321 fail!(<Error<T>>::SettingPropertiesNotAllowed)355 with_weight(356 <Pallet<T>>::set_token_properties(357 self,358 &sender,359 token_id,360 properties.into_iter(),361 false,362 nesting_budget,363 ),364 weight,365 )322 }366 }323367324 fn set_token_property_permissions(368 fn set_token_property_permissions(325 &self,369 &self,326 _sender: &T::CrossAccountId,370 sender: &T::CrossAccountId,327 _property_permissions: Vec<PropertyKeyPermission>,371 property_permissions: Vec<PropertyKeyPermission>,328 ) -> DispatchResultWithPostInfo {372 ) -> DispatchResultWithPostInfo {373 let weight =374 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);375329 fail!(<Error<T>>::SettingPropertiesNotAllowed)376 with_weight(377 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),378 weight,379 )330 }380 }331381332 fn delete_token_properties(382 fn delete_token_properties(333 &self,383 &self,334 _sender: T::CrossAccountId,384 sender: T::CrossAccountId,335 _token_id: TokenId,385 token_id: TokenId,336 _property_keys: Vec<PropertyKey>,386 property_keys: Vec<PropertyKey>,337 _nesting_budget: &dyn Budget,387 nesting_budget: &dyn Budget,338 ) -> DispatchResultWithPostInfo {388 ) -> DispatchResultWithPostInfo {389 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);390339 fail!(<Error<T>>::SettingPropertiesNotAllowed)391 with_weight(392 <Pallet<T>>::delete_token_properties(393 self,394 &sender,395 token_id,396 property_keys.into_iter(),397 nesting_budget,398 ),399 weight,400 )340 }401 }341402373 TokenId(<TokensMinted<T>>::get(self.id))434 TokenId(<TokensMinted<T>>::get(self.id))374 }435 }375436376 fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {437 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {377 None438 <Pallet<T>>::token_owner(self.id, token)378 }439 }379440380 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {441 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {pallets/refungible/src/lib.rsdiffbeforeafterboth878788#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]898990use frame_support::{ensure, BoundedVec};90use frame_support::{ensure, fail, BoundedVec, transactional, storage::with_transaction};91use up_data_structs::{91use up_data_structs::{92 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,92 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,93 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,93 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,94 Property, PropertyScope, TrySetProperty, PropertyKey, PropertyValue, PropertyPermission,95 PropertyKeyPermission,94};96};95use pallet_evm::account::CrossAccountId;97use pallet_evm::account::CrossAccountId;96use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};98use pallet_common::{99 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,100 CommonCollectionOperations as _,101};97use pallet_structure::Pallet as PalletStructure;102use pallet_structure::Pallet as PalletStructure;98use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};103use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};99use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};104use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};100use core::ops::Deref;105use core::ops::Deref;101use codec::{Encode, Decode, MaxEncodedLen};106use codec::{Encode, Decode, MaxEncodedLen};175 QueryKind = ValueQuery,180 QueryKind = ValueQuery,176 >;181 >;182183 #[pallet::storage]184 #[pallet::getter(fn token_properties)]185 pub type TokenProperties<T: Config> = StorageNMap<186 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),187 Value = up_data_structs::Properties,188 QueryKind = ValueQuery,189 OnEmpty = up_data_structs::TokenProperties,190 >;177191178 /// Total amount of pieces for token192 /// Total amount of pieces for token179 #[pallet::storage]193 #[pallet::storage]279 <TotalSupply<T>>::contains_key((collection.id, token))293 <TotalSupply<T>>::contains_key((collection.id, token))280 }294 }295296 pub fn set_scoped_token_property(297 collection_id: CollectionId,298 token_id: TokenId,299 scope: PropertyScope,300 property: Property,301 ) -> DispatchResult {302 TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {303 properties.try_scoped_set(scope, property.key, property.value)304 })305 .map_err(<CommonError<T>>::from)?;306307 Ok(())308 }309310 pub fn set_scoped_token_properties(311 collection_id: CollectionId,312 token_id: TokenId,313 scope: PropertyScope,314 properties: impl Iterator<Item = Property>,315 ) -> DispatchResult {316 TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {317 stored_properties.try_scoped_set_from_iter(scope, properties)318 })319 .map_err(<CommonError<T>>::from)?;320321 Ok(())322 }281}323}282324283// unchecked calls skips any permission checks325// unchecked calls skips any permission checks339381340 <TokensBurnt<T>>::insert(collection.id, burnt);382 <TokensBurnt<T>>::insert(collection.id, burnt);341 <TokenData<T>>::remove((collection.id, token_id));383 <TokenData<T>>::remove((collection.id, token_id));384 <TokenProperties<T>>::remove((collection.id, token_id));342 <TotalSupply<T>>::remove((collection.id, token_id));385 <TotalSupply<T>>::remove((collection.id, token_id));343 <Balance<T>>::remove_prefix((collection.id, token_id), None);386 <Balance<T>>::remove_prefix((collection.id, token_id), None);344 <Allowance<T>>::remove_prefix((collection.id, token_id), None);387 <Allowance<T>>::remove_prefix((collection.id, token_id), None);427 Ok(())470 Ok(())428 }471 }472473 #[transactional]474 fn modify_token_properties(475 collection: &RefungibleHandle<T>,476 sender: &T::CrossAccountId,477 token_id: TokenId,478 properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,479 is_token_create: bool,480 nesting_budget: &dyn Budget,481 ) -> DispatchResult {482 let is_collection_admin = || collection.is_owner_or_admin(sender);483 let is_token_owner = || -> Result<bool, DispatchError> {484 let balance = collection.balance(sender.clone(), token_id);485 let total_pieces: u128 =486 Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);487 if balance != total_pieces {488 return Ok(false);489 }490491 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(492 sender.clone(),493 collection.id,494 token_id,495 None,496 nesting_budget,497 )?;498499 Ok(is_bundle_owner)500 };501502 for (key, value) in properties {503 let permission = <PalletCommon<T>>::property_permissions(collection.id)504 .get(&key)505 .cloned()506 .unwrap_or_else(PropertyPermission::none);507508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))509 .get(&key)510 .is_some();511512 match permission {513 PropertyPermission { mutable: false, .. } if is_property_exists => {514 return Err(<CommonError<T>>::NoPermission.into());515 }516517 PropertyPermission {518 collection_admin,519 token_owner,520 ..521 } => {522 //TODO: investigate threats during public minting.523 let is_token_create =524 is_token_create && (collection_admin || token_owner) && value.is_some();525 if !(is_token_create526 || (collection_admin && is_collection_admin())527 || (token_owner && is_token_owner()?))528 {529 fail!(<CommonError<T>>::NoPermission);530 }531 }532 }533534 match value {535 Some(value) => {536 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {537 properties.try_set(key.clone(), value)538 })539 .map_err(<CommonError<T>>::from)?;540541 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(542 collection.id,543 token_id,544 key,545 ));546 }547 None => {548 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {549 properties.remove(&key)550 })551 .map_err(<CommonError<T>>::from)?;552553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(554 collection.id,555 token_id,556 key,557 ));558 }559 }560 }561562 Ok(())563 }564565 pub fn set_token_properties(566 collection: &RefungibleHandle<T>,567 sender: &T::CrossAccountId,568 token_id: TokenId,569 properties: impl Iterator<Item = Property>,570 is_token_create: bool,571 nesting_budget: &dyn Budget,572 ) -> DispatchResult {573 Self::modify_token_properties(574 collection,575 sender,576 token_id,577 properties.map(|p| (p.key, Some(p.value))),578 is_token_create,579 nesting_budget,580 )581 }582583 pub fn set_token_property(584 collection: &RefungibleHandle<T>,585 sender: &T::CrossAccountId,586 token_id: TokenId,587 property: Property,588 nesting_budget: &dyn Budget,589 ) -> DispatchResult {590 let is_token_create = false;591592 Self::set_token_properties(593 collection,594 sender,595 token_id,596 [property].into_iter(),597 is_token_create,598 nesting_budget,599 )600 }601602 pub fn delete_token_properties(603 collection: &RefungibleHandle<T>,604 sender: &T::CrossAccountId,605 token_id: TokenId,606 property_keys: impl Iterator<Item = PropertyKey>,607 nesting_budget: &dyn Budget,608 ) -> DispatchResult {609 let is_token_create = false;610611 Self::modify_token_properties(612 collection,613 sender,614 token_id,615 property_keys.into_iter().map(|key| (key, None)),616 is_token_create,617 nesting_budget,618 )619 }620621 pub fn delete_token_property(622 collection: &RefungibleHandle<T>,623 sender: &T::CrossAccountId,624 token_id: TokenId,625 property_key: PropertyKey,626 nesting_budget: &dyn Budget,627 ) -> DispatchResult {628 Self::delete_token_properties(629 collection,630 sender,631 token_id,632 [property_key].into_iter(),633 nesting_budget,634 )635 }429636430 /// Transfer RFT token pieces from one account to another.637 /// Transfer RFT token pieces from one account to another.431 ///638 ///629836630 // =========837 // =========631838632 <TokensMinted<T>>::insert(collection.id, tokens_minted);839 with_transaction(|| {633 for (account, balance) in balances {634 <AccountBalance<T>>::insert((collection.id, account), balance);635 }636 for (i, token) in data.into_iter().enumerate() {840 for (i, data) in data.iter().enumerate() {637 let token_id = first_token_id + i as u32 + 1;841 let token_id = first_token_id + i as u32 + 1;638 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);842 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);639843640 <TokenData<T>>::insert(844 <TokenData<T>>::insert(641 (collection.id, token_id),845 (collection.id, token_id),642 ItemData {846 ItemData {643 const_data: token.const_data,847 const_data: data.const_data.clone(),644 },848 },645 );849 );646850647 for (user, amount) in token.users.into_iter() {851 for (user, amount) in data.users.iter() {648 if amount == 0 {852 if *amount == 0 {649 continue;853 continue;650 }854 }651 <Balance<T>>::insert((collection.id, token_id, &user), amount);855 <Balance<T>>::insert((collection.id, token_id, &user), amount);652 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);856 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);653 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(857 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(654 &user,858 user,655 collection.id,859 collection.id,656 TokenId(token_id),860 TokenId(token_id),657 );861 );658659 // TODO: ERC20 transfer event660 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(661 collection.id,662 TokenId(token_id),663 user,664 amount,665 ));666 }862 }863864 if let Err(e) = Self::set_token_properties(865 collection,866 sender,867 TokenId(token_id),868 data.properties.clone().into_iter(),869 true,870 nesting_budget,871 ) {872 return TransactionOutcome::Rollback(Err(e));873 }667 }874 }875 TransactionOutcome::Commit(Ok(()))876 })?;877878 <TokensMinted<T>>::insert(collection.id, tokens_minted);879880 for (account, balance) in balances {881 <AccountBalance<T>>::insert((collection.id, account), balance);882 }883884 for (i, token) in data.into_iter().enumerate() {885 let token_id = first_token_id + i as u32 + 1;886887 for (user, amount) in token.users.into_iter() {888 if amount == 0 {889 continue;890 }891892 // TODO: ERC20 transfer event893 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(894 collection.id,895 TokenId(token_id),896 user,897 amount,898 ));899 }900 }668 Ok(())901 Ok(())669 }902 }670903849 );1082 );850 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1083 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);851 // Ensure user owns all pieces1084 // Ensure user owns all pieces852 let total_supply = <TotalSupply<T>>::get((collection.id, token));1085 let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);853 let balance = <Balance<T>>::get((collection.id, token, owner));1086 let balance = <Balance<T>>::get((collection.id, token, owner));854 ensure!(1087 ensure!(855 total_supply == balance,1088 total_pieces == balance,856 <Error<T>>::RepartitionWhileNotOwningAllPieces1089 <Error<T>>::RepartitionWhileNotOwningAllPieces857 );1090 );8581091861 Ok(())1094 Ok(())862 }1095 }10961097 fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {1098 let mut owner = None;1099 let mut count = 0;1100 for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1101 count += 1;1102 if count > 1 {1103 return None;1104 }1105 owner = Some(key);1106 }1107 owner1108 }8631109864 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1110 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {865 <TotalSupply<T>>::try_get((collection_id, token_id)).ok()1111 <TotalSupply<T>>::try_get((collection_id, token_id)).ok()866 }1112 }11131114 pub fn set_collection_properties(1115 collection: &RefungibleHandle<T>,1116 sender: &T::CrossAccountId,1117 properties: Vec<Property>,1118 ) -> DispatchResult {1119 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)1120 }11211122 pub fn delete_collection_properties(1123 collection: &RefungibleHandle<T>,1124 sender: &T::CrossAccountId,1125 property_keys: Vec<PropertyKey>,1126 ) -> DispatchResult {1127 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)1128 }11291130 pub fn set_token_property_permissions(1131 collection: &RefungibleHandle<T>,1132 sender: &T::CrossAccountId,1133 property_permissions: Vec<PropertyKeyPermission>,1134 ) -> DispatchResult {1135 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1136 }867}1137}8681138pallets/refungible/src/weights.rsdiffbeforeafterboth3//! Autogenerated weights for pallet_refungible3//! Autogenerated weights for pallet_refungible4//!4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-06-27, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024889// Executed Command:9// Executed Command:49 fn transfer_from_removing() -> Weight;49 fn transfer_from_removing() -> Weight;50 fn transfer_from_creating_removing() -> Weight;50 fn transfer_from_creating_removing() -> Weight;51 fn burn_from() -> Weight;51 fn burn_from() -> Weight;52 fn set_token_property_permissions(b: u32, ) -> Weight;53 fn set_token_properties(b: u32, ) -> Weight;54 fn delete_token_properties(b: u32, ) -> Weight;52 fn repartition_item() -> Weight;55 fn repartition_item() -> Weight;53}56}545762 // Storage: Refungible TokenData (r:0 w:1)65 // Storage: Refungible TokenData (r:0 w:1)63 // Storage: Refungible Owned (r:0 w:1)66 // Storage: Refungible Owned (r:0 w:1)64 fn create_item() -> Weight {67 fn create_item() -> Weight {65 (17_553_000 as Weight)68 (21_310_000 as Weight)66 .saturating_add(T::DbWeight::get().reads(2 as Weight))69 .saturating_add(T::DbWeight::get().reads(2 as Weight))67 .saturating_add(T::DbWeight::get().writes(6 as Weight))70 .saturating_add(T::DbWeight::get().writes(6 as Weight))68 }71 }73 // Storage: Refungible TokenData (r:0 w:4)76 // Storage: Refungible TokenData (r:0 w:4)74 // Storage: Refungible Owned (r:0 w:4)77 // Storage: Refungible Owned (r:0 w:4)75 fn create_multiple_items(b: u32, ) -> Weight {78 fn create_multiple_items(b: u32, ) -> Weight {76 (10_654_000 as Weight)79 (9_552_000 as Weight)77 // Standard Error: 1_00080 // Standard Error: 2_00078 .saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))81 .saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))79 .saturating_add(T::DbWeight::get().reads(2 as Weight))82 .saturating_add(T::DbWeight::get().reads(2 as Weight))80 .saturating_add(T::DbWeight::get().writes(2 as Weight))83 .saturating_add(T::DbWeight::get().writes(2 as Weight))81 .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))84 .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))87 // Storage: Refungible TokenData (r:0 w:4)90 // Storage: Refungible TokenData (r:0 w:4)88 // Storage: Refungible Owned (r:0 w:4)91 // Storage: Refungible Owned (r:0 w:4)89 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {92 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {90 (3_587_000 as Weight)93 (4_857_000 as Weight)91 // Standard Error: 2_00094 // Standard Error: 2_00092 .saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))95 .saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))93 .saturating_add(T::DbWeight::get().reads(1 as Weight))96 .saturating_add(T::DbWeight::get().reads(1 as Weight))94 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))97 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))95 .saturating_add(T::DbWeight::get().writes(1 as Weight))98 .saturating_add(T::DbWeight::get().writes(1 as Weight))102 // Storage: Refungible Balance (r:0 w:4)105 // Storage: Refungible Balance (r:0 w:4)103 // Storage: Refungible Owned (r:0 w:4)106 // Storage: Refungible Owned (r:0 w:4)104 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {107 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {105 (1_980_000 as Weight)108 (11_335_000 as Weight)106 // Standard Error: 2_000109 // Standard Error: 2_000107 .saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))110 .saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))108 .saturating_add(T::DbWeight::get().reads(1 as Weight))111 .saturating_add(T::DbWeight::get().reads(1 as Weight))109 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))112 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))110 .saturating_add(T::DbWeight::get().writes(3 as Weight))113 .saturating_add(T::DbWeight::get().writes(3 as Weight))115 // Storage: Refungible AccountBalance (r:1 w:1)118 // Storage: Refungible AccountBalance (r:1 w:1)116 // Storage: Refungible Owned (r:0 w:1)119 // Storage: Refungible Owned (r:0 w:1)117 fn burn_item_partial() -> Weight {120 fn burn_item_partial() -> Weight {118 (21_010_000 as Weight)121 (21_239_000 as Weight)119 .saturating_add(T::DbWeight::get().reads(3 as Weight))122 .saturating_add(T::DbWeight::get().reads(3 as Weight))120 .saturating_add(T::DbWeight::get().writes(4 as Weight))123 .saturating_add(T::DbWeight::get().writes(4 as Weight))121 }124 }125 // Storage: Refungible TokensBurnt (r:1 w:1)128 // Storage: Refungible TokensBurnt (r:1 w:1)126 // Storage: Refungible TokenData (r:0 w:1)129 // Storage: Refungible TokenData (r:0 w:1)127 // Storage: Refungible Owned (r:0 w:1)130 // Storage: Refungible Owned (r:0 w:1)131 // Storage: Refungible TokenProperties (r:0 w:1)128 fn burn_item_fully() -> Weight {132 fn burn_item_fully() -> Weight {129 (28_413_000 as Weight)133 (29_426_000 as Weight)130 .saturating_add(T::DbWeight::get().reads(4 as Weight))134 .saturating_add(T::DbWeight::get().reads(4 as Weight))131 .saturating_add(T::DbWeight::get().writes(6 as Weight))135 .saturating_add(T::DbWeight::get().writes(7 as Weight))132 }136 }133 // Storage: Refungible Balance (r:2 w:2)137 // Storage: Refungible Balance (r:2 w:2)134 fn transfer_normal() -> Weight {138 fn transfer_normal() -> Weight {135 (17_513_000 as Weight)139 (17_743_000 as Weight)136 .saturating_add(T::DbWeight::get().reads(2 as Weight))140 .saturating_add(T::DbWeight::get().reads(2 as Weight))137 .saturating_add(T::DbWeight::get().writes(2 as Weight))141 .saturating_add(T::DbWeight::get().writes(2 as Weight))138 }142 }139 // Storage: Refungible Balance (r:2 w:2)143 // Storage: Refungible Balance (r:2 w:2)140 // Storage: Refungible AccountBalance (r:1 w:1)144 // Storage: Refungible AccountBalance (r:1 w:1)141 // Storage: Refungible Owned (r:0 w:1)145 // Storage: Refungible Owned (r:0 w:1)142 fn transfer_creating() -> Weight {146 fn transfer_creating() -> Weight {143 (20_469_000 as Weight)147 (20_699_000 as Weight)144 .saturating_add(T::DbWeight::get().reads(3 as Weight))148 .saturating_add(T::DbWeight::get().reads(3 as Weight))145 .saturating_add(T::DbWeight::get().writes(4 as Weight))149 .saturating_add(T::DbWeight::get().writes(4 as Weight))146 }150 }147 // Storage: Refungible Balance (r:2 w:2)151 // Storage: Refungible Balance (r:2 w:2)148 // Storage: Refungible AccountBalance (r:1 w:1)152 // Storage: Refungible AccountBalance (r:1 w:1)149 // Storage: Refungible Owned (r:0 w:1)153 // Storage: Refungible Owned (r:0 w:1)150 fn transfer_removing() -> Weight {154 fn transfer_removing() -> Weight {151 (22_472_000 as Weight)155 (22_833_000 as Weight)152 .saturating_add(T::DbWeight::get().reads(3 as Weight))156 .saturating_add(T::DbWeight::get().reads(3 as Weight))153 .saturating_add(T::DbWeight::get().writes(4 as Weight))157 .saturating_add(T::DbWeight::get().writes(4 as Weight))154 }158 }155 // Storage: Refungible Balance (r:2 w:2)159 // Storage: Refungible Balance (r:2 w:2)156 // Storage: Refungible AccountBalance (r:2 w:2)160 // Storage: Refungible AccountBalance (r:2 w:2)157 // Storage: Refungible Owned (r:0 w:2)161 // Storage: Refungible Owned (r:0 w:2)158 fn transfer_creating_removing() -> Weight {162 fn transfer_creating_removing() -> Weight {159 (24_866_000 as Weight)163 (24_936_000 as Weight)160 .saturating_add(T::DbWeight::get().reads(4 as Weight))164 .saturating_add(T::DbWeight::get().reads(4 as Weight))161 .saturating_add(T::DbWeight::get().writes(6 as Weight))165 .saturating_add(T::DbWeight::get().writes(6 as Weight))162 }166 }163 // Storage: Refungible Balance (r:1 w:0)167 // Storage: Refungible Balance (r:1 w:0)164 // Storage: Refungible Allowance (r:0 w:1)168 // Storage: Refungible Allowance (r:0 w:1)165 fn approve() -> Weight {169 fn approve() -> Weight {166 (13_475_000 as Weight)170 (13_446_000 as Weight)167 .saturating_add(T::DbWeight::get().reads(1 as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))168 .saturating_add(T::DbWeight::get().writes(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))169 }173 }170 // Storage: Refungible Allowance (r:1 w:1)174 // Storage: Refungible Allowance (r:1 w:1)171 // Storage: Refungible Balance (r:2 w:2)175 // Storage: Refungible Balance (r:2 w:2)172 fn transfer_from_normal() -> Weight {176 fn transfer_from_normal() -> Weight {173 (24_707_000 as Weight)177 (24_777_000 as Weight)174 .saturating_add(T::DbWeight::get().reads(3 as Weight))178 .saturating_add(T::DbWeight::get().reads(3 as Weight))175 .saturating_add(T::DbWeight::get().writes(3 as Weight))179 .saturating_add(T::DbWeight::get().writes(3 as Weight))176 }180 }179 // Storage: Refungible AccountBalance (r:1 w:1)183 // Storage: Refungible AccountBalance (r:1 w:1)180 // Storage: Refungible Owned (r:0 w:1)184 // Storage: Refungible Owned (r:0 w:1)181 fn transfer_from_creating() -> Weight {185 fn transfer_from_creating() -> Weight {182 (27_812_000 as Weight)186 (28_483_000 as Weight)183 .saturating_add(T::DbWeight::get().reads(4 as Weight))187 .saturating_add(T::DbWeight::get().reads(4 as Weight))184 .saturating_add(T::DbWeight::get().writes(5 as Weight))188 .saturating_add(T::DbWeight::get().writes(5 as Weight))185 }189 }188 // Storage: Refungible AccountBalance (r:1 w:1)192 // Storage: Refungible AccountBalance (r:1 w:1)189 // Storage: Refungible Owned (r:0 w:1)193 // Storage: Refungible Owned (r:0 w:1)190 fn transfer_from_removing() -> Weight {194 fn transfer_from_removing() -> Weight {191 (29_966_000 as Weight)195 (29_896_000 as Weight)192 .saturating_add(T::DbWeight::get().reads(4 as Weight))196 .saturating_add(T::DbWeight::get().reads(4 as Weight))193 .saturating_add(T::DbWeight::get().writes(5 as Weight))197 .saturating_add(T::DbWeight::get().writes(5 as Weight))194 }198 }197 // Storage: Refungible AccountBalance (r:2 w:2)201 // Storage: Refungible AccountBalance (r:2 w:2)198 // Storage: Refungible Owned (r:0 w:2)202 // Storage: Refungible Owned (r:0 w:2)199 fn transfer_from_creating_removing() -> Weight {203 fn transfer_from_creating_removing() -> Weight {200 (31_660_000 as Weight)204 (32_070_000 as Weight)201 .saturating_add(T::DbWeight::get().reads(5 as Weight))205 .saturating_add(T::DbWeight::get().reads(5 as Weight))202 .saturating_add(T::DbWeight::get().writes(7 as Weight))206 .saturating_add(T::DbWeight::get().writes(7 as Weight))203 }207 }208 // Storage: Refungible TokensBurnt (r:1 w:1)212 // Storage: Refungible TokensBurnt (r:1 w:1)209 // Storage: Refungible TokenData (r:0 w:1)213 // Storage: Refungible TokenData (r:0 w:1)210 // Storage: Refungible Owned (r:0 w:1)214 // Storage: Refungible Owned (r:0 w:1)215 // Storage: Refungible TokenProperties (r:0 w:1)211 fn burn_from() -> Weight {216 fn burn_from() -> Weight {212 (36_248_000 as Weight)217 (36_789_000 as Weight)213 .saturating_add(T::DbWeight::get().reads(5 as Weight))218 .saturating_add(T::DbWeight::get().reads(5 as Weight))214 .saturating_add(T::DbWeight::get().writes(7 as Weight))219 .saturating_add(T::DbWeight::get().writes(8 as Weight))215 }220 }221 // Storage: Common CollectionPropertyPermissions (r:1 w:1)222 fn set_token_property_permissions(b: u32, ) -> Weight {223 (0 as Weight)224 // Standard Error: 62_000225 .saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))226 .saturating_add(T::DbWeight::get().reads(1 as Weight))227 .saturating_add(T::DbWeight::get().writes(1 as Weight))228 }229 // Storage: Common CollectionPropertyPermissions (r:1 w:0)230 // Storage: Refungible TokenProperties (r:1 w:1)231 fn set_token_properties(b: u32, ) -> Weight {232 (0 as Weight)233 // Standard Error: 1_668_000234 .saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))235 .saturating_add(T::DbWeight::get().reads(2 as Weight))236 .saturating_add(T::DbWeight::get().writes(1 as Weight))237 }238 // Storage: Common CollectionPropertyPermissions (r:1 w:0)239 // Storage: Refungible TokenProperties (r:1 w:1)240 fn delete_token_properties(b: u32, ) -> Weight {241 (0 as Weight)242 // Standard Error: 1_619_000243 .saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))244 .saturating_add(T::DbWeight::get().reads(2 as Weight))245 .saturating_add(T::DbWeight::get().writes(1 as Weight))246 }216 // Storage: Refungible TotalSupply (r:1 w:1)247 // Storage: Refungible TotalSupply (r:1 w:1)217 // Storage: Refungible Balance (r:1 w:1)248 // Storage: Refungible Balance (r:1 w:1)218 fn repartition_item() -> Weight {249 fn repartition_item() -> Weight {219 (8_226_000 as Weight)250 (8_325_000 as Weight)220 .saturating_add(T::DbWeight::get().reads(2 as Weight))251 .saturating_add(T::DbWeight::get().reads(2 as Weight))221 .saturating_add(T::DbWeight::get().writes(2 as Weight))252 .saturating_add(T::DbWeight::get().writes(2 as Weight))222 }253 }231 // Storage: Refungible TokenData (r:0 w:1)262 // Storage: Refungible TokenData (r:0 w:1)232 // Storage: Refungible Owned (r:0 w:1)263 // Storage: Refungible Owned (r:0 w:1)233 fn create_item() -> Weight {264 fn create_item() -> Weight {234 (17_553_000 as Weight)265 (21_310_000 as Weight)235 .saturating_add(RocksDbWeight::get().reads(2 as Weight))266 .saturating_add(RocksDbWeight::get().reads(2 as Weight))236 .saturating_add(RocksDbWeight::get().writes(6 as Weight))267 .saturating_add(RocksDbWeight::get().writes(6 as Weight))237 }268 }242 // Storage: Refungible TokenData (r:0 w:4)273 // Storage: Refungible TokenData (r:0 w:4)243 // Storage: Refungible Owned (r:0 w:4)274 // Storage: Refungible Owned (r:0 w:4)244 fn create_multiple_items(b: u32, ) -> Weight {275 fn create_multiple_items(b: u32, ) -> Weight {245 (10_654_000 as Weight)276 (9_552_000 as Weight)246 // Standard Error: 1_000277 // Standard Error: 2_000247 .saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))278 .saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))248 .saturating_add(RocksDbWeight::get().reads(2 as Weight))279 .saturating_add(RocksDbWeight::get().reads(2 as Weight))249 .saturating_add(RocksDbWeight::get().writes(2 as Weight))280 .saturating_add(RocksDbWeight::get().writes(2 as Weight))250 .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))281 .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))256 // Storage: Refungible TokenData (r:0 w:4)287 // Storage: Refungible TokenData (r:0 w:4)257 // Storage: Refungible Owned (r:0 w:4)288 // Storage: Refungible Owned (r:0 w:4)258 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {289 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {259 (3_587_000 as Weight)290 (4_857_000 as Weight)260 // Standard Error: 2_000291 // Standard Error: 2_000261 .saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))292 .saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))262 .saturating_add(RocksDbWeight::get().reads(1 as Weight))293 .saturating_add(RocksDbWeight::get().reads(1 as Weight))263 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))294 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))264 .saturating_add(RocksDbWeight::get().writes(1 as Weight))295 .saturating_add(RocksDbWeight::get().writes(1 as Weight))271 // Storage: Refungible Balance (r:0 w:4)302 // Storage: Refungible Balance (r:0 w:4)272 // Storage: Refungible Owned (r:0 w:4)303 // Storage: Refungible Owned (r:0 w:4)273 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {304 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {274 (1_980_000 as Weight)305 (11_335_000 as Weight)275 // Standard Error: 2_000306 // Standard Error: 2_000276 .saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))307 .saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))277 .saturating_add(RocksDbWeight::get().reads(1 as Weight))308 .saturating_add(RocksDbWeight::get().reads(1 as Weight))278 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))309 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))279 .saturating_add(RocksDbWeight::get().writes(3 as Weight))310 .saturating_add(RocksDbWeight::get().writes(3 as Weight))284 // Storage: Refungible AccountBalance (r:1 w:1)315 // Storage: Refungible AccountBalance (r:1 w:1)285 // Storage: Refungible Owned (r:0 w:1)316 // Storage: Refungible Owned (r:0 w:1)286 fn burn_item_partial() -> Weight {317 fn burn_item_partial() -> Weight {287 (21_010_000 as Weight)318 (21_239_000 as Weight)288 .saturating_add(RocksDbWeight::get().reads(3 as Weight))319 .saturating_add(RocksDbWeight::get().reads(3 as Weight))289 .saturating_add(RocksDbWeight::get().writes(4 as Weight))320 .saturating_add(RocksDbWeight::get().writes(4 as Weight))290 }321 }294 // Storage: Refungible TokensBurnt (r:1 w:1)325 // Storage: Refungible TokensBurnt (r:1 w:1)295 // Storage: Refungible TokenData (r:0 w:1)326 // Storage: Refungible TokenData (r:0 w:1)296 // Storage: Refungible Owned (r:0 w:1)327 // Storage: Refungible Owned (r:0 w:1)328 // Storage: Refungible TokenProperties (r:0 w:1)297 fn burn_item_fully() -> Weight {329 fn burn_item_fully() -> Weight {298 (28_413_000 as Weight)330 (29_426_000 as Weight)299 .saturating_add(RocksDbWeight::get().reads(4 as Weight))331 .saturating_add(RocksDbWeight::get().reads(4 as Weight))300 .saturating_add(RocksDbWeight::get().writes(6 as Weight))332 .saturating_add(RocksDbWeight::get().writes(7 as Weight))301 }333 }302 // Storage: Refungible Balance (r:2 w:2)334 // Storage: Refungible Balance (r:2 w:2)303 fn transfer_normal() -> Weight {335 fn transfer_normal() -> Weight {304 (17_513_000 as Weight)336 (17_743_000 as Weight)305 .saturating_add(RocksDbWeight::get().reads(2 as Weight))337 .saturating_add(RocksDbWeight::get().reads(2 as Weight))306 .saturating_add(RocksDbWeight::get().writes(2 as Weight))338 .saturating_add(RocksDbWeight::get().writes(2 as Weight))307 }339 }308 // Storage: Refungible Balance (r:2 w:2)340 // Storage: Refungible Balance (r:2 w:2)309 // Storage: Refungible AccountBalance (r:1 w:1)341 // Storage: Refungible AccountBalance (r:1 w:1)310 // Storage: Refungible Owned (r:0 w:1)342 // Storage: Refungible Owned (r:0 w:1)311 fn transfer_creating() -> Weight {343 fn transfer_creating() -> Weight {312 (20_469_000 as Weight)344 (20_699_000 as Weight)313 .saturating_add(RocksDbWeight::get().reads(3 as Weight))345 .saturating_add(RocksDbWeight::get().reads(3 as Weight))314 .saturating_add(RocksDbWeight::get().writes(4 as Weight))346 .saturating_add(RocksDbWeight::get().writes(4 as Weight))315 }347 }316 // Storage: Refungible Balance (r:2 w:2)348 // Storage: Refungible Balance (r:2 w:2)317 // Storage: Refungible AccountBalance (r:1 w:1)349 // Storage: Refungible AccountBalance (r:1 w:1)318 // Storage: Refungible Owned (r:0 w:1)350 // Storage: Refungible Owned (r:0 w:1)319 fn transfer_removing() -> Weight {351 fn transfer_removing() -> Weight {320 (22_472_000 as Weight)352 (22_833_000 as Weight)321 .saturating_add(RocksDbWeight::get().reads(3 as Weight))353 .saturating_add(RocksDbWeight::get().reads(3 as Weight))322 .saturating_add(RocksDbWeight::get().writes(4 as Weight))354 .saturating_add(RocksDbWeight::get().writes(4 as Weight))323 }355 }324 // Storage: Refungible Balance (r:2 w:2)356 // Storage: Refungible Balance (r:2 w:2)325 // Storage: Refungible AccountBalance (r:2 w:2)357 // Storage: Refungible AccountBalance (r:2 w:2)326 // Storage: Refungible Owned (r:0 w:2)358 // Storage: Refungible Owned (r:0 w:2)327 fn transfer_creating_removing() -> Weight {359 fn transfer_creating_removing() -> Weight {328 (24_866_000 as Weight)360 (24_936_000 as Weight)329 .saturating_add(RocksDbWeight::get().reads(4 as Weight))361 .saturating_add(RocksDbWeight::get().reads(4 as Weight))330 .saturating_add(RocksDbWeight::get().writes(6 as Weight))362 .saturating_add(RocksDbWeight::get().writes(6 as Weight))331 }363 }332 // Storage: Refungible Balance (r:1 w:0)364 // Storage: Refungible Balance (r:1 w:0)333 // Storage: Refungible Allowance (r:0 w:1)365 // Storage: Refungible Allowance (r:0 w:1)334 fn approve() -> Weight {366 fn approve() -> Weight {335 (13_475_000 as Weight)367 (13_446_000 as Weight)336 .saturating_add(RocksDbWeight::get().reads(1 as Weight))368 .saturating_add(RocksDbWeight::get().reads(1 as Weight))337 .saturating_add(RocksDbWeight::get().writes(1 as Weight))369 .saturating_add(RocksDbWeight::get().writes(1 as Weight))338 }370 }339 // Storage: Refungible Allowance (r:1 w:1)371 // Storage: Refungible Allowance (r:1 w:1)340 // Storage: Refungible Balance (r:2 w:2)372 // Storage: Refungible Balance (r:2 w:2)341 fn transfer_from_normal() -> Weight {373 fn transfer_from_normal() -> Weight {342 (24_707_000 as Weight)374 (24_777_000 as Weight)343 .saturating_add(RocksDbWeight::get().reads(3 as Weight))375 .saturating_add(RocksDbWeight::get().reads(3 as Weight))344 .saturating_add(RocksDbWeight::get().writes(3 as Weight))376 .saturating_add(RocksDbWeight::get().writes(3 as Weight))345 }377 }348 // Storage: Refungible AccountBalance (r:1 w:1)380 // Storage: Refungible AccountBalance (r:1 w:1)349 // Storage: Refungible Owned (r:0 w:1)381 // Storage: Refungible Owned (r:0 w:1)350 fn transfer_from_creating() -> Weight {382 fn transfer_from_creating() -> Weight {351 (27_812_000 as Weight)383 (28_483_000 as Weight)352 .saturating_add(RocksDbWeight::get().reads(4 as Weight))384 .saturating_add(RocksDbWeight::get().reads(4 as Weight))353 .saturating_add(RocksDbWeight::get().writes(5 as Weight))385 .saturating_add(RocksDbWeight::get().writes(5 as Weight))354 }386 }357 // Storage: Refungible AccountBalance (r:1 w:1)389 // Storage: Refungible AccountBalance (r:1 w:1)358 // Storage: Refungible Owned (r:0 w:1)390 // Storage: Refungible Owned (r:0 w:1)359 fn transfer_from_removing() -> Weight {391 fn transfer_from_removing() -> Weight {360 (29_966_000 as Weight)392 (29_896_000 as Weight)361 .saturating_add(RocksDbWeight::get().reads(4 as Weight))393 .saturating_add(RocksDbWeight::get().reads(4 as Weight))362 .saturating_add(RocksDbWeight::get().writes(5 as Weight))394 .saturating_add(RocksDbWeight::get().writes(5 as Weight))363 }395 }366 // Storage: Refungible AccountBalance (r:2 w:2)398 // Storage: Refungible AccountBalance (r:2 w:2)367 // Storage: Refungible Owned (r:0 w:2)399 // Storage: Refungible Owned (r:0 w:2)368 fn transfer_from_creating_removing() -> Weight {400 fn transfer_from_creating_removing() -> Weight {369 (31_660_000 as Weight)401 (32_070_000 as Weight)370 .saturating_add(RocksDbWeight::get().reads(5 as Weight))402 .saturating_add(RocksDbWeight::get().reads(5 as Weight))371 .saturating_add(RocksDbWeight::get().writes(7 as Weight))403 .saturating_add(RocksDbWeight::get().writes(7 as Weight))372 }404 }377 // Storage: Refungible TokensBurnt (r:1 w:1)409 // Storage: Refungible TokensBurnt (r:1 w:1)378 // Storage: Refungible TokenData (r:0 w:1)410 // Storage: Refungible TokenData (r:0 w:1)379 // Storage: Refungible Owned (r:0 w:1)411 // Storage: Refungible Owned (r:0 w:1)412 // Storage: Refungible TokenProperties (r:0 w:1)380 fn burn_from() -> Weight {413 fn burn_from() -> Weight {381 (36_248_000 as Weight)414 (36_789_000 as Weight)382 .saturating_add(RocksDbWeight::get().reads(5 as Weight))415 .saturating_add(RocksDbWeight::get().reads(5 as Weight))383 .saturating_add(RocksDbWeight::get().writes(7 as Weight))416 .saturating_add(RocksDbWeight::get().writes(8 as Weight))417 }418 // Storage: Common CollectionPropertyPermissions (r:1 w:1)419 fn set_token_property_permissions(b: u32, ) -> Weight {420 (0 as Weight)421 // Standard Error: 62_000422 .saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))423 .saturating_add(RocksDbWeight::get().reads(1 as Weight))424 .saturating_add(RocksDbWeight::get().writes(1 as Weight))425 }426 // Storage: Common CollectionPropertyPermissions (r:1 w:0)427 // Storage: Refungible TokenProperties (r:1 w:1)428 fn set_token_properties(b: u32, ) -> Weight {429 (0 as Weight)430 // Standard Error: 1_668_000431 .saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))432 .saturating_add(RocksDbWeight::get().reads(2 as Weight))433 .saturating_add(RocksDbWeight::get().writes(1 as Weight))434 }435 // Storage: Common CollectionPropertyPermissions (r:1 w:0)436 // Storage: Refungible TokenProperties (r:1 w:1)437 fn delete_token_properties(b: u32, ) -> Weight {438 (0 as Weight)439 // Standard Error: 1_619_000440 .saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))441 .saturating_add(RocksDbWeight::get().reads(2 as Weight))442 .saturating_add(RocksDbWeight::get().writes(1 as Weight))384 }443 }385 // Storage: Refungible TotalSupply (r:1 w:1)444 // Storage: Refungible TotalSupply (r:1 w:1)386 // Storage: Refungible Balance (r:1 w:1)445 // Storage: Refungible Balance (r:1 w:1)387 fn repartition_item() -> Weight {446 fn repartition_item() -> Weight {388 (8_226_000 as Weight)447 (8_325_000 as Weight)389 .saturating_add(RocksDbWeight::get().reads(2 as Weight))448 .saturating_add(RocksDbWeight::get().reads(2 as Weight))390 .saturating_add(RocksDbWeight::get().writes(2 as Weight))449 .saturating_add(RocksDbWeight::get().writes(2 as Weight))391 }450 }primitives/data-structs/Cargo.tomldiffbeforeafterboth6license = 'GPLv3'6license = 'GPLv3'7homepage = "https://unique.network"7homepage = "https://unique.network"8repository = 'https://github.com/UniqueNetwork/unique-chain'8repository = 'https://github.com/UniqueNetwork/unique-chain'9version = '0.1.0'9version = '0.1.1'101011[dependencies]11[dependencies]12scale-info = { version = "2.0.1", default-features = false, features = [12scale-info = { version = "2.0.1", default-features = false, features = [primitives/data-structs/Changelog.mddiffbeforeafterbothno changes
primitives/data-structs/src/lib.rsdiffbeforeafterboth537537 pub pieces: u128,538 pub pieces: u128,539540 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]541 #[derivative(Debug(format_with = "bounded::vec_debug"))]542 pub properties: CollectionPropertiesVec,538}543}539544540#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]545#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]568 pub const_data: BoundedVec<u8, CustomDataLimit>,573 pub const_data: BoundedVec<u8, CustomDataLimit>,569 #[derivative(Debug(format_with = "bounded::map_debug"))]574 #[derivative(Debug(format_with = "bounded::map_debug"))]570 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,575 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,576 #[derivative(Debug(format_with = "bounded::vec_debug"))]577 pub properties: CollectionPropertiesVec,571}578}572579573#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]580#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]tests/src/createMultipleItems.test.tsdiffbeforeafterboth376 // ReFungible376 // ReFungible377 const collectionIdReFungible =377 const collectionIdReFungible =378 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});378 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});379 {379 const argsReFungible = [380 const argsReFungible = [380 {ReFungible: ['1'.repeat(2049), 10]},381 {ReFungible: ['1'.repeat(2049), 10, []]},381 {ReFungible: ['2'.repeat(2049), 10]},382 {ReFungible: ['2'.repeat(2049), 10, []]},382 {ReFungible: ['3'.repeat(2049), 10]},383 {ReFungible: ['3'.repeat(2049), 10, []]},383 ];384 ];384 const createMultipleItemsTxFungible = api.tx.unique385 const createMultipleItemsTxFungible = api.tx.unique385 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);386 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);386 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;387 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;388 }389 {390 const argsReFungible = [391 {ReFungible: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}},392 {ReFungible: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}},393 {ReFungible: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}},394 ];395 const createMultipleItemsTxFungible = api.tx.unique396 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);397 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;398 }387 });399 });388 });400 });389401tests/src/interfaces/augment-api-query.tsdiffbeforeafterboth408 **/408 **/409 owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;409 owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;410 tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;410 tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;411 tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;411 tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;412 tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;412 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;413 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;413 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;414 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;tests/src/interfaces/default/types.tsdiffbeforeafterboth2461export interface UpDataStructsCreateReFungibleData extends Struct {2461export interface UpDataStructsCreateReFungibleData extends Struct {2462 readonly constData: Bytes;2462 readonly constData: Bytes;2463 readonly pieces: u128;2463 readonly pieces: u128;2464 readonly properties: Vec<UpDataStructsProperty>;2464}2465}246524662466/** @name UpDataStructsCreateRefungibleExData */2467/** @name UpDataStructsCreateRefungibleExData */2467export interface UpDataStructsCreateRefungibleExData extends Struct {2468export interface UpDataStructsCreateRefungibleExData extends Struct {2468 readonly constData: Bytes;2469 readonly constData: Bytes;2469 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;2470 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;2471 readonly properties: Vec<UpDataStructsProperty>;2470}2472}247124732472/** @name UpDataStructsNestingPermissions */2474/** @name UpDataStructsNestingPermissions */tests/src/interfaces/lookup.tsdiffbeforeafterboth1502 **/1502 **/1503 UpDataStructsCreateReFungibleData: {1503 UpDataStructsCreateReFungibleData: {1504 constData: 'Bytes',1504 constData: 'Bytes',1505 pieces: 'u128'1505 pieces: 'u128',1506 properties: 'Vec<UpDataStructsProperty>'1506 },1507 },1507 /**1508 /**1508 * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1509 * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1527 **/1528 **/1528 UpDataStructsCreateRefungibleExData: {1529 UpDataStructsCreateRefungibleExData: {1529 constData: 'Bytes',1530 constData: 'Bytes',1530 users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>'1531 users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',1532 properties: 'Vec<UpDataStructsProperty>'1531 },1533 },1532 /**1534 /**1533 * Lookup204: pallet_unique_scheduler::pallet::Call<T>1535 * Lookup204: pallet_unique_scheduler::pallet::Call<T>tests/src/interfaces/types-lookup.tsdiffbeforeafterboth1629 export interface UpDataStructsCreateReFungibleData extends Struct {1629 export interface UpDataStructsCreateReFungibleData extends Struct {1630 readonly constData: Bytes;1630 readonly constData: Bytes;1631 readonly pieces: u128;1631 readonly pieces: u128;1632 readonly properties: Vec<UpDataStructsProperty>;1632 }1633 }163316341634 /** @name UpDataStructsCreateItemExData (193) */1635 /** @name UpDataStructsCreateItemExData (193) */1654 export interface UpDataStructsCreateRefungibleExData extends Struct {1655 export interface UpDataStructsCreateRefungibleExData extends Struct {1655 readonly constData: Bytes;1656 readonly constData: Bytes;1656 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;1657 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;1658 readonly properties: Vec<UpDataStructsProperty>;1657 }1659 }165816601659 /** @name PalletUniqueSchedulerCall (204) */1661 /** @name PalletUniqueSchedulerCall (204) */tests/src/nesting/properties.test.tsdiffbeforeafterboth2import usingApi, {executeTransaction} from '../substrate/substrate-api';2import usingApi, {executeTransaction} from '../substrate/substrate-api';3import {3import {4 addCollectionAdminExpectSuccess,4 addCollectionAdminExpectSuccess,5 CollectionMode,5 createCollectionExpectSuccess,6 createCollectionExpectSuccess,6 setCollectionPermissionsExpectSuccess,7 setCollectionPermissionsExpectSuccess,7 createItemExpectSuccess,8 createItemExpectSuccess,23 });24 });24 });25 });252626 it('Makes sure collectionById supplies required fields', async () => {27 async function testMakeSureSuppliesRequired(mode: CollectionMode) {27 await usingApi(async api => {28 await usingApi(async api => {28 const collectionId = await createCollectionExpectSuccess();29 const collectionId = await createCollectionExpectSuccess({mode: mode});293030 const collectionOption = await api.rpc.unique.collectionById(collectionId);31 const collectionOption = await api.rpc.unique.collectionById(collectionId);31 expect(collectionOption.isSome).to.be.true;32 expect(collectionOption.isSome).to.be.true;57 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);58 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);58 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);59 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);59 });60 });61 }6263 it('Makes sure collectionById supplies required fields for NFT', async () => {64 await testMakeSureSuppliesRequired({type: 'NFT'});60 });65 });6667 it('Makes sure collectionById supplies required fields for ReFungible', async () => {68 await testMakeSureSuppliesRequired({type: 'ReFungible'});69 });61});70});627163// ---------- COLLECTION PROPERTIES72// ---------- COLLECTION PROPERTIES79 });88 });80 });89 });81909182 it('Sets properties for a collection', async () => {92 async function testSetsPropertiesForCollection(mode: string) {83 await usingApi(async api => {93 await usingApi(async api => {84 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));94 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));85 const {collectionId} = getCreateCollectionResult(events);95 const {collectionId} = getCreateCollectionResult(events);869687 // As owner97 // As owner106 {key: 'black_hole', value: ''},116 {key: 'black_hole', value: ''},107 ]);117 ]);108 });118 });119 }120 it('Sets properties for a NFT collection', async () => {121 await testSetsPropertiesForCollection('NFT');109 });122 });123 it('Sets properties for a ReFungible collection', async () => {124 await testSetsPropertiesForCollection('ReFungible');125 });110126111 it('Check valid names for collection properties keys', async () => {127 async function testCheckValidNames(mode: string) {112 await usingApi(async api => {128 await usingApi(async api => {113 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));129 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));114 const {collectionId} = getCreateCollectionResult(events);130 const {collectionId} = getCreateCollectionResult(events);115131 116 // alpha symbols132 // alpha symbols117 await expect(executeTransaction(133 await expect(executeTransaction(118 api, 134 api, 119 bob, 135 bob, 120 api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 136 api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 121 )).to.not.be.rejected;137 )).to.not.be.rejected;122138 123 // numeric symbols139 // numeric symbols124 await expect(executeTransaction(140 await expect(executeTransaction(125 api, 141 api, 126 bob, 142 bob, 127 api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 143 api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 128 )).to.not.be.rejected;144 )).to.not.be.rejected;129145 130 // underscore symbol146 // underscore symbol131 await expect(executeTransaction(147 await expect(executeTransaction(132 api, 148 api, 133 bob, 149 bob, 134 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 150 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 135 )).to.not.be.rejected;151 )).to.not.be.rejected;136152 137 // dash symbol153 // dash symbol138 await expect(executeTransaction(154 await expect(executeTransaction(139 api, 155 api, 140 bob, 156 bob, 141 api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 157 api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 142 )).to.not.be.rejected;158 )).to.not.be.rejected;143159 144 // underscore symbol160 // underscore symbol145 await expect(executeTransaction(161 await expect(executeTransaction(146 api, 162 api, 147 bob, 163 bob, 148 api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 164 api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 149 )).to.not.be.rejected;165 )).to.not.be.rejected;150166 151 const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];167 const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];152 const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();168 const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();153 expect(properties).to.be.deep.equal([169 expect(properties).to.be.deep.equal([158 {key: 'build.rs', value: ''},174 {key: 'build.rs', value: ''},159 ]);175 ]);160 });176 });177 }178 it('Check valid names for NFT collection properties keys', async () => {179 await testCheckValidNames('NFT');161 });180 });181 it('Check valid names for ReFungible collection properties keys', async () => {182 await testCheckValidNames('ReFungible');183 });162184163 it('Changes properties of a collection', async () => {185 async function testChangesProperties(mode: CollectionMode) {164 await usingApi(async api => {186 await usingApi(async api => {165 const collection = await createCollectionExpectSuccess();187 const collection = await createCollectionExpectSuccess({mode: mode});166188 167 await expect(executeTransaction(189 await expect(executeTransaction(168 api, 190 api, 169 alice, 191 alice, 170 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 192 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 171 )).to.not.be.rejected;193 )).to.not.be.rejected;172194 173 // Mutate the properties195 // Mutate the properties174 await expect(executeTransaction(196 await expect(executeTransaction(175 api, 197 api, 176 alice, 198 alice, 177 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 199 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 178 )).to.not.be.rejected;200 )).to.not.be.rejected;179201 180 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();202 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();181 expect(properties).to.be.deep.equal([203 expect(properties).to.be.deep.equal([182 {key: 'electron', value: 'bonded'},204 {key: 'electron', value: 'bonded'},183 {key: 'black_hole', value: 'LIGO'},205 {key: 'black_hole', value: 'LIGO'},184 ]);206 ]);185 });207 });208 }209 it('Changes properties of a NFT collection', async () => {210 await testChangesProperties({type: 'NFT'});186 });211 });212 it('Changes properties of a ReFungible collection', async () => {213 await testChangesProperties({type: 'ReFungible'});214 });187215188 it('Deletes properties of a collection', async () => {216 async function testDeleteProperties(mode: CollectionMode) {189 await usingApi(async api => {217 await usingApi(async api => {190 const collection = await createCollectionExpectSuccess();218 const collection = await createCollectionExpectSuccess({mode: mode});191219 192 await expect(executeTransaction(220 await expect(executeTransaction(193 api, 221 api, 194 alice, 222 alice, 195 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 223 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 196 )).to.not.be.rejected;224 )).to.not.be.rejected;197225 198 await expect(executeTransaction(226 await expect(executeTransaction(199 api, 227 api, 200 alice, 228 alice, 201 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 229 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 202 )).to.not.be.rejected;230 )).to.not.be.rejected;203231 204 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();232 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();205 expect(properties).to.be.deep.equal([233 expect(properties).to.be.deep.equal([206 {key: 'black_hole', value: 'LIGO'},234 {key: 'black_hole', value: 'LIGO'},207 ]);235 ]);208 });236 }); 237 }238 it('Deletes properties of a NFT collection', async () => {239 await testDeleteProperties({type: 'NFT'});209 });240 });241 it('Deletes properties of a ReFungible collection', async () => {242 await testDeleteProperties({type: 'ReFungible'});243 });210});244});211245212describe('Negative Integration Test: Collection Properties', () => {246describe('Negative Integration Test: Collection Properties', () => {217 });251 });218 });252 });219 253 220 it('Fails to set properties in a collection if not its onwer/administrator', async () => {254 async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {221 await usingApi(async api => {255 await usingApi(async api => {222 const collection = await createCollectionExpectSuccess();256 const collection = await createCollectionExpectSuccess({mode: mode});223257 224 await expect(executeTransaction(258 await expect(executeTransaction(225 api, 259 api, 226 bob, 260 bob, 230 const properties = (await api.query.common.collectionProperties(collection)).toJSON();264 const properties = (await api.query.common.collectionProperties(collection)).toJSON();231 expect(properties.map).to.be.empty;265 expect(properties.map).to.be.empty;232 expect(properties.consumedSpace).to.equal(0);266 expect(properties.consumedSpace).to.equal(0);233 });267 }); 268 }269 it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {270 await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});234 });271 });272 it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {273 await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});274 });235 275 236 it('Fails to set properties that exceed the limits', async () => {276 async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {237 await usingApi(async api => {277 await usingApi(async api => {238 const collection = await createCollectionExpectSuccess();278 const collection = await createCollectionExpectSuccess({mode: mode});239 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 279 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 240280 241 // Mute the general tx parsing error, too many bytes to process281 // Mute the general tx parsing error, too many bytes to process242 {282 {243 console.error = () => {};283 console.error = () => {};247 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 287 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 248 )).to.be.rejected;288 )).to.be.rejected;249 }289 }250290 251 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();291 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();252 expect(properties).to.be.empty;292 expect(properties).to.be.empty;253293 254 await expect(executeTransaction(294 await expect(executeTransaction(255 api, 295 api, 256 alice, 296 alice, 259 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 299 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 260 ]), 300 ]), 261 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);301 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);262302 263 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();303 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();264 expect(properties).to.be.empty;304 expect(properties).to.be.empty;265 });305 }); 306 }307 it('Fails to set properties that exceed the limits (NFT)', async () => {308 await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});266 });309 });310 it('Fails to set properties that exceed the limits (ReFungible)', async () => {311 await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});312 });267 313 268 it('Fails to set more properties than it is allowed', async () => {314 async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {269 await usingApi(async api => {315 await usingApi(async api => {270 const collection = await createCollectionExpectSuccess();316 const collection = await createCollectionExpectSuccess({mode: mode});271317 272 const propertiesToBeSet = [];318 const propertiesToBeSet = [];273 for (let i = 0; i < 65; i++) {319 for (let i = 0; i < 65; i++) {274 propertiesToBeSet.push({320 propertiesToBeSet.push({275 key: 'electron_' + i,321 key: 'electron_' + i,276 value: Math.random() > 0.5 ? 'high' : 'low',322 value: Math.random() > 0.5 ? 'high' : 'low',277 });323 });278 }324 }279325 280 await expect(executeTransaction(326 await expect(executeTransaction(281 api, 327 api, 282 alice, 328 alice, 283 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 329 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 284 )).to.be.rejectedWith(/common\.PropertyLimitReached/);330 )).to.be.rejectedWith(/common\.PropertyLimitReached/);285331 286 const properties = (await api.query.common.collectionProperties(collection)).toJSON();332 const properties = (await api.query.common.collectionProperties(collection)).toJSON();287 expect(properties.map).to.be.empty;333 expect(properties.map).to.be.empty;288 expect(properties.consumedSpace).to.equal(0);334 expect(properties.consumedSpace).to.equal(0);289 });335 }); 336 }337 it('Fails to set more properties than it is allowed (NFT)', async () => {338 await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});290 });339 });291292 it('Fails to set properties with invalid names', async () => {340 it('Fails to set more properties than it is allowed (ReFungible)', async () => {341 await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});342 });343 344 async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {293 await usingApi(async api => {345 await usingApi(async api => {294 const collection = await createCollectionExpectSuccess();346 const collection = await createCollectionExpectSuccess({mode: mode});295347 296 const invalidProperties = [348 const invalidProperties = [297 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],349 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],298 [{key: 'Mr/Sandman', value: 'Bring me a gene'}],350 [{key: 'Mr/Sandman', value: 'Bring me a gene'}],299 [{key: 'déjà vu', value: 'hmm...'}],351 [{key: 'déjà vu', value: 'hmm...'}],300 ];352 ];301353 302 for (let i = 0; i < invalidProperties.length; i++) {354 for (let i = 0; i < invalidProperties.length; i++) {303 await expect(executeTransaction(355 await expect(executeTransaction(304 api, 356 api, 305 alice, 357 alice, 306 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 358 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 307 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);359 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);308 }360 }309361 310 await expect(executeTransaction(362 await expect(executeTransaction(311 api, 363 api, 312 alice, 364 alice, 313 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 365 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 314 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);366 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);315367 316 await expect(executeTransaction(368 await expect(executeTransaction(317 api, 369 api, 318 alice, 370 alice, 319 api.tx.unique.setCollectionProperties(collection, [371 api.tx.unique.setCollectionProperties(collection, [320 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},372 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},321 ]), 373 ]), 322 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;374 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;323375 324 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');376 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');325377 326 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();378 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();327 expect(properties).to.be.deep.equal([379 expect(properties).to.be.deep.equal([328 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},380 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},329 ]);381 ]);330382 331 for (let i = 0; i < invalidProperties.length; i++) {383 for (let i = 0; i < invalidProperties.length; i++) {332 await expect(executeTransaction(384 await expect(executeTransaction(333 api, 385 api, 336 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);388 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);337 }389 }338 });390 });391 }392 it('Fails to set properties with invalid names (NFT)', async () => {393 await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});339 });394 });395 it('Fails to set properties with invalid names (ReFungible)', async () => {396 await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});397 });340});398});341399342// ---------- ACCESS RIGHTS400// ---------- ACCESS RIGHTS357 });415 });358 });416 });359 417 360 it('Sets access rights to properties of a collection', async () => {418 async function testSetsAccessRightsToProperties(mode: CollectionMode) {361 await usingApi(async api => {419 await usingApi(async api => {362 const collection = await createCollectionExpectSuccess();420 const collection = await createCollectionExpectSuccess({mode: mode});363421 364 await expect(executeTransaction(422 await expect(executeTransaction(365 api, 423 api, 366 alice, 424 alice, 367 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 425 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 368 )).to.not.be.rejected;426 )).to.not.be.rejected;369427 370 await addCollectionAdminExpectSuccess(alice, collection, bob.address);428 await addCollectionAdminExpectSuccess(alice, collection, bob.address);371429 372 await expect(executeTransaction(430 await expect(executeTransaction(373 api, 431 api, 374 alice, 432 alice, 375 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 433 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 376 )).to.not.be.rejected;434 )).to.not.be.rejected;377435 378 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();436 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();379 expect(propertyRights).to.be.deep.equal([437 expect(propertyRights).to.be.deep.equal([380 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},438 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},381 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},439 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},382 ]);440 ]);383 });441 }); 442 }443 it('Sets access rights to properties of a collection (NFT)', async () => {444 await testSetsAccessRightsToProperties({type: 'NFT'});384 });445 });446 it('Sets access rights to properties of a collection (ReFungible)', async () => {447 await testSetsAccessRightsToProperties({type: 'ReFungible'});448 });385 449 386 it('Changes access rights to properties of a collection', async () => {450 async function testChangesAccessRightsToProperty(mode: CollectionMode) {387 await usingApi(async api => {451 await usingApi(async api => {388 const collection = await createCollectionExpectSuccess();452 const collection = await createCollectionExpectSuccess({mode: mode});389453 390 await expect(executeTransaction(454 await expect(executeTransaction(391 api, 455 api, 392 alice, 456 alice, 393 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 457 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 394 )).to.not.be.rejected;458 )).to.not.be.rejected;395459 396 await expect(executeTransaction(460 await expect(executeTransaction(397 api, 461 api, 398 alice, 462 alice, 399 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 463 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 400 )).to.not.be.rejected;464 )).to.not.be.rejected;401465 402 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();466 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();403 expect(propertyRights).to.be.deep.equal([467 expect(propertyRights).to.be.deep.equal([404 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},468 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},405 ]);469 ]);406 });470 });471 }472 it('Changes access rights to properties of a NFT collection', async () => {473 await testChangesAccessRightsToProperty({type: 'NFT'});407 });474 });475 it('Changes access rights to properties of a ReFungible collection', async () => {476 await testChangesAccessRightsToProperty({type: 'ReFungible'});477 });408});478});409479410describe('Negative Integration Test: Access Rights to Token Properties', () => {480describe('Negative Integration Test: Access Rights to Token Properties', () => {415 });485 });416 });486 });417487418 it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {488 async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {419 await usingApi(async api => {489 await usingApi(async api => {420 const collection = await createCollectionExpectSuccess();490 const collection = await createCollectionExpectSuccess({mode: mode});421491 422 await expect(executeTransaction(492 await expect(executeTransaction(423 api, 493 api, 424 bob, 494 bob, 425 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 495 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 426 )).to.be.rejectedWith(/common\.NoPermission/);496 )).to.be.rejectedWith(/common\.NoPermission/);427497 428 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();498 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();429 expect(propertyRights).to.be.empty;499 expect(propertyRights).to.be.empty;430 });500 });501 }502 it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {503 await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});431 });504 });505 it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {506 await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});507 });432508433 it('Prevents from adding too many possible properties', async () => {509 async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {434 await usingApi(async api => {510 await usingApi(async api => {435 const collection = await createCollectionExpectSuccess();511 const collection = await createCollectionExpectSuccess({mode: mode});436512 437 const constitution = [];513 const constitution = [];438 for (let i = 0; i < 65; i++) {514 for (let i = 0; i < 65; i++) {439 constitution.push({515 constitution.push({440 key: 'property_' + i,516 key: 'property_' + i,441 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},517 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},442 });518 });443 }519 }444520 445 await expect(executeTransaction(521 await expect(executeTransaction(446 api, 522 api, 447 alice, 523 alice, 448 api.tx.unique.setTokenPropertyPermissions(collection, constitution), 524 api.tx.unique.setTokenPropertyPermissions(collection, constitution), 449 )).to.be.rejectedWith(/common\.PropertyLimitReached/);525 )).to.be.rejectedWith(/common\.PropertyLimitReached/);450526 451 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();527 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();452 expect(propertyRights).to.be.empty;528 expect(propertyRights).to.be.empty;453 });529 }); 530 }531 it('Prevents from adding too many possible properties (NFT)', async () => {532 await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});454 });533 });534 it('Prevents from adding too many possible properties (ReFungible)', async () => {535 await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});536 });455537456 it('Prevents access rights to be modified if constant', async () => {538 async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {457 await usingApi(async api => {539 await usingApi(async api => {458 const collection = await createCollectionExpectSuccess();540 const collection = await createCollectionExpectSuccess({mode: mode});459541 460 await expect(executeTransaction(542 await expect(executeTransaction(461 api, 543 api, 462 alice, 544 alice, 463 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 545 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 464 )).to.not.be.rejected;546 )).to.not.be.rejected;465547 466 await expect(executeTransaction(548 await expect(executeTransaction(467 api, 549 api, 468 alice, 550 alice, 469 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 551 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 470 )).to.be.rejectedWith(/common\.NoPermission/);552 )).to.be.rejectedWith(/common\.NoPermission/);471553 472 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();554 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();473 expect(propertyRights).to.deep.equal([555 expect(propertyRights).to.deep.equal([474 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},556 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},475 ]);557 ]);476 });558 }); 559 }560 it('Prevents access rights to be modified if constant (NFT)', async () => {561 await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});477 });562 });563 it('Prevents access rights to be modified if constant (ReFungible)', async () => {564 await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});565 });478566479 it('Prevents adding properties with invalid names', async () => {567 async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {480 await usingApi(async api => {568 await usingApi(async api => {481 const collection = await createCollectionExpectSuccess();569 const collection = await createCollectionExpectSuccess({mode: mode});482570 483 const invalidProperties = [571 const invalidProperties = [484 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],572 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],485 [{key: 'G#4', permission: {tokenOwner: true}}],573 [{key: 'G#4', permission: {tokenOwner: true}}],486 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],574 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],487 ];575 ];488576 489 for (let i = 0; i < invalidProperties.length; i++) {577 for (let i = 0; i < invalidProperties.length; i++) {490 await expect(executeTransaction(578 await expect(executeTransaction(491 api, 579 api, 492 alice, 580 alice, 493 api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 581 api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 494 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);582 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);495 }583 }496584 497 await expect(executeTransaction(585 await expect(executeTransaction(498 api, 586 api, 499 alice, 587 alice, 500 api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 588 api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 501 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);589 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);502590 503 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string591 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string504 await expect(executeTransaction(592 await expect(executeTransaction(505 api, 593 api, 508 {key: correctKey, permission: {collectionAdmin: true}},596 {key: correctKey, permission: {collectionAdmin: true}},509 ]), 597 ]), 510 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;598 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;511599 512 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');600 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');513601 514 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();602 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();515 expect(propertyRights).to.be.deep.equal([603 expect(propertyRights).to.be.deep.equal([516 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},604 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},517 ]);605 ]);518 });606 });607 }608 it('Prevents adding properties with invalid names (NFT)', async () => {609 await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});519 });610 });611 it('Prevents adding properties with invalid names (ReFungible)', async () => {612 await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});613 });520});614});521615522// ---------- TOKEN PROPERTIES616// ---------- TOKEN PROPERTIES523617524describe('Integration Test: Token Properties', () => {618describe('Integration Test: Token Properties', () => {525 let collection: number;526 let token: number;527 let nestedToken: number;528 let permissions: {permission: any, signers: IKeyringPair[]}[];619 let permissions: {permission: any, signers: IKeyringPair[]}[];529620530 before(async () => {621 before(async () => {531 await usingApi(async (api, privateKeyWrapper) => {622 await usingApi(async (api, privateKeyWrapper) => {532 alice = privateKeyWrapper('//Alice');623 alice = privateKeyWrapper('//Alice'); // collection owner533 bob = privateKeyWrapper('//Bob');624 bob = privateKeyWrapper('//Bob'); // collection admin534 charlie = privateKeyWrapper('//Charlie');625 charlie = privateKeyWrapper('//Charlie'); // token owner535626536 permissions = [627 permissions = [537 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},628 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},543 ];634 ];544 });635 });545 });636 });546547 beforeEach(async () => {548 await usingApi(async () => {549 collection = await createCollectionExpectSuccess();550 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});551552 token = await createItemExpectSuccess(alice, collection, 'NFT');553 nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});554555 await addCollectionAdminExpectSuccess(alice, collection, bob.address);556 await transferExpectSuccess(collection, token, alice, charlie);557 });558 });559 637 560 it('Reads yet empty properties of a token', async () => {638 async function testReadsYetEmptyProperties(mode: CollectionMode) {561 await usingApi(async api => {639 await usingApi(async api => {562 const collection = await createCollectionExpectSuccess();640 const collection = await createCollectionExpectSuccess({mode: mode});563 const token = await createItemExpectSuccess(alice, collection, 'NFT');641 const token = await createItemExpectSuccess(alice, collection, mode.type);564 642 565 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();643 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();566 expect(properties.map).to.be.empty;644 expect(properties.map).to.be.empty;567 expect(properties.consumedSpace).to.be.equal(0);645 expect(properties.consumedSpace).to.be.equal(0);568646 569 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;647 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;570 expect(tokenData).to.be.empty;648 expect(tokenData).to.be.empty;571 });649 });650 }651 it('Reads yet empty properties of a token (NFT)', async () => {652 await testReadsYetEmptyProperties({type: 'NFT'});572 });653 });654 it('Reads yet empty properties of a token (ReFungible)', async () => {655 await testReadsYetEmptyProperties({type: 'ReFungible'});656 });573657574 it('Assigns properties to a token according to permissions', async () => {658 async function testAssignPropertiesAccordingToPermissions(mode: CollectionMode, pieces: number) {575 await usingApi(async api => {659 await usingApi(async api => {660 const collection = await createCollectionExpectSuccess({mode: mode});661 const token = await createItemExpectSuccess(alice, collection, mode.type);662 await addCollectionAdminExpectSuccess(alice, collection, bob.address);663 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);664576 const propertyKeys: string[] = [];665 const propertyKeys: string[] = [];577 let i = 0;666 let i = 0;578 for (const permission of permissions) {667 for (const permission of permissions) {603 expect(tokensData[i].value).to.be.equal('Serotonin increase');692 expect(tokensData[i].value).to.be.equal('Serotonin increase');604 }693 }605 });694 });695 }696 it('Assigns properties to a token according to permissions (NFT)', async () => {697 await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);606 });698 });699 it('Assigns properties to a token according to permissions (ReFungible)', async () => {700 await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);701 });607702608 it('Changes properties of a token according to permissions', async () => {703 async function testChangesPropertiesAccordingPermission(mode: CollectionMode, pieces: number) {609 await usingApi(async api => {704 await usingApi(async api => {705 const collection = await createCollectionExpectSuccess({mode: mode});706 const token = await createItemExpectSuccess(alice, collection, mode.type);707 await addCollectionAdminExpectSuccess(alice, collection, bob.address);708 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);709610 const propertyKeys: string[] = [];710 const propertyKeys: string[] = [];611 let i = 0;711 let i = 0;612 for (const permission of permissions) {712 for (const permission of permissions) {615 for (const signer of permission.signers) {715 for (const signer of permission.signers) {616 const key = i + '_' + signer.address;716 const key = i + '_' + signer.address;617 propertyKeys.push(key);717 propertyKeys.push(key);618718 619 await expect(executeTransaction(719 await expect(executeTransaction(620 api, 720 api, 621 alice, 721 alice, 622 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 722 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 623 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;723 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;624724 625 await expect(executeTransaction(725 await expect(executeTransaction(626 api, 726 api, 627 signer, 727 signer, 628 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 728 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 629 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;729 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;630730 631 await expect(executeTransaction(731 await expect(executeTransaction(632 api, 732 api, 633 signer, 733 signer, 634 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 734 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 635 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;735 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;636 }736 }637737 638 i++;738 i++;639 }739 }640740 641 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];741 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];642 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];742 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];643 for (let i = 0; i < properties.length; i++) {743 for (let i = 0; i < properties.length; i++) {644 expect(properties[i].value).to.be.equal('Serotonin stable');744 expect(properties[i].value).to.be.equal('Serotonin stable');645 expect(tokensData[i].value).to.be.equal('Serotonin stable');745 expect(tokensData[i].value).to.be.equal('Serotonin stable');646 }746 }647 });747 });748 }749 it('Changes properties of a token according to permissions (NFT)', async () => {750 await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);648 });751 });752 it('Changes properties of a token according to permissions (ReFungible)', async () => {753 await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);754 });649755650 it('Deletes properties of a token according to permissions', async () => {756 async function testDeletePropertiesAccordingPermission(mode: CollectionMode, pieces: number) {651 await usingApi(async api => {757 await usingApi(async api => {758 const collection = await createCollectionExpectSuccess({mode: mode});759 const token = await createItemExpectSuccess(alice, collection, mode.type);760 await addCollectionAdminExpectSuccess(alice, collection, bob.address);761 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);762652 const propertyKeys: string[] = [];763 const propertyKeys: string[] = [];653 let i = 0;764 let i = 0;654765 655 for (const permission of permissions) {766 for (const permission of permissions) {656 if (!permission.permission.mutable) continue;767 if (!permission.permission.mutable) continue;657 768 658 for (const signer of permission.signers) {769 for (const signer of permission.signers) {659 const key = i + '_' + signer.address;770 const key = i + '_' + signer.address;660 propertyKeys.push(key);771 propertyKeys.push(key);661772 662 await expect(executeTransaction(773 await expect(executeTransaction(663 api, 774 api, 664 alice, 775 alice, 665 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 776 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 666 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;777 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;667778 668 await expect(executeTransaction(779 await expect(executeTransaction(669 api, 780 api, 670 signer, 781 signer, 671 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 782 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 672 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;783 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;673784 674 await expect(executeTransaction(785 await expect(executeTransaction(675 api, 786 api, 676 signer, 787 signer, 680 791 681 i++;792 i++;682 }793 }683794 684 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];795 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];685 expect(properties).to.be.empty;796 expect(properties).to.be.empty;686 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];797 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];687 expect(tokensData).to.be.empty;798 expect(tokensData).to.be.empty;688 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);799 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);689 });800 });801 }802 it('Deletes properties of a token according to permissions (NFT)', async () => {803 await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);690 });804 });805 it('Deletes properties of a token according to permissions (ReFungible)', async () => {806 await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);807 });691808692 it('Assigns properties to a nested token according to permissions', async () => {809 it('Assigns properties to a nested token according to permissions', async () => {693 await usingApi(async api => {810 await usingApi(async api => {811 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});812 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});813 const token = await createItemExpectSuccess(alice, collection, 'NFT');814 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});815 await addCollectionAdminExpectSuccess(alice, collection, bob.address);816 await transferExpectSuccess(collection, token, alice, charlie);817694 const propertyKeys: string[] = [];818 const propertyKeys: string[] = [];695 let i = 0;819 let i = 0;696 for (const permission of permissions) {820 for (const permission of permissions) {725849726 it('Changes properties of a nested token according to permissions', async () => {850 it('Changes properties of a nested token according to permissions', async () => {727 await usingApi(async api => {851 await usingApi(async api => {852 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});853 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});854 const token = await createItemExpectSuccess(alice, collection, 'NFT');855 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});856 await addCollectionAdminExpectSuccess(alice, collection, bob.address);857 await transferExpectSuccess(collection, token, alice, charlie);858728 const propertyKeys: string[] = [];859 const propertyKeys: string[] = [];729 let i = 0;860 let i = 0;730 for (const permission of permissions) {861 for (const permission of permissions) {767898768 it('Deletes properties of a nested token according to permissions', async () => {899 it('Deletes properties of a nested token according to permissions', async () => {769 await usingApi(async api => {900 await usingApi(async api => {901 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});902 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});903 const token = await createItemExpectSuccess(alice, collection, 'NFT');904 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});905 await addCollectionAdminExpectSuccess(alice, collection, bob.address);906 await transferExpectSuccess(collection, token, alice, charlie);907770 const propertyKeys: string[] = [];908 const propertyKeys: string[] = [];771 let i = 0;909 let i = 0;772910832 });970 });833 });971 });834972835 beforeEach(async () => {973 async function prepare(mode: CollectionMode, pieces: number) {836 collection = await createCollectionExpectSuccess();974 collection = await createCollectionExpectSuccess({mode: mode});837 token = await createItemExpectSuccess(alice, collection, 'NFT');975 token = await createItemExpectSuccess(alice, collection, mode.type);838 await addCollectionAdminExpectSuccess(alice, collection, bob.address);976 await addCollectionAdminExpectSuccess(alice, collection, bob.address);839 await transferExpectSuccess(collection, token, alice, charlie);977 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);840 978 841 await usingApi(async api => {979 await usingApi(async api => {842 let i = 0;980 let i = 0;848 alice, 986 alice, 849 api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 987 api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 850 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;988 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;851989 852 await expect(executeTransaction(990 await expect(executeTransaction(853 api, 991 api, 854 signer, 992 signer, 855 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 993 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 856 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;994 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;857995 858 i++;996 i++;859 }997 }860998 861 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;999 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;862 });1000 }); 863 });1001 }8641002865 it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {1003 async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(mode: CollectionMode, pieces: number) {1004 await prepare(mode, pieces);1005 866 await usingApi(async api => {1006 await usingApi(async api => {867 let i = -1;1007 let i = -1;868 for (const forbiddance of constitution) {1008 for (const forbiddance of constitution) {869 i++;1009 i++;870 if (!forbiddance.permission.mutable) continue;1010 if (!forbiddance.permission.mutable) continue;8711011 872 await expect(executeTransaction(1012 await expect(executeTransaction(873 api, 1013 api, 874 forbiddance.sinner, 1014 forbiddance.sinner, 875 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1015 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 876 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1016 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);8771017 878 await expect(executeTransaction(1018 await expect(executeTransaction(879 api, 1019 api, 880 forbiddance.sinner, 1020 forbiddance.sinner, 881 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 1021 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 882 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1022 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);883 }1023 }8841024 885 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1025 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();886 expect(properties.consumedSpace).to.be.equal(originalSpace);1026 expect(properties.consumedSpace).to.be.equal(originalSpace);887 });1027 });1028 }1029 it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {1030 await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);888 });1031 });1032 it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {1033 await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);1034 });8891035890 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {1036 async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(mode: CollectionMode, pieces: number) {1037 await prepare(mode, pieces);1038 891 await usingApi(async api => {1039 await usingApi(async api => {892 let i = -1;1040 let i = -1;893 for (const permission of constitution) {1041 for (const permission of constitution) {894 i++;1042 i++;895 if (permission.permission.mutable) continue;1043 if (permission.permission.mutable) continue;8961044 897 await expect(executeTransaction(1045 await expect(executeTransaction(898 api, 1046 api, 899 permission.signers[0], 1047 permission.signers[0], 900 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1048 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 901 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1049 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);9021050 903 await expect(executeTransaction(1051 await expect(executeTransaction(904 api, 1052 api, 905 permission.signers[0], 1053 permission.signers[0], 906 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 1054 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 907 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1055 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);908 }1056 }9091057 910 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1058 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();911 expect(properties.consumedSpace).to.be.equal(originalSpace);1059 expect(properties.consumedSpace).to.be.equal(originalSpace);912 });1060 }); 1061 }1062 it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {1063 await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);913 });1064 });1065 it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {1066 await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);1067 });9141068915 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {1069 async function testForbidsAddingPropertiesIfPropertyNotDeclared(mode: CollectionMode, pieces: number) {1070 await prepare(mode, pieces);1071916 await usingApi(async api => {1072 await usingApi(async api => {917 await expect(executeTransaction(1073 await expect(executeTransaction(925 alice, 1081 alice, 926 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 1082 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 927 ), 'on setting a new non-permitted property').to.not.be.rejected;1083 ), 'on setting a new non-permitted property').to.not.be.rejected;9281084 929 await expect(executeTransaction(1085 await expect(executeTransaction(930 api, 1086 api, 931 alice, 1087 alice, 932 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 1088 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 933 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);1089 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);9341090 935 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;1091 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;936 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1092 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();937 expect(properties.consumedSpace).to.be.equal(originalSpace);1093 expect(properties.consumedSpace).to.be.equal(originalSpace);938 });1094 });1095 }1096 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {1097 await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);939 });1098 });1099 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {1100 await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);1101 });9401102941 it('Forbids adding too many properties to a token', async () => {1103 async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {1104 await prepare(mode, pieces);1105942 await usingApi(async api => {1106 await usingApi(async api => {943 await expect(executeTransaction(1107 await expect(executeTransaction(948 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},1112 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},949 ]), 1113 ]), 950 ), 'on setting a new non-permitted property').to.not.be.rejected;1114 ), 'on setting a new non-permitted property').to.not.be.rejected;9511115 952 // Mute the general tx parsing error1116 // Mute the general tx parsing error953 {1117 {954 console.error = () => {};1118 console.error = () => {};958 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 1122 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 959 )).to.be.rejected;1123 )).to.be.rejected;960 }1124 }9611125 962 await expect(executeTransaction(1126 await expect(executeTransaction(963 api, 1127 api, 964 alice, 1128 alice, 967 {key: 'young_years', value: 'neverending'.repeat(1490)},1131 {key: 'young_years', value: 'neverending'.repeat(1490)},968 ]), 1132 ]), 969 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);1133 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);9701134 971 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;1135 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;972 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1136 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();973 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1137 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1138 });1139 }1140 it('Forbids adding too many properties to a token (NFT)', async () => {1141 await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);1142 });1143 it('Forbids adding too many properties to a token (ReFungible)', async () => {1144 await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);1145 });1146});11471148describe('ReFungible token properties permissions tests', () => {1149 let collection: number;1150 let token: number;11511152 before(async () => {1153 await usingApi(async (api, privateKeyWrapper) => {1154 alice = privateKeyWrapper('//Alice');1155 bob = privateKeyWrapper('//Bob');1156 charlie = privateKeyWrapper('//Charlie');1157 });1158 });11591160 beforeEach(async () => {1161 await usingApi(async api => {1162 collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});1163 token = await createItemExpectSuccess(alice, collection, 'ReFungible');1164 await addCollectionAdminExpectSuccess(alice, collection, bob.address);11651166 await expect(executeTransaction(1167 api, 1168 alice, 1169 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1170 )).to.not.be.rejected;1171 });1172 });11731174 it('Forbids add token property with tokenOwher==true but signer have\'t all pieces', async () => {1175 await usingApi(async api => {1176 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1177 1178 await expect(executeTransaction(1179 api, 1180 alice, 1181 api.tx.unique.setTokenProperties(collection, token, [1182 {key: 'key', value: 'word'}, 1183 ]), 1184 )).to.be.rejectedWith(/common\.NoPermission/);1185 });1186 });11871188 it('Forbids mutate token property with tokenOwher==true but signer have\'t all pieces', async () => {1189 await usingApi(async api => {1190 await expect(executeTransaction(1191 api, 1192 alice, 1193 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1194 )).to.not.be.rejected;1195 1196 await expect(executeTransaction(1197 api, 1198 alice, 1199 api.tx.unique.setTokenProperties(collection, token, [1200 {key: 'key', value: 'word'}, 1201 ]), 1202 )).to.be.not.rejected;12031204 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1205 1206 await expect(executeTransaction(1207 api, 1208 alice, 1209 api.tx.unique.setTokenProperties(collection, token, [1210 {key: 'key', value: 'bad word'}, 1211 ]), 1212 )).to.be.rejectedWith(/common\.NoPermission/);1213 });1214 });12151216 it('Forbids delete token property with tokenOwher==true but signer have\'t all pieces', async () => {1217 await usingApi(async api => {1218 await expect(executeTransaction(1219 api, 1220 alice, 1221 api.tx.unique.setTokenProperties(collection, token, [1222 {key: 'key', value: 'word'}, 1223 ]), 1224 )).to.be.not.rejected;12251226 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1227 1228 await expect(executeTransaction(1229 api, 1230 alice, 1231 api.tx.unique.deleteTokenProperties(collection, token, [1232 'key',1233 ]), 1234 )).to.be.rejectedWith(/common\.NoPermission/);974 });1235 });975 });1236 });976});1237});tests/src/refungible.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {default as usingApi} from './substrate/substrate-api';17import {default as usingApi, executeTransaction} from './substrate/substrate-api';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {19import {20 createCollectionExpectSuccess,20 createCollectionExpectSuccess,30 transfer,30 transfer,31 burnItem,31 burnItem,32 repartitionRFT,32 repartitionRFT,33 createCollectionWithPropsExpectSuccess,34 getDetailedCollectionInfo,33} from './util/helpers';35} from './util/helpers';343635import chai from 'chai';37import chai from 'chai';188 });190 });189});191});192193describe('Test Refungible properties:', () => {194 before(async () => {195 await usingApi(async (api, privateKeyWrapper) => {196 alice = privateKeyWrapper('//Alice');197 bob = privateKeyWrapper('//Bob');198 });199 });200 201 it('Сreate new collection with properties', async () => {202 await usingApi(async api => {203 const properties = [{key: 'key1', value: 'val1'}];204 const propertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}];205 const collectionId = await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'ReFungible'},206 properties: properties,207 propPerm: propertyPermissions, 208 });209 const collection = (await getDetailedCollectionInfo(api, collectionId))!;210 expect(collection.properties.toHuman()).to.be.deep.equal(properties);211 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);212 });213 });214});190215tests/src/util/helpers.tsdiffbeforeafterboth284 type: 'ReFungible';284 type: 'ReFungible';285}285}286286287type CollectionMode = Nft | Fungible | ReFungible;287export type CollectionMode = Nft | Fungible | ReFungible;288288289export type Property = {289export type Property = {290 key: any,290 key: any,1414 tx = api.tx.unique.createItem(collectionId, to, createData as any);1414 tx = api.tx.unique.createItem(collectionId, to, createData as any);1415 }1415 }141614161417 const events = await submitTransactionAsync(sender, tx);1417 const events = await executeTransaction(api, sender, tx);1418 const result = getCreateItemResult(events);1418 const result = getCreateItemResult(events);141914191420 const itemCountAfter = await getLastTokenId(api, collectionId);1420 const itemCountAfter = await getLastTokenId(api, collectionId);