git.delta.rocks / unique-network / refs/commits / 3750ef0fdbd1

difftreelog

Merge pull request #422 from UniqueNetwork/feature/CORE-410

Yaroslav Bolyukin2022-07-21parents: #9f5f42d #14bb047.patch.diff
in: master
Feature/core 410 Properties for RFT

21 files changed

modifiedCargo.lockdiffbeforeafterboth
63206320
6321[[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",
1273312733
12734[[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",
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
966 ),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,
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
183 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)?}
187187
188 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}
212212
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
3//! Autogenerated weights for pallet_nonfungible3//! Autogenerated weights for pallet_nonfungible
4//!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-dev
6//! 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: 1024
88
9// 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_000
70 .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_000
82 .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_000
123 .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_000
170 .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_000
180 .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_000
190 .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_000
214 .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_000
226 .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_000
267 .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_000
314 .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_000
324 .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_000
334 .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}
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
1[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"
66
addedpallets/refungible/Changelog.mddiffbeforeafterboth

no changes

modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
18use crate::{Pallet, Config, RefungibleHandle};18use crate::{Pallet, Config, RefungibleHandle};
1919
20use 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)?}
210
211 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)?}
226
227 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)?}
248
249 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)?}
206272
207 repartition_item {273 repartition_item {
208 bench_init!{274 bench_init!{
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
20use 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}
46
47fn 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 0
52 }
53}
4354
44pub 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 }
4960
50 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 }
5373
54 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 }
6995
70 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 0
73 }98 }
7499
75 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 0
78 }102 }
79103
80 fn set_token_properties(_amount: u32) -> Weight {104 fn set_token_properties(amount: u32) -> Weight {
81 // Error105 <SelfWeightOf<T>>::set_token_properties(amount)
82 0
83 }106 }
84107
85 fn delete_token_properties(_amount: u32) -> Weight {108 fn delete_token_properties(amount: u32) -> Weight {
86 // Error109 <SelfWeightOf<T>>::delete_token_properties(amount)
87 0
88 }110 }
89111
90 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 0
93 }114 }
94115
95 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 }
297319
298 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);
326
303 fail!(<Error<T>>::SettingPropertiesNotAllowed)327 with_weight(
328 <Pallet<T>>::set_collection_properties(self, &sender, properties),
329 weight,
330 )
304 }331 }
305332
306 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);
339
311 fail!(<Error<T>>::SettingPropertiesNotAllowed)340 with_weight(
341 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),
342 weight,
343 )
312 }344 }
313345
314 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);
354
321 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 }
323367
324 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);
375
329 fail!(<Error<T>>::SettingPropertiesNotAllowed)376 with_weight(
377 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),
378 weight,
379 )
330 }380 }
331381
332 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);
390
339 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 }
341402
373 TokenId(<TokensMinted<T>>::get(self.id))434 TokenId(<TokensMinted<T>>::get(self.id))
374 }435 }
375436
376 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 }
379440
380 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {441 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
8787
88#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]
8989
90use 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 >;
182
183 #[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 >;
177191
178 /// Total amount of pieces for token192 /// Total amount of pieces for token
179 #[pallet::storage]193 #[pallet::storage]
279 <TotalSupply<T>>::contains_key((collection.id, token))293 <TotalSupply<T>>::contains_key((collection.id, token))
280 }294 }
295
296 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)?;
306
307 Ok(())
308 }
309
310 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)?;
320
321 Ok(())
322 }
281}323}
282324
283// unchecked calls skips any permission checks325// unchecked calls skips any permission checks
339381
340 <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 }
472
473 #[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 }
490
491 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(
492 sender.clone(),
493 collection.id,
494 token_id,
495 None,
496 nesting_budget,
497 )?;
498
499 Ok(is_bundle_owner)
500 };
501
502 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);
507
508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))
509 .get(&key)
510 .is_some();
511
512 match permission {
513 PropertyPermission { mutable: false, .. } if is_property_exists => {
514 return Err(<CommonError<T>>::NoPermission.into());
515 }
516
517 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_create
526 || (collection_admin && is_collection_admin())
527 || (token_owner && is_token_owner()?))
528 {
529 fail!(<CommonError<T>>::NoPermission);
530 }
531 }
532 }
533
534 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)?;
540
541 <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)?;
552
553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
554 collection.id,
555 token_id,
556 key,
557 ));
558 }
559 }
560 }
561
562 Ok(())
563 }
564
565 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 }
582
583 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;
591
592 Self::set_token_properties(
593 collection,
594 sender,
595 token_id,
596 [property].into_iter(),
597 is_token_create,
598 nesting_budget,
599 )
600 }
601
602 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;
610
611 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 }
620
621 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 }
429636
430 /// Transfer RFT token pieces from one account to another.637 /// Transfer RFT token pieces from one account to another.
431 ///638 ///
629836
630 // =========837 // =========
631838
632 <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]);
639843
640 <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 );
646850
647 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 );
658
659 // TODO: ERC20 transfer event
660 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
661 collection.id,
662 TokenId(token_id),
663 user,
664 amount,
665 ));
666 }862 }
863
864 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 })?;
877
878 <TokensMinted<T>>::insert(collection.id, tokens_minted);
879
880 for (account, balance) in balances {
881 <AccountBalance<T>>::insert((collection.id, account), balance);
882 }
883
884 for (i, token) in data.into_iter().enumerate() {
885 let token_id = first_token_id + i as u32 + 1;
886
887 for (user, amount) in token.users.into_iter() {
888 if amount == 0 {
889 continue;
890 }
891
892 // TODO: ERC20 transfer event
893 <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 }
670903
849 );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 pieces
852 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>>::RepartitionWhileNotOwningAllPieces
857 );1090 );
8581091
861 Ok(())1094 Ok(())
862 }1095 }
1096
1097 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 owner
1108 }
8631109
864 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 }
1113
1114 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 }
1121
1122 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 }
1129
1130 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}
8681138
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
3//! Autogenerated weights for pallet_refungible3//! Autogenerated weights for pallet_refungible
4//!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-dev
6//! 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: 1024
88
9// 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}
5457
62 // 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_000
78 .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_000
92 .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_000
107 .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_000
225 .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_000
234 .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_000
243 .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_000
247 .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_000
261 .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_000
276 .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_000
422 .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_000
431 .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_000
440 .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 }
modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
6license = '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'
1010
11[dependencies]11[dependencies]
12scale-info = { version = "2.0.1", default-features = false, features = [12scale-info = { version = "2.0.1", default-features = false, features = [
addedprimitives/data-structs/Changelog.mddiffbeforeafterboth

no changes

modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
537
537 pub pieces: u128,538 pub pieces: u128,
539
540 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
541 #[derivative(Debug(format_with = "bounded::vec_debug"))]
542 pub properties: CollectionPropertiesVec,
538}543}
539544
540#[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}
572579
573#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]580#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
376 // ReFungible376 // ReFungible
377 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.unique
385 .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.unique
396 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);
397 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;
398 }
387 });399 });
388 });400 });
389401
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
408 **/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]>;
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
2461export 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}
24652466
2466/** @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}
24712473
2472/** @name UpDataStructsNestingPermissions */2474/** @name UpDataStructsNestingPermissions */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
1502 **/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>
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
1629 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 }
16331634
1634 /** @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 }
16581660
1659 /** @name PalletUniqueSchedulerCall (204) */1661 /** @name PalletUniqueSchedulerCall (204) */
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
2import 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 });
2526
26 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});
2930
30 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 }
62
63 it('Makes sure collectionById supplies required fields for NFT', async () => {
64 await testMakeSureSuppliesRequired({type: 'NFT'});
60 });65 });
66
67 it('Makes sure collectionById supplies required fields for ReFungible', async () => {
68 await testMakeSureSuppliesRequired({type: 'ReFungible'});
69 });
61});70});
6271
63// ---------- COLLECTION PROPERTIES72// ---------- COLLECTION PROPERTIES
79 });88 });
80 });89 });
8190
91
82 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);
8696
87 // As owner97 // As owner
106 {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 });
110126
111 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 symbols
117 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 symbols
124 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 symbol
131 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 symbol
138 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 symbol
145 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 });
162184
163 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 properties
174 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 });
187215
188 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});
211245
212describe('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 process
242 {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 });
291
292 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});
341399
342// ---------- ACCESS RIGHTS400// ---------- ACCESS RIGHTS
357 });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});
409479
410describe('Negative Integration Test: Access Rights to Token Properties', () => {480describe('Negative Integration Test: Access Rights to Token Properties', () => {
415 });485 });
416 });486 });
417487
418 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 });
432508
433 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 });
455537
456 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 });
478566
479 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-string
504 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});
521615
522// ---------- TOKEN PROPERTIES616// ---------- TOKEN PROPERTIES
523617
524describe('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[]}[];
529620
530 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 owner
533 bob = privateKeyWrapper('//Bob');624 bob = privateKeyWrapper('//Bob'); // collection admin
534 charlie = privateKeyWrapper('//Charlie');625 charlie = privateKeyWrapper('//Charlie'); // token owner
535626
536 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 });
546
547 beforeEach(async () => {
548 await usingApi(async () => {
549 collection = await createCollectionExpectSuccess();
550 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
551
552 token = await createItemExpectSuccess(alice, collection, 'NFT');
553 nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
554
555 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 });
573657
574 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);
664
576 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 });
607702
608 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);
709
610 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 });
649755
650 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);
762
652 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 });
691808
692 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);
817
694 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) {
725849
726 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);
858
728 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) {
767898
768 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);
907
770 const propertyKeys: string[] = [];908 const propertyKeys: string[] = [];
771 let i = 0;909 let i = 0;
772910
832 });970 });
833 });971 });
834972
835 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 }
8641002
865 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 });
8891035
890 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 });
9141068
915 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);
1071
916 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 });
9401102
941 it('Forbids adding too many properties to a token', async () => {1103 async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {
1104 await prepare(mode, pieces);
1105
942 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 error
953 {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});
1147
1148describe('ReFungible token properties permissions tests', () => {
1149 let collection: number;
1150 let token: number;
1151
1152 before(async () => {
1153 await usingApi(async (api, privateKeyWrapper) => {
1154 alice = privateKeyWrapper('//Alice');
1155 bob = privateKeyWrapper('//Bob');
1156 charlie = privateKeyWrapper('//Charlie');
1157 });
1158 });
1159
1160 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);
1165
1166 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 });
1173
1174 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 });
1187
1188 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;
1203
1204 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 });
1215
1216 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;
1225
1226 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});
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17import {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';
3436
35import chai from 'chai';37import chai from 'chai';
188 });190 });
189});191});
192
193describe('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});
190215
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
284 type: 'ReFungible';284 type: 'ReFungible';
285}285}
286286
287type CollectionMode = Nft | Fungible | ReFungible;287export type CollectionMode = Nft | Fungible | ReFungible;
288288
289export 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 }
14161416
1417 const events = await submitTransactionAsync(sender, tx);1417 const events = await executeTransaction(api, sender, tx);
1418 const result = getCreateItemResult(events);1418 const result = getCreateItemResult(events);
14191419
1420 const itemCountAfter = await getLastTokenId(api, collectionId);1420 const itemCountAfter = await getLastTokenId(api, collectionId);