git.delta.rocks / unique-network / refs/commits / c6354cf493a0

difftreelog

feat add ApproveForAll to Eth and Sub

Grigoriy Simonov2022-12-06parent: #e7f81f3.patch.diff
in: master

39 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
247 at: Option<BlockHash>,247 at: Option<BlockHash>,
248 ) -> Result<Option<String>>;248 ) -> Result<Option<String>>;
249
250 /// Get whether an operator is approved by a given owner.
251 #[method(name = "unique_isApprovedForAll")]
252 fn is_approved_for_all(
253 &self,
254 collection: CollectionId,
255 owner: CrossAccountId,
256 operator: CrossAccountId,
257 at: Option<BlockHash>,
258 ) -> Result<bool>;
249}259}
250260
251mod app_promotion_unique_rpc {261mod app_promotion_unique_rpc {
569 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);579 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);
570 pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);580 pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);
571 pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);581 pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);
582 pass_method!(is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> bool, unique_api);
572}583}
573584
574impl<C, Block, BlockNumber, CrossAccountId, AccountId>585impl<C, Block, BlockNumber, CrossAccountId, AccountId>
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
472 u128,472 u128,
473 ),473 ),
474
475 /// Amount pieces of token owned by `sender` was approved for `spender`.
476 ApprovedForAll(
477 /// Id of collection to which item is belong.
478 CollectionId,
479 /// Owner of a wallet.
480 T::CrossAccountId,
481 /// Id for which operator status was granted or rewoked.
482 T::CrossAccountId,
483 /// Is operator status was granted or rewoked.
484 bool,
485 ),
474486
475 /// The colletion property has been added or edited.487 /// The colletion property has been added or edited.
476 CollectionPropertySet(488 CollectionPropertySet(
1522 /// The price of retrieving token owner1534 /// The price of retrieving token owner
1523 fn token_owner() -> Weight;1535 fn token_owner() -> Weight;
1536
1537 /// The price of setting approval for all
1538 fn set_approval_for_all() -> Weight;
1524}1539}
15251540
1526/// Weight info extension trait for refungible pallet.1541/// Weight info extension trait for refungible pallet.
1829 /// Get extension for RFT collection.1844 /// Get extension for RFT collection.
1830 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1845 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;
1846
1847 /// An operator is allowed to transfer all tokens of the sender on their behalf.
1848 /// * `owner` - Token owner
1849 /// * `operator` - Operator
1850 /// * `approve` - Is operator enabled or disabled
1851 fn set_approval_for_all(
1852 &self,
1853 owner: T::CrossAccountId,
1854 operator: T::CrossAccountId,
1855 approve: bool,
1856 ) -> DispatchResultWithPostInfo;
1857
1858 /// Tells whether an operator is approved by a given owner.
1859 fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;
1831}1860}
18321861
1833/// Extension for RFT collection.1862/// Extension for RFT collection.
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
108 Weight::zero()108 Weight::zero()
109 }109 }
110
111 fn set_approval_for_all() -> Weight {
112 Weight::zero()
113 }
110}114}
111115
112/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete116/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
425 <TotalSupply<T>>::try_get(self.id).ok()429 <TotalSupply<T>>::try_get(self.id).ok()
426 }430 }
431
432 fn set_approval_for_all(
433 &self,
434 _owner: T::CrossAccountId,
435 _operator: T::CrossAccountId,
436 _approve: bool,
437 ) -> DispatchResultWithPostInfo {
438 fail!(<Error<T>>::SettingApprovalForAllNotAllowed)
439 }
440
441 fn is_approved_for_all(&self, _owner: T::CrossAccountId, _operator: T::CrossAccountId) -> bool {
442 false
443 }
427}444}
428445
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
127 FungibleDisallowsNesting,127 FungibleDisallowsNesting,
128 /// Setting item properties is not allowed.128 /// Setting item properties is not allowed.
129 SettingPropertiesNotAllowed,129 SettingPropertiesNotAllowed,
130 /// Setting approval for all is not allowed.
131 SettingApprovalForAllNotAllowed,
130 }132 }
131133
132 #[pallet::config]134 #[pallet::config]
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
223223
224 }: {collection.token_owner(item)}224 }: {collection.token_owner(item)}
225
226 set_approval_for_all {
227 bench_init!{
228 owner: sub; collection: collection(owner);
229 operator: cross_from_sub(owner); owner: cross_sub;
230 };
231 }: {<Pallet<T>>::set_approval_for_all(&collection, &owner, &operator, true)}
232
233 is_approved_for_all {
234 bench_init!{
235 owner: sub; collection: collection(owner);
236 operator: cross_from_sub(owner); owner: cross_sub;
237 };
238 }: {<Pallet<T>>::is_approved_for_all(&collection, &owner, &operator)}
225}239}
226240
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
123 <SelfWeightOf<T>>::token_owner()123 <SelfWeightOf<T>>::token_owner()
124 }124 }
125
126 fn set_approval_for_all() -> Weight {
127 <SelfWeightOf<T>>::set_approval_for_all()
128 }
125}129}
126130
127fn map_create_data<T: Config>(131fn map_create_data<T: Config>(
513 }517 }
514 }518 }
519
520 fn set_approval_for_all(
521 &self,
522 owner: T::CrossAccountId,
523 operator: T::CrossAccountId,
524 approve: bool,
525 ) -> DispatchResultWithPostInfo {
526 with_weight(
527 <Pallet<T>>::set_approval_for_all(self, &owner, &operator, approve),
528 <CommonWeights<T>>::set_approval_for_all(),
529 )
530 }
531
532 fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
533 <Pallet<T>>::is_approved_for_all(self, &owner, &operator)
534 }
515}535}
516536
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
469 Ok(())469 Ok(())
470 }470 }
471471
472 /// @notice Sets or unsets the approval of a given operator.
473 /// An operator is allowed to transfer all tokens of the sender on their behalf.
472 /// @dev Not implemented474 /// @param operator Operator
475 /// @param approved Is operator enabled or disabled
476 #[weight(<SelfWeightOf<T>>::set_approval_for_all())]
473 fn set_approval_for_all(477 fn set_approval_for_all(
474 &mut self,478 &mut self,
475 _caller: caller,479 caller: caller,
476 _operator: address,480 operator: address,
477 _approved: bool,481 approved: bool,
478 ) -> Result<void> {482 ) -> Result<void> {
479 // TODO: Not implemetable483 let caller = T::CrossAccountId::from_eth(caller);
484 let operator = T::CrossAccountId::from_eth(operator);
485
486 <Pallet<T>>::set_approval_for_all(self, &caller, &operator, approved)
480 Err("not implemented".into())487 .map_err(dispatch_to_evm::<T>)?;
488 Ok(())
481 }489 }
482490
483 /// @dev Not implemented491 /// @dev Not implemented
486 Err("not implemented".into())494 Err("not implemented".into())
487 }495 }
488496
489 /// @dev Not implemented497 /// @notice Tells whether an operator is approved by a given owner.
498 #[weight(<SelfWeightOf<T>>::is_approved_for_all())]
490 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {499 fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
491 // TODO: Not implemetable500 let owner = T::CrossAccountId::from_eth(owner);
501 let operator = T::CrossAccountId::from_eth(operator);
502
492 Err("not implemented".into())503 Ok(<Pallet<T>>::is_approved_for_all(self, &owner, &operator))
493 }504 }
494505
495 /// @notice Returns collection helper contract address506 /// @notice Returns collection helper contract address
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
272 QueryKind = OptionQuery,272 QueryKind = OptionQuery,
273 >;273 >;
274
275 /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
276 #[pallet::storage]
277 pub type WalletOperator<T: Config> = StorageNMap<
278 Key = (
279 Key<Twox64Concat, CollectionId>,
280 Key<Blake2_128Concat, T::CrossAccountId>,
281 Key<Blake2_128Concat, T::CrossAccountId>,
282 ),
283 Value = bool,
284 QueryKind = OptionQuery,
285 >;
274286
275 /// Upgrade from the old schema to properties.287 /// Upgrade from the old schema to properties.
276 #[pallet::hooks]288 #[pallet::hooks]
438 <TokensBurnt<T>>::remove(id);450 <TokensBurnt<T>>::remove(id);
439 let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);451 let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);
440 let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);452 let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);
453 let _ = <WalletOperator<T>>::clear_prefix((id,), u32::MAX, None);
441 Ok(())454 Ok(())
442 }455 }
443456
1193 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {1206 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
1194 return Ok(());1207 return Ok(());
1195 }1208 }
1209 if <WalletOperator<T>>::get((collection.id, from, spender)) == Some(true) {
1210 return Ok(());
1211 }
1196 ensure!(1212 ensure!(
1197 collection.ignores_allowance(spender),1213 collection.ignores_allowance(spender),
1198 <CommonError<T>>::ApprovedValueTooLow1214 <CommonError<T>>::ApprovedValueTooLow
1327 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1343 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)
1328 }1344 }
1345
1346 /// Sets or unsets the approval of a given operator.
1347 ///
1348 /// An operator is allowed to transfer all token pieces of the sender on their behalf.
1349 /// - `owner`: Token owner
1350 /// - `operator`: Operator
1351 /// - `approve`: Is operator enabled or disabled
1352 pub fn set_approval_for_all(
1353 collection: &NonfungibleHandle<T>,
1354 owner: &T::CrossAccountId,
1355 operator: &T::CrossAccountId,
1356 approve: bool,
1357 ) -> DispatchResult {
1358 if collection.permissions.access() == AccessMode::AllowList {
1359 collection.check_allowlist(owner)?;
1360 collection.check_allowlist(operator)?;
1361 }
1362
1363 <PalletCommon<T>>::ensure_correct_receiver(operator)?;
1364
1365 // =========
1366
1367 <WalletOperator<T>>::insert((collection.id, owner, operator), approve);
1368 <PalletEvm<T>>::deposit_log(
1369 ERC721Events::ApprovalForAll {
1370 owner: *owner.as_eth(),
1371 operator: *operator.as_eth(),
1372 approved: approve,
1373 }
1374 .to_log(collection_id_to_address(collection.id)),
1375 );
1376 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
1377 collection.id,
1378 owner.clone(),
1379 operator.clone(),
1380 approve,
1381 ));
1382 Ok(())
1383 }
1384
1385 /// Tells whether an operator is approved by a given owner.
1386 pub fn is_approved_for_all(
1387 collection: &NonfungibleHandle<T>,
1388 owner: &T::CrossAccountId,
1389 operator: &T::CrossAccountId,
1390 ) -> bool {
1391 <WalletOperator<T>>::get((collection.id, owner, operator)).unwrap_or(false)
1392 }
1329}1393}
13301394
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
1020 dummy = 0;1020 dummy = 0;
1021 }1021 }
10221022
1023 /// @notice Sets or unsets the approval of a given operator.
1024 /// An operator is allowed to transfer all tokens of the sender on their behalf.
1023 /// @dev Not implemented1025 /// @param operator Operator
1026 /// @param approved Is operator enabled or disabled
1024 /// @dev EVM selector for this function is: 0xa22cb465,1027 /// @dev EVM selector for this function is: 0xa22cb465,
1025 /// or in textual repr: setApprovalForAll(address,bool)1028 /// or in textual repr: setApprovalForAll(address,bool)
1026 function setApprovalForAll(address operator, bool approved) public {1029 function setApprovalForAll(address operator, bool approved) public {
1040 return 0x0000000000000000000000000000000000000000;1043 return 0x0000000000000000000000000000000000000000;
1041 }1044 }
10421045
1043 /// @dev Not implemented1046 /// @notice Tells whether an operator is approved by a given owner.
1044 /// @dev EVM selector for this function is: 0xe985e9c5,1047 /// @dev EVM selector for this function is: 0xe985e9c5,
1045 /// or in textual repr: isApprovedForAll(address,address)1048 /// or in textual repr: isApprovedForAll(address,address)
1046 function isApprovedForAll(address owner, address operator) public view returns (address) {1049 function isApprovedForAll(address owner, address operator) public view returns (bool) {
1047 require(false, stub_error);1050 require(false, stub_error);
1048 owner;1051 owner;
1049 operator;1052 operator;
1050 dummy;1053 dummy;
1051 return 0x0000000000000000000000000000000000000000;1054 return false;
1052 }1055 }
10531056
1054 /// @notice Returns collection helper contract address1057 /// @notice Returns collection helper contract address
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
26#![cfg_attr(rustfmt, rustfmt_skip)]26#![cfg_attr(rustfmt, rustfmt_skip)]
27#![allow(unused_parens)]27#![allow(unused_parens)]
28#![allow(unused_imports)]28#![allow(unused_imports)]
29#![allow(missing_docs)]
29#![allow(clippy::unnecessary_cast)]30#![allow(clippy::unnecessary_cast)]
3031
31use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};32use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
47 fn set_token_properties(b: u32, ) -> Weight;48 fn set_token_properties(b: u32, ) -> Weight;
48 fn delete_token_properties(b: u32, ) -> Weight;49 fn delete_token_properties(b: u32, ) -> Weight;
49 fn token_owner() -> Weight;50 fn token_owner() -> Weight;
51 fn set_approval_for_all() -> Weight;
52 fn is_approved_for_all() -> Weight;
50}53}
5154
52/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.55/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.
195 Weight::from_ref_time(4_366_000)198 Weight::from_ref_time(4_366_000)
196 .saturating_add(T::DbWeight::get().reads(1 as u64))199 .saturating_add(T::DbWeight::get().reads(1 as u64))
197 }200 }
201 // Storage: Nonfungible WalletOperator (r:0 w:1)
202 fn set_approval_for_all() -> Weight {
203 Weight::from_ref_time(16_231_000 as u64)
204 .saturating_add(T::DbWeight::get().writes(1 as u64))
205 }
206 // Storage: Nonfungible WalletOperator (r:1 w:0)
207 fn is_approved_for_all() -> Weight {
208 Weight::from_ref_time(6_161_000 as u64)
209 .saturating_add(T::DbWeight::get().reads(1 as u64))
210 }
198}211}
199212
200// For backwards compatibility and tests213// For backwards compatibility and tests
342 Weight::from_ref_time(4_366_000)355 Weight::from_ref_time(4_366_000)
343 .saturating_add(RocksDbWeight::get().reads(1 as u64))356 .saturating_add(RocksDbWeight::get().reads(1 as u64))
344 }357 }
358 // Storage: Nonfungible WalletOperator (r:0 w:1)
359 fn set_approval_for_all() -> Weight {
360 Weight::from_ref_time(16_231_000 as u64)
361 .saturating_add(RocksDbWeight::get().writes(1 as u64))
362 }
363 // Storage: Nonfungible WalletOperator (r:1 w:0)
364 fn is_approved_for_all() -> Weight {
365 Weight::from_ref_time(6_161_000 as u64)
366 .saturating_add(RocksDbWeight::get().reads(1 as u64))
367 }
345}368}
346369
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
291 let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;291 let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;
292 }: {<Pallet<T>>::token_owner(collection.id, item)}292 }: {<Pallet<T>>::token_owner(collection.id, item)}
293
294 set_approval_for_all {
295 bench_init!{
296 owner: sub; collection: collection(owner);
297 operator: cross_from_sub(owner); owner: cross_sub;
298 };
299 }: {<Pallet<T>>::set_approval_for_all(&collection, &owner, &operator, true)}
300
301 is_approved_for_all {
302 bench_init!{
303 owner: sub; collection: collection(owner);
304 operator: cross_from_sub(owner); owner: cross_sub;
305 };
306 }: {<Pallet<T>>::is_approved_for_all(&collection, &owner, &operator)}
293}307}
294308
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
153 <SelfWeightOf<T>>::token_owner()153 <SelfWeightOf<T>>::token_owner()
154 }154 }
155
156 fn set_approval_for_all() -> Weight {
157 <SelfWeightOf<T>>::set_approval_for_all()
158 }
155}159}
156160
157fn map_create_data<T: Config>(161fn map_create_data<T: Config>(
517 <Pallet<T>>::total_pieces(self.id, token)521 <Pallet<T>>::total_pieces(self.id, token)
518 }522 }
523
524 fn set_approval_for_all(
525 &self,
526 owner: T::CrossAccountId,
527 operator: T::CrossAccountId,
528 approve: bool,
529 ) -> DispatchResultWithPostInfo {
530 with_weight(
531 <Pallet<T>>::set_approval_for_all(self, &owner, &operator, approve),
532 <CommonWeights<T>>::set_approval_for_all(),
533 )
534 }
535
536 fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
537 <Pallet<T>>::is_approved_for_all(self, &owner, &operator)
538 }
519}539}
520540
521impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {541impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
461 Err("not implemented".into())461 Err("not implemented".into())
462 }462 }
463463
464 /// @notice Sets or unsets the approval of a given operator.
465 /// An operator is allowed to transfer all tokens of the sender on their behalf.
464 /// @dev Not implemented466 /// @param operator Operator
467 /// @param approved Is operator enabled or disabled
468 #[weight(<SelfWeightOf<T>>::set_approval_for_all())]
465 fn set_approval_for_all(469 fn set_approval_for_all(
466 &mut self,470 &mut self,
467 _caller: caller,471 caller: caller,
468 _operator: address,472 operator: address,
469 _approved: bool,473 approved: bool,
470 ) -> Result<void> {474 ) -> Result<void> {
471 // TODO: Not implemetable475 let caller = T::CrossAccountId::from_eth(caller);
476 let operator = T::CrossAccountId::from_eth(operator);
477
478 <Pallet<T>>::set_approval_for_all(self, &caller, &operator, approved)
472 Err("not implemented".into())479 .map_err(dispatch_to_evm::<T>)?;
480 Ok(())
473 }481 }
474482
475 /// @dev Not implemented483 /// @dev Not implemented
478 Err("not implemented".into())486 Err("not implemented".into())
479 }487 }
480488
481 /// @dev Not implemented489 /// @notice Tells whether an operator is approved by a given owner.
490 #[weight(<SelfWeightOf<T>>::is_approved_for_all())]
482 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {491 fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
483 // TODO: Not implemetable492 let owner = T::CrossAccountId::from_eth(owner);
493 let operator = T::CrossAccountId::from_eth(operator);
494
484 Err("not implemented".into())495 Ok(<Pallet<T>>::is_approved_for_all(self, &owner, &operator))
485 }496 }
486497
487 /// @notice Returns collection helper contract address498 /// @notice Returns collection helper contract address
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
273 QueryKind = ValueQuery,273 QueryKind = ValueQuery,
274 >;274 >;
275
276 /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
277 #[pallet::storage]
278 pub type WalletOperator<T: Config> = StorageNMap<
279 Key = (
280 Key<Twox64Concat, CollectionId>,
281 Key<Blake2_128Concat, T::CrossAccountId>,
282 Key<Blake2_128Concat, T::CrossAccountId>,
283 ),
284 Value = bool,
285 QueryKind = OptionQuery,
286 >;
275287
276 #[pallet::hooks]288 #[pallet::hooks]
277 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {289 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1162 let allowance =1174 let allowance =
1163 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);1175 <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);
1176
1177 // Allowance if any would be reduced if spender is also wallet operator
1178 if <WalletOperator<T>>::get((collection.id, from, spender)) == Some(true) {
1179 return Ok(allowance);
1180 }
1181
1164 if allowance.is_none() {1182 if allowance.is_none() {
1165 ensure!(1183 ensure!(
1388 }1406 }
1389 }1407 }
1408
1409 /// Sets or unsets the approval of a given operator.
1410 ///
1411 /// An operator is allowed to transfer all tokens of the sender on their behalf.
1412 /// - `owner`: Token owner
1413 /// - `operator`: Operator
1414 /// - `approve`: Is operator enabled or disabled
1415 pub fn set_approval_for_all(
1416 collection: &RefungibleHandle<T>,
1417 owner: &T::CrossAccountId,
1418 operator: &T::CrossAccountId,
1419 approve: bool,
1420 ) -> DispatchResult {
1421 if collection.permissions.access() == AccessMode::AllowList {
1422 collection.check_allowlist(owner)?;
1423 collection.check_allowlist(operator)?;
1424 }
1425
1426 <PalletCommon<T>>::ensure_correct_receiver(operator)?;
1427
1428 // =========
1429
1430 <WalletOperator<T>>::insert((collection.id, owner, operator), approve);
1431 <PalletEvm<T>>::deposit_log(
1432 ERC721Events::ApprovalForAll {
1433 owner: *owner.as_eth(),
1434 operator: *operator.as_eth(),
1435 approved: approve,
1436 }
1437 .to_log(collection_id_to_address(collection.id)),
1438 );
1439 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
1440 collection.id,
1441 owner.clone(),
1442 operator.clone(),
1443 approve,
1444 ));
1445 Ok(())
1446 }
1447
1448 /// Tells whether an operator is approved by a given owner.
1449 pub fn is_approved_for_all(
1450 collection: &RefungibleHandle<T>,
1451 owner: &T::CrossAccountId,
1452 operator: &T::CrossAccountId,
1453 ) -> bool {
1454 <WalletOperator<T>>::get((collection.id, owner, operator)).unwrap_or(false)
1455 }
1390}1456}
13911457
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
1017 dummy = 0;1017 dummy = 0;
1018 }1018 }
10191019
1020 /// @notice Sets or unsets the approval of a given operator.
1021 /// An operator is allowed to transfer all tokens of the sender on their behalf.
1020 /// @dev Not implemented1022 /// @param operator Operator
1023 /// @param approved Is operator enabled or disabled
1021 /// @dev EVM selector for this function is: 0xa22cb465,1024 /// @dev EVM selector for this function is: 0xa22cb465,
1022 /// or in textual repr: setApprovalForAll(address,bool)1025 /// or in textual repr: setApprovalForAll(address,bool)
1023 function setApprovalForAll(address operator, bool approved) public {1026 function setApprovalForAll(address operator, bool approved) public {
1037 return 0x0000000000000000000000000000000000000000;1040 return 0x0000000000000000000000000000000000000000;
1038 }1041 }
10391042
1040 /// @dev Not implemented1043 /// @notice Tells whether an operator is approved by a given owner.
1041 /// @dev EVM selector for this function is: 0xe985e9c5,1044 /// @dev EVM selector for this function is: 0xe985e9c5,
1042 /// or in textual repr: isApprovedForAll(address,address)1045 /// or in textual repr: isApprovedForAll(address,address)
1043 function isApprovedForAll(address owner, address operator) public view returns (address) {1046 function isApprovedForAll(address owner, address operator) public view returns (bool) {
1044 require(false, stub_error);1047 require(false, stub_error);
1045 owner;1048 owner;
1046 operator;1049 operator;
1047 dummy;1050 dummy;
1048 return 0x0000000000000000000000000000000000000000;1051 return false;
1049 }1052 }
10501053
1051 /// @notice Returns collection helper contract address1054 /// @notice Returns collection helper contract address
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-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-11-25, 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:
26#![cfg_attr(rustfmt, rustfmt_skip)]26#![cfg_attr(rustfmt, rustfmt_skip)]
27#![allow(unused_parens)]27#![allow(unused_parens)]
28#![allow(unused_imports)]28#![allow(unused_imports)]
29#![allow(missing_docs)]
29#![allow(clippy::unnecessary_cast)]30#![allow(clippy::unnecessary_cast)]
3031
31use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};32use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
54 fn delete_token_properties(b: u32, ) -> Weight;55 fn delete_token_properties(b: u32, ) -> Weight;
55 fn repartition_item() -> Weight;56 fn repartition_item() -> Weight;
56 fn token_owner() -> Weight;57 fn token_owner() -> Weight;
58 fn set_approval_for_all() -> Weight;
59 fn is_approved_for_all() -> Weight;
57}60}
5861
59/// Weights for pallet_refungible using the Substrate node and recommended hardware.62/// Weights for pallet_refungible using the Substrate node and recommended hardware.
259 Weight::from_ref_time(9_431_000)262 Weight::from_ref_time(9_431_000)
260 .saturating_add(T::DbWeight::get().reads(2 as u64))263 .saturating_add(T::DbWeight::get().reads(2 as u64))
261 }264 }
265 // Storage: Refungible WalletOperator (r:0 w:1)
266 fn set_approval_for_all() -> Weight {
267 Weight::from_ref_time(16_150_000 as u64)
268 .saturating_add(T::DbWeight::get().writes(1 as u64))
269 }
270 // Storage: Refungible WalletOperator (r:1 w:0)
271 fn is_approved_for_all() -> Weight {
272 Weight::from_ref_time(5_901_000 as u64)
273 .saturating_add(T::DbWeight::get().reads(1 as u64))
274 }
262}275}
263276
264// For backwards compatibility and tests277// For backwards compatibility and tests
463 Weight::from_ref_time(9_431_000)476 Weight::from_ref_time(9_431_000)
464 .saturating_add(RocksDbWeight::get().reads(2 as u64))477 .saturating_add(RocksDbWeight::get().reads(2 as u64))
465 }478 }
479 // Storage: Refungible WalletOperator (r:0 w:1)
480 fn set_approval_for_all() -> Weight {
481 Weight::from_ref_time(16_150_000 as u64)
482 .saturating_add(RocksDbWeight::get().writes(1 as u64))
483 }
484 // Storage: Refungible WalletOperator (r:1 w:0)
485 fn is_approved_for_all() -> Weight {
486 Weight::from_ref_time(5_901_000 as u64)
487 .saturating_add(RocksDbWeight::get().reads(1 as u64))
488 }
466}489}
467490
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
1127 })1127 })
1128 }1128 }
1129
1130 /// Sets or unsets the approval of a given operator.
1131 ///
1132 /// An operator is allowed to transfer all tokens of the sender on their behalf.
1133 ///
1134 /// # Arguments
1135 ///
1136 /// * `owner`: Token owner
1137 /// * `operator`: Operator
1138 /// * `approve`: Is operator enabled or disabled
1139 #[weight = T::CommonWeightInfo::set_approval_for_all()]
1140 pub fn set_approval_for_all(
1141 origin,
1142 collection_id: CollectionId,
1143 operator: T::CrossAccountId,
1144 approve: bool,
1145 ) -> DispatchResultWithPostInfo {
1146 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
1147 dispatch_tx::<T, _>(collection_id, |d| {
1148 d.set_approval_for_all(sender, operator, approve)
1149 })
1150 }
1129 }1151 }
1130}1152}
11311153
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
133133
134 fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;134 fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
135
136 /// Get whether an operator is approved by a given owner.
137 fn is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result<bool>;
135 }138 }
136}139}
137140
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
188 dispatch_unique_runtime!(collection.total_pieces(token_id))188 dispatch_unique_runtime!(collection.total_pieces(token_id))
189 }189 }
190
191 fn is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result<bool, DispatchError> {
192 dispatch_unique_runtime!(collection.is_approved_for_all(owner, operator))
193 }
190 }194 }
191195
192 impl app_promotion_rpc::AppPromotionApi<Block, BlockNumber, CrossAccountId, AccountId> for Runtime {196 impl app_promotion_rpc::AppPromotionApi<Block, BlockNumber, CrossAccountId, AccountId> for Runtime {
modifiedruntime/common/weights.rsdiffbeforeafterboth
121 max_weight_of!(token_owner())121 max_weight_of!(token_owner())
122 }122 }
123
124 fn set_approval_for_all() -> Weight {
125 max_weight_of!(set_approval_for_all())
126 }
123}127}
124128
125#[cfg(feature = "refungible")]129#[cfg(feature = "refungible")]
modifiedtests/src/approve.test.tsdiffbeforeafterboth
604 });604 });
605});605});
606
607describe('Normal user can approve other users to be wallet operator:', () => {
608 let alice: IKeyringPair;
609 let bob: IKeyringPair;
610
611 before(async () => {
612 await usingPlaygrounds(async (helper, privateKey) => {
613 const donor = await privateKey({filename: __filename});
614 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
615 });
616 });
617
618 itSub('[nft] Enable and disable approval', async ({helper}) => {
619 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
620 await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
621 const checkBeforeApprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
622 expect(await checkBeforeApprovalTx()).to.be.false;
623 await helper.nft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, true);
624 const checkAfterApprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
625 expect(await checkAfterApprovalTx()).to.be.true;
626 await helper.nft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, false);
627 const checkAfterDisapprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
628 expect(await checkAfterDisapprovalTx()).to.be.false;
629 });
630
631 itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {
632 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
633 const checkBeforeApprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
634 expect(await checkBeforeApprovalTx()).to.be.false;
635 await helper.rft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, true);
636 const checkAfterApprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
637 expect(await checkAfterApprovalTx()).to.be.true;
638 await helper.rft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, false);
639 const checkAfterDisapprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
640 expect(await checkAfterDisapprovalTx()).to.be.false;
641 });
642});
606643
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
384 { "internalType": "address", "name": "operator", "type": "address" }384 { "internalType": "address", "name": "operator", "type": "address" }
385 ],385 ],
386 "name": "isApprovedForAll",386 "name": "isApprovedForAll",
387 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],387 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
388 "stateMutability": "view",388 "stateMutability": "view",
389 "type": "function"389 "type": "function"
390 },390 },
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
366 { "internalType": "address", "name": "operator", "type": "address" }366 { "internalType": "address", "name": "operator", "type": "address" }
367 ],367 ],
368 "name": "isApprovedForAll",368 "name": "isApprovedForAll",
369 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],369 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
370 "stateMutability": "view",370 "stateMutability": "view",
371 "type": "function"371 "type": "function"
372 },372 },
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
671 /// or in textual repr: approve(address,uint256)671 /// or in textual repr: approve(address,uint256)
672 function approve(address approved, uint256 tokenId) external;672 function approve(address approved, uint256 tokenId) external;
673673
674 /// @notice Sets or unsets the approval of a given operator.
675 /// An operator is allowed to transfer all tokens of the sender on their behalf.
674 /// @dev Not implemented676 /// @param operator Operator
677 /// @param approved Is operator enabled or disabled
675 /// @dev EVM selector for this function is: 0xa22cb465,678 /// @dev EVM selector for this function is: 0xa22cb465,
676 /// or in textual repr: setApprovalForAll(address,bool)679 /// or in textual repr: setApprovalForAll(address,bool)
677 function setApprovalForAll(address operator, bool approved) external;680 function setApprovalForAll(address operator, bool approved) external;
681 /// or in textual repr: getApproved(uint256)684 /// or in textual repr: getApproved(uint256)
682 function getApproved(uint256 tokenId) external view returns (address);685 function getApproved(uint256 tokenId) external view returns (address);
683686
684 /// @dev Not implemented687 /// @notice Tells whether an operator is approved by a given owner.
685 /// @dev EVM selector for this function is: 0xe985e9c5,688 /// @dev EVM selector for this function is: 0xe985e9c5,
686 /// or in textual repr: isApprovedForAll(address,address)689 /// or in textual repr: isApprovedForAll(address,address)
687 function isApprovedForAll(address owner, address operator) external view returns (address);690 function isApprovedForAll(address owner, address operator) external view returns (bool);
688691
689 /// @notice Returns collection helper contract address692 /// @notice Returns collection helper contract address
690 /// @dev EVM selector for this function is: 0x1896cce6,693 /// @dev EVM selector for this function is: 0x1896cce6,
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
668 /// or in textual repr: approve(address,uint256)668 /// or in textual repr: approve(address,uint256)
669 function approve(address approved, uint256 tokenId) external;669 function approve(address approved, uint256 tokenId) external;
670670
671 /// @notice Sets or unsets the approval of a given operator.
672 /// An operator is allowed to transfer all tokens of the sender on their behalf.
671 /// @dev Not implemented673 /// @param operator Operator
674 /// @param approved Is operator enabled or disabled
672 /// @dev EVM selector for this function is: 0xa22cb465,675 /// @dev EVM selector for this function is: 0xa22cb465,
673 /// or in textual repr: setApprovalForAll(address,bool)676 /// or in textual repr: setApprovalForAll(address,bool)
674 function setApprovalForAll(address operator, bool approved) external;677 function setApprovalForAll(address operator, bool approved) external;
678 /// or in textual repr: getApproved(uint256)681 /// or in textual repr: getApproved(uint256)
679 function getApproved(uint256 tokenId) external view returns (address);682 function getApproved(uint256 tokenId) external view returns (address);
680683
681 /// @dev Not implemented684 /// @notice Tells whether an operator is approved by a given owner.
682 /// @dev EVM selector for this function is: 0xe985e9c5,685 /// @dev EVM selector for this function is: 0xe985e9c5,
683 /// or in textual repr: isApprovedForAll(address,address)686 /// or in textual repr: isApprovedForAll(address,address)
684 function isApprovedForAll(address owner, address operator) external view returns (address);687 function isApprovedForAll(address owner, address operator) external view returns (bool);
685688
686 /// @notice Returns collection helper contract address689 /// @notice Returns collection helper contract address
687 /// @dev EVM selector for this function is: 0x1896cce6,690 /// @dev EVM selector for this function is: 0x1896cce6,
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
249 }249 }
250 });250 });
251
252 itEth('Can perform setApprovalForAll()', async ({helper}) => {
253 const owner = await helper.eth.createAccountWithBalance(donor);
254 const operator = helper.eth.createAccount();
255
256 const collection = await helper.nft.mintCollection(minter, {});
257
258 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
259 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
260
261 const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
262 expect(approvedBefore).to.be.equal(false);
263
264 {
265 const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
266
267 expect(result.events.ApprovalForAll).to.be.like({
268 address: collectionAddress,
269 event: 'ApprovalForAll',
270 returnValues: {
271 owner,
272 operator,
273 approved: true,
274 },
275 });
276
277 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
278 expect(approvedAfter).to.be.equal(true);
279 }
280
281 {
282 const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
283
284 expect(result.events.ApprovalForAll).to.be.like({
285 address: collectionAddress,
286 event: 'ApprovalForAll',
287 returnValues: {
288 owner,
289 operator,
290 approved: false,
291 },
292 });
293
294 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
295 expect(approvedAfter).to.be.equal(false);
296 }
297 });
298
299 itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
300 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
301
302 const owner = await helper.eth.createAccountWithBalance(donor);
303 const operator = await helper.eth.createAccountWithBalance(donor, 100n);
304
305 const token = await collection.mintToken(minter, {Ethereum: owner});
306
307 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
308 const contract = helper.ethNativeContract.collection(address, 'nft');
309
310 {
311 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
312 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
313 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
314 const events = result.events.Transfer;
315
316 expect(events).to.be.like({
317 address,
318 event: 'Transfer',
319 returnValues: {
320 from: owner,
321 to: '0x0000000000000000000000000000000000000000',
322 tokenId: token.tokenId.toString(),
323 },
324 });
325 }
326 });
327
328 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
329 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
330
331 const owner = await helper.eth.createAccountWithBalance(donor);
332 const operator = await helper.eth.createAccountWithBalance(donor);
333 const receiver = charlie;
334
335 const token = await collection.mintToken(minter, {Ethereum: owner});
336
337 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
338 const contract = helper.ethNativeContract.collection(address, 'nft');
339
340 {
341 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
342 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
343 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
344 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
345 const event = result.events.Transfer;
346 expect(event).to.be.like({
347 address: helper.ethAddress.fromCollectionId(collection.collectionId),
348 event: 'Transfer',
349 returnValues: {
350 from: owner,
351 to: helper.address.substrateToEth(receiver.address),
352 tokenId: token.tokenId.toString(),
353 },
354 });
355 }
356
357 expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
358 });
251359
252 itEth('Can perform burnFromCross()', async ({helper}) => {360 itEth('Can perform burnFromCross()', async ({helper}) => {
253 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});361 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
823 });931 });
824});932});
933
934describe('Negative tests', () => {
935 let donor: IKeyringPair;
936 let minter: IKeyringPair;
937 let alice: IKeyringPair;
938 let bob: IKeyringPair;
939
940 before(async function() {
941 await usingEthPlaygrounds(async (helper, privateKey) => {
942 donor = await privateKey({filename: __filename});
943 [minter, alice, bob] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
944 });
945 });
946
947 itEth('[negative] Cant perform burn without approval', async ({helper}) => {
948 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
949
950 const owner = bob;
951 const spender = await helper.eth.createAccountWithBalance(donor, 100n);
952
953 const token = await collection.mintToken(minter, {Substrate: owner.address});
954
955 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
956 const contract = helper.ethNativeContract.collection(address, 'nft');
957
958 {
959 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
960 await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
961 }
962 });
963
964 itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
965 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
966 const owner = bob;
967 const receiver = alice;
968
969 const spender = await helper.eth.createAccountWithBalance(donor, 100n);
970
971 const token = await collection.mintToken(minter, {Substrate: owner.address});
972
973 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
974 const contract = helper.ethNativeContract.collection(address, 'nft');
975
976 {
977 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
978 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
979 await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
980 }
981 });
982});
825983
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
169 }169 }
170 });170 });
171
172 itEth('Can perform setApprovalForAll()', async ({helper}) => {
173 const owner = await helper.eth.createAccountWithBalance(donor);
174 const operator = helper.eth.createAccount();
175
176 const collection = await helper.rft.mintCollection(minter, {});
177
178 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
179 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
180
181 const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
182 expect(approvedBefore).to.be.equal(false);
183
184 {
185 const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
186
187 expect(result.events.ApprovalForAll).to.be.like({
188 address: collectionAddress,
189 event: 'ApprovalForAll',
190 returnValues: {
191 owner,
192 operator,
193 approved: true,
194 },
195 });
196
197 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
198 expect(approvedAfter).to.be.equal(true);
199 }
200
201 {
202 const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
203
204 expect(result.events.ApprovalForAll).to.be.like({
205 address: collectionAddress,
206 event: 'ApprovalForAll',
207 returnValues: {
208 owner,
209 operator,
210 approved: false,
211 },
212 });
213
214 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
215 expect(approvedAfter).to.be.equal(false);
216 }
217 });
218
219 itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
220 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
221
222 const owner = await helper.eth.createAccountWithBalance(donor);
223 const operator = await helper.eth.createAccountWithBalance(donor, 100n);
224
225 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
226
227 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
228 const contract = helper.ethNativeContract.collection(address, 'rft');
229
230 {
231 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
232 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
233 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
234 const events = result.events.Transfer;
235
236 expect(events).to.be.like({
237 address,
238 event: 'Transfer',
239 returnValues: {
240 from: owner,
241 to: '0x0000000000000000000000000000000000000000',
242 tokenId: token.tokenId.toString(),
243 },
244 });
245 }
246 });
247
248 itEth('Can perform burn with approve and approvalForAll', async ({helper}) => {
249 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
250
251 const owner = await helper.eth.createAccountWithBalance(donor);
252 const operator = await helper.eth.createAccountWithBalance(donor, 100n);
253
254 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
255
256 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
257 const contract = helper.ethNativeContract.collection(address, 'rft');
258
259 const rftToken = helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner);
260
261 {
262 await rftToken.methods.approve(operator, 15n).send({from: owner});
263 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
264 await rftToken.methods.burnFrom(owner, 10n).send({from: operator});
265 const allowance = await rftToken.methods.allowance(owner, operator).call();
266 expect(allowance).to.be.equal('5');
267 }
268 });
269
270 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
271 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
272
273 const owner = await helper.eth.createAccountWithBalance(donor);
274 const operator = await helper.eth.createAccountWithBalance(donor);
275 const receiver = charlie;
276
277 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
278
279 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
280 const contract = helper.ethNativeContract.collection(address, 'rft');
281
282 {
283 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
284 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
285 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
286 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
287 const event = result.events.Transfer;
288 expect(event).to.be.like({
289 address: helper.ethAddress.fromCollectionId(collection.collectionId),
290 event: 'Transfer',
291 returnValues: {
292 from: owner,
293 to: helper.address.substrateToEth(receiver.address),
294 tokenId: token.tokenId.toString(),
295 },
296 });
297 }
298
299 expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
300 });
171301
172 itEth('Can perform burn()', async ({helper}) => {302 itEth('Can perform burn()', async ({helper}) => {
173 const caller = await helper.eth.createAccountWithBalance(donor);303 const caller = await helper.eth.createAccountWithBalance(donor);
595 });725 });
596});726});
727
728describe('Negative tests', () => {
729 let donor: IKeyringPair;
730 let minter: IKeyringPair;
731 let alice: IKeyringPair;
732
733 before(async function() {
734 await usingEthPlaygrounds(async (helper, privateKey) => {
735 donor = await privateKey({filename: __filename});
736 [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
737 });
738 });
739
740 itEth('[negative] Cant perform burn without approval', async ({helper}) => {
741 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
742
743 const owner = await helper.eth.createAccountWithBalance(donor, 100n);
744 const spender = await helper.eth.createAccountWithBalance(donor, 100n);
745
746 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
747
748 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
749 const contract = helper.ethNativeContract.collection(address, 'rft');
750
751 {
752 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
753 await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
754 }
755 });
756
757 itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
758 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
759 const owner = await helper.eth.createAccountWithBalance(donor, 100n);
760 const receiver = alice;
761
762 const spender = await helper.eth.createAccountWithBalance(donor, 100n);
763
764 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
765
766 const address = helper.ethAddress.fromCollectionId(collection.collectionId);
767 const contract = helper.ethNativeContract.collection(address, 'rft');
768
769 {
770 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
771 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
772 await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
773 }
774 });
775});
597776
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
385 * Not Fungible item data used to mint in Fungible collection.385 * Not Fungible item data used to mint in Fungible collection.
386 **/386 **/
387 NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;387 NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
388 /**
389 * Setting approval for all is not allowed.
390 **/
391 SettingApprovalForAllNotAllowed: AugmentedError<ApiType>;
388 /**392 /**
389 * Setting item properties is not allowed.393 * Setting item properties is not allowed.
390 **/394 **/
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
106 * Amount pieces of token owned by `sender` was approved for `spender`.106 * Amount pieces of token owned by `sender` was approved for `spender`.
107 **/107 **/
108 Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;108 Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
109 /**
110 * Amount pieces of token owned by `sender` was approved for `spender`.
111 **/
112 ApprovedForAll: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
109 /**113 /**
110 * New collection was created114 * New collection was created
111 **/115 **/
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
441 * Total amount of minted tokens in a collection.441 * Total amount of minted tokens in a collection.
442 **/442 **/
443 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;443 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
444 /**
445 * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
446 **/
447 walletOperator: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<Option<bool>>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
444 /**448 /**
445 * Generic query449 * Generic query
446 **/450 **/
644 * Total amount of pieces for token648 * Total amount of pieces for token
645 **/649 **/
646 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;650 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
651 /**
652 * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
653 **/
654 walletOperator: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<Option<bool>>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
647 /**655 /**
648 * Generic query656 * Generic query
649 **/657 **/
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
719 * Get effective collection limits719 * Get effective collection limits
720 **/720 **/
721 effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;721 effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;
722 /**
723 * Tells whether an operator is approved by a given owner.
724 **/
725 isApprovedForAll: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<bool>>>;
722 /**726 /**
723 * Get the last token ID created in a collection727 * Get the last token ID created in a collection
724 **/728 **/
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
1544 * * `amount`: New number of parts/pieces into which the token shall be partitioned.1544 * * `amount`: New number of parts/pieces into which the token shall be partitioned.
1545 **/1545 **/
1546 repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;1546 repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
1547 /**
1548 * Sets or unsets the approval of a given operator.
1549 *
1550 * An operator is allowed to transfer all tokens of the sender on their behalf.
1551 *
1552 * # Arguments
1553 *
1554 * * `owner`: Token owner
1555 * * `operator`: Operator
1556 * * `approve`: Is operator enabled or disabled
1557 **/
1558 setApprovalForAll: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
1547 /**1559 /**
1548 * Set specific limits of a collection. Empty, or None fields mean chain default.1560 * Set specific limits of a collection. Empty, or None fields mean chain default.
1549 * 1561 *
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
1286 readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;1286 readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
1287 readonly isApproved: boolean;1287 readonly isApproved: boolean;
1288 readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;1288 readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
1289 readonly isApprovedForAll: boolean;
1290 readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
1289 readonly isCollectionPropertySet: boolean;1291 readonly isCollectionPropertySet: boolean;
1290 readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;1292 readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
1291 readonly isCollectionPropertyDeleted: boolean;1293 readonly isCollectionPropertyDeleted: boolean;
1296 readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;1298 readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
1297 readonly isPropertyPermissionSet: boolean;1299 readonly isPropertyPermissionSet: boolean;
1298 readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;1300 readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
1299 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';1301 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
1300}1302}
13011303
1302/** @name PalletConfigurationCall */1304/** @name PalletConfigurationCall */
1603 readonly isFungibleItemsDontHaveData: boolean;1605 readonly isFungibleItemsDontHaveData: boolean;
1604 readonly isFungibleDisallowsNesting: boolean;1606 readonly isFungibleDisallowsNesting: boolean;
1605 readonly isSettingPropertiesNotAllowed: boolean;1607 readonly isSettingPropertiesNotAllowed: boolean;
1608 readonly isSettingApprovalForAllNotAllowed: boolean;
1606 readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';1609 readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingApprovalForAllNotAllowed';
1607}1610}
16081611
1609/** @name PalletInflationCall */1612/** @name PalletInflationCall */
2309 readonly tokenId: u32;2312 readonly tokenId: u32;
2310 readonly amount: u128;2313 readonly amount: u128;
2311 } & Struct;2314 } & Struct;
2315 readonly isSetApprovalForAll: boolean;
2316 readonly asSetApprovalForAll: {
2317 readonly collectionId: u32;
2318 readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
2319 readonly approve: bool;
2320 } & Struct;
2312 readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';2321 readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetApprovalForAll';
2313}2322}
23142323
2315/** @name PalletUniqueError */2324/** @name PalletUniqueError */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
1046 ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',1046 ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
1047 Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',1047 Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
1048 Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',1048 Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
1049 ApprovedForAll: '(u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,bool)',
1049 CollectionPropertySet: '(u32,Bytes)',1050 CollectionPropertySet: '(u32,Bytes)',
1050 CollectionPropertyDeleted: '(u32,Bytes)',1051 CollectionPropertyDeleted: '(u32,Bytes)',
1051 TokenPropertySet: '(u32,u32,Bytes)',1052 TokenPropertySet: '(u32,u32,Bytes)',
1052 TokenPropertyDeleted: '(u32,u32,Bytes)',1053 TokenPropertyDeleted: '(u32,u32,Bytes)',
1053 PropertyPermissionSet: '(u32,Bytes)'1054 PropertyPermissionSet: '(u32,Bytes)'
1054 }1055 }
1055 },1056 },
1056 /**1057 /**
1057 * Lookup99: pallet_structure::pallet::Event<T>1058 * Lookup100: pallet_structure::pallet::Event<T>
1058 **/1059 **/
1059 PalletStructureEvent: {1060 PalletStructureEvent: {
1060 _enum: {1061 _enum: {
1061 Executed: 'Result<Null, SpRuntimeDispatchError>'1062 Executed: 'Result<Null, SpRuntimeDispatchError>'
1062 }1063 }
1063 },1064 },
1064 /**1065 /**
1065 * Lookup100: pallet_rmrk_core::pallet::Event<T>1066 * Lookup101: pallet_rmrk_core::pallet::Event<T>
1066 **/1067 **/
1067 PalletRmrkCoreEvent: {1068 PalletRmrkCoreEvent: {
1068 _enum: {1069 _enum: {
1069 CollectionCreated: {1070 CollectionCreated: {
1138 }1139 }
1139 }1140 }
1140 },1141 },
1141 /**1142 /**
1142 * Lookup101: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>1143 * Lookup102: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
1143 **/1144 **/
1144 RmrkTraitsNftAccountIdOrCollectionNftTuple: {1145 RmrkTraitsNftAccountIdOrCollectionNftTuple: {
1145 _enum: {1146 _enum: {
1146 AccountId: 'AccountId32',1147 AccountId: 'AccountId32',
2303 collectionId: 'u32',2304 collectionId: 'u32',
2304 tokenId: 'u32',2305 tokenId: 'u32',
2305 amount: 'u128'2306 amount: 'u128',
2306 }2307 },
2308 set_approval_for_all: {
2309 collectionId: 'u32',
2310 operator: 'PalletEvmAccountBasicCrossAccountIdRepr',
2311 approve: 'bool'
2312 }
2307 }2313 }
2308 },2314 },
2309 /**2315 /**
3445 * Lookup430: pallet_fungible::pallet::Error<T>3451 * Lookup430: pallet_fungible::pallet::Error<T>
3446 **/3452 **/
3447 PalletFungibleError: {3453 PalletFungibleError: {
3448 _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']3454 _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingApprovalForAllNotAllowed']
3449 },3455 },
3450 /**3456 /**
3451 * Lookup431: pallet_refungible::ItemData3457 * Lookup431: pallet_refungible::ItemData
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
1182 readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;1182 readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
1183 readonly isApproved: boolean;1183 readonly isApproved: boolean;
1184 readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;1184 readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
1185 readonly isApprovedForAll: boolean;
1186 readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
1185 readonly isCollectionPropertySet: boolean;1187 readonly isCollectionPropertySet: boolean;
1186 readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;1188 readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
1187 readonly isCollectionPropertyDeleted: boolean;1189 readonly isCollectionPropertyDeleted: boolean;
1192 readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;1194 readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
1193 readonly isPropertyPermissionSet: boolean;1195 readonly isPropertyPermissionSet: boolean;
1194 readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;1196 readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
1195 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';1197 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
1196 }1198 }
11971199
1198 /** @name PalletStructureEvent (99) */1200 /** @name PalletStructureEvent (100) */
1199 interface PalletStructureEvent extends Enum {1201 interface PalletStructureEvent extends Enum {
1200 readonly isExecuted: boolean;1202 readonly isExecuted: boolean;
1201 readonly asExecuted: Result<Null, SpRuntimeDispatchError>;1203 readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
1202 readonly type: 'Executed';1204 readonly type: 'Executed';
1203 }1205 }
12041206
1205 /** @name PalletRmrkCoreEvent (100) */1207 /** @name PalletRmrkCoreEvent (101) */
1206 interface PalletRmrkCoreEvent extends Enum {1208 interface PalletRmrkCoreEvent extends Enum {
1207 readonly isCollectionCreated: boolean;1209 readonly isCollectionCreated: boolean;
1208 readonly asCollectionCreated: {1210 readonly asCollectionCreated: {
1292 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet';1294 readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet';
1293 }1295 }
12941296
1295 /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (101) */1297 /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (102) */
1296 interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum {1298 interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum {
1297 readonly isAccountId: boolean;1299 readonly isAccountId: boolean;
1298 readonly asAccountId: AccountId32;1300 readonly asAccountId: AccountId32;
2539 readonly tokenId: u32;2541 readonly tokenId: u32;
2540 readonly amount: u128;2542 readonly amount: u128;
2541 } & Struct;2543 } & Struct;
2544 readonly isSetApprovalForAll: boolean;
2545 readonly asSetApprovalForAll: {
2546 readonly collectionId: u32;
2547 readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
2548 readonly approve: bool;
2549 } & Struct;
2542 readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';2550 readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetApprovalForAll';
2543 }2551 }
25442552
2545 /** @name UpDataStructsCollectionMode (240) */2553 /** @name UpDataStructsCollectionMode (240) */
3655 readonly isFungibleItemsDontHaveData: boolean;3663 readonly isFungibleItemsDontHaveData: boolean;
3656 readonly isFungibleDisallowsNesting: boolean;3664 readonly isFungibleDisallowsNesting: boolean;
3657 readonly isSettingPropertiesNotAllowed: boolean;3665 readonly isSettingPropertiesNotAllowed: boolean;
3666 readonly isSettingApprovalForAllNotAllowed: boolean;
3658 readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';3667 readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingApprovalForAllNotAllowed';
3659 }3668 }
36603669
3661 /** @name PalletRefungibleItemData (431) */3670 /** @name PalletRefungibleItemData (431) */
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
175 [collectionParam, tokenParam], 175 [collectionParam, tokenParam],
176 'Option<u128>',176 'Option<u128>',
177 ),177 ),
178 isApprovedForAll: fun(
179 'Tells whether an operator is approved by a given owner.',
180 [collectionParam, crossAccountParam('owner'), crossAccountParam('operator')],
181 'Option<bool>',
182 ),
178 },183 },
179};184};
180185
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
1414 return null;1414 return null;
1415 }1415 }
1416
1417 /**
1418 * Tells whether an operator is approved by a given owner.
1419 * @param collectionId ID of collection
1420 * @param owner owner address
1421 * @param operator operator addrees
1422 * @returns true if operator is enabled
1423 */
1424 async isApprovedForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {
1425 return (await this.helper.callRpc('api.rpc.unique.isApprovedForAll', [collectionId, owner, operator])).toJSON();
1426 }
1427
1428 /** Sets or unsets the approval of a given operator.
1429 * An operator is allowed to transfer all tokens of the sender on their behalf.
1430 * @param operator Operator
1431 * @param approved Is operator enabled or disabled
1432 * @returns ```true``` if extrinsic success, otherwise ```false```
1433 */
1434 async setApprovalForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {
1435 const result = await this.helper.executeExtrinsic(
1436 signer,
1437 'api.tx.unique.setApprovalForAll', [collectionId, operator, approved],
1438 true,
1439 );
1440 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');
1441 }
1416}1442}
14171443
14181444