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
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -246,6 +246,16 @@
 		token_id: TokenId,
 		at: Option<BlockHash>,
 	) -> Result<Option<String>>;
+
+	/// Get whether an operator is approved by a given owner.
+	#[method(name = "unique_isApprovedForAll")]
+	fn is_approved_for_all(
+		&self,
+		collection: CollectionId,
+		owner: CrossAccountId,
+		operator: CrossAccountId,
+		at: Option<BlockHash>,
+	) -> Result<bool>;
 }
 
 mod app_promotion_unique_rpc {
@@ -569,6 +579,7 @@
 	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);
 	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);
 	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);
+	pass_method!(is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> bool, unique_api);
 }
 
 impl<C, Block, BlockNumber, CrossAccountId, AccountId>
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -472,6 +472,18 @@
 			u128,
 		),
 
+		/// Amount pieces of token owned by `sender` was approved for `spender`.
+		ApprovedForAll(
+			/// Id of collection to which item is belong.
+			CollectionId,
+			/// Owner of a wallet.
+			T::CrossAccountId,
+			/// Id for which operator status was granted or rewoked.
+			T::CrossAccountId,
+			/// Is operator status was granted or rewoked.
+			bool,
+		),
+
 		/// The colletion property has been added or edited.
 		CollectionPropertySet(
 			/// Id of collection to which property has been set.
@@ -1521,6 +1533,9 @@
 
 	/// The price of retrieving token owner
 	fn token_owner() -> Weight;
+
+	/// The price of setting approval for all
+	fn set_approval_for_all() -> Weight;
 }
 
 /// Weight info extension trait for refungible pallet.
@@ -1828,6 +1843,20 @@
 
 	/// Get extension for RFT collection.
 	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;
+
+	/// An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// * `owner` - Token owner
+	/// * `operator` - Operator
+	/// * `approve` - Is operator enabled or disabled
+	fn set_approval_for_all(
+		&self,
+		owner: T::CrossAccountId,
+		operator: T::CrossAccountId,
+		approve: bool,
+	) -> DispatchResultWithPostInfo;
+
+	/// Tells whether an operator is approved by a given owner.
+	fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;
 }
 
 /// Extension for RFT collection.
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -107,6 +107,10 @@
 	fn token_owner() -> Weight {
 		Weight::zero()
 	}
+
+	fn set_approval_for_all() -> Weight {
+		Weight::zero()
+	}
 }
 
 /// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
@@ -424,4 +428,17 @@
 		}
 		<TotalSupply<T>>::try_get(self.id).ok()
 	}
+
+	fn set_approval_for_all(
+		&self,
+		_owner: T::CrossAccountId,
+		_operator: T::CrossAccountId,
+		_approve: bool,
+	) -> DispatchResultWithPostInfo {
+		fail!(<Error<T>>::SettingApprovalForAllNotAllowed)
+	}
+
+	fn is_approved_for_all(&self, _owner: T::CrossAccountId, _operator: T::CrossAccountId) -> bool {
+		false
+	}
 }
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -127,6 +127,8 @@
 		FungibleDisallowsNesting,
 		/// Setting item properties is not allowed.
 		SettingPropertiesNotAllowed,
+		/// Setting approval for all is not allowed.
+		SettingApprovalForAllNotAllowed,
 	}
 
 	#[pallet::config]
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -222,4 +222,18 @@
 		let item = create_max_item(&collection, &owner, owner.clone())?;
 
 	}: {collection.token_owner(item)}
+
+	set_approval_for_all {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			operator: cross_from_sub(owner); owner: cross_sub;
+		};
+	}: {<Pallet<T>>::set_approval_for_all(&collection, &owner, &operator, true)}
+
+	is_approved_for_all {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			operator: cross_from_sub(owner); owner: cross_sub;
+		};
+	}: {<Pallet<T>>::is_approved_for_all(&collection, &owner, &operator)}
 }
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -122,6 +122,10 @@
 	fn token_owner() -> Weight {
 		<SelfWeightOf<T>>::token_owner()
 	}
+
+	fn set_approval_for_all() -> Weight {
+		<SelfWeightOf<T>>::set_approval_for_all()
+	}
 }
 
 fn map_create_data<T: Config>(
@@ -512,4 +516,20 @@
 			None
 		}
 	}
+
+	fn set_approval_for_all(
+		&self,
+		owner: T::CrossAccountId,
+		operator: T::CrossAccountId,
+		approve: bool,
+	) -> DispatchResultWithPostInfo {
+		with_weight(
+			<Pallet<T>>::set_approval_for_all(self, &owner, &operator, approve),
+			<CommonWeights<T>>::set_approval_for_all(),
+		)
+	}
+
+	fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
+		<Pallet<T>>::is_approved_for_all(self, &owner, &operator)
+	}
 }
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -469,15 +469,23 @@
 		Ok(())
 	}
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
+	#[weight(<SelfWeightOf<T>>::set_approval_for_all())]
 	fn set_approval_for_all(
 		&mut self,
-		_caller: caller,
-		_operator: address,
-		_approved: bool,
+		caller: caller,
+		operator: address,
+		approved: bool,
 	) -> Result<void> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
+		let caller = T::CrossAccountId::from_eth(caller);
+		let operator = T::CrossAccountId::from_eth(operator);
+
+		<Pallet<T>>::set_approval_for_all(self, &caller, &operator, approved)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(())
 	}
 
 	/// @dev Not implemented
@@ -486,10 +494,13 @@
 		Err("not implemented".into())
 	}
 
-	/// @dev Not implemented
-	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
+	/// @notice Tells whether an operator is approved by a given owner.
+	#[weight(<SelfWeightOf<T>>::is_approved_for_all())]
+	fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
+		let owner = T::CrossAccountId::from_eth(owner);
+		let operator = T::CrossAccountId::from_eth(operator);
+
+		Ok(<Pallet<T>>::is_approved_for_all(self, &owner, &operator))
 	}
 
 	/// @notice Returns collection helper contract address
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -272,6 +272,18 @@
 		QueryKind = OptionQuery,
 	>;
 
+	/// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+	#[pallet::storage]
+	pub type WalletOperator<T: Config> = StorageNMap<
+		Key = (
+			Key<Twox64Concat, CollectionId>,
+			Key<Blake2_128Concat, T::CrossAccountId>,
+			Key<Blake2_128Concat, T::CrossAccountId>,
+		),
+		Value = bool,
+		QueryKind = OptionQuery,
+	>;
+
 	/// Upgrade from the old schema to properties.
 	#[pallet::hooks]
 	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
@@ -438,6 +450,7 @@
 		<TokensBurnt<T>>::remove(id);
 		let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);
 		let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);
+		let _ = <WalletOperator<T>>::clear_prefix((id,), u32::MAX, None);
 		Ok(())
 	}
 
@@ -1193,6 +1206,9 @@
 		if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
 			return Ok(());
 		}
+		if <WalletOperator<T>>::get((collection.id, from, spender)) == Some(true) {
+			return Ok(());
+		}
 		ensure!(
 			collection.ignores_allowance(spender),
 			<CommonError<T>>::ApprovedValueTooLow
@@ -1326,4 +1342,52 @@
 	) -> DispatchResult {
 		Self::create_multiple_items(collection, sender, vec![data], nesting_budget)
 	}
+
+	/// Sets or unsets the approval of a given operator.
+	///
+	/// An operator is allowed to transfer all token pieces of the sender on their behalf.
+	/// - `owner`: Token owner
+	/// - `operator`: Operator
+	/// - `approve`: Is operator enabled or disabled
+	pub fn set_approval_for_all(
+		collection: &NonfungibleHandle<T>,
+		owner: &T::CrossAccountId,
+		operator: &T::CrossAccountId,
+		approve: bool,
+	) -> DispatchResult {
+		if collection.permissions.access() == AccessMode::AllowList {
+			collection.check_allowlist(owner)?;
+			collection.check_allowlist(operator)?;
+		}
+
+		<PalletCommon<T>>::ensure_correct_receiver(operator)?;
+
+		// =========
+
+		<WalletOperator<T>>::insert((collection.id, owner, operator), approve);
+		<PalletEvm<T>>::deposit_log(
+			ERC721Events::ApprovalForAll {
+				owner: *owner.as_eth(),
+				operator: *operator.as_eth(),
+				approved: approve,
+			}
+			.to_log(collection_id_to_address(collection.id)),
+		);
+		<PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
+			collection.id,
+			owner.clone(),
+			operator.clone(),
+			approve,
+		));
+		Ok(())
+	}
+
+	/// Tells whether an operator is approved by a given owner.
+	pub fn is_approved_for_all(
+		collection: &NonfungibleHandle<T>,
+		owner: &T::CrossAccountId,
+		operator: &T::CrossAccountId,
+	) -> bool {
+		<WalletOperator<T>>::get((collection.id, owner, operator)).unwrap_or(false)
+	}
 }
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -1020,7 +1020,10 @@
 		dummy = 0;
 	}
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
 	/// @dev EVM selector for this function is: 0xa22cb465,
 	///  or in textual repr: setApprovalForAll(address,bool)
 	function setApprovalForAll(address operator, bool approved) public {
@@ -1040,15 +1043,15 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
-	/// @dev Not implemented
+	/// @notice Tells whether an operator is approved by a given owner.
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) public view returns (address) {
+	function isApprovedForAll(address owner, address operator) public view returns (bool) {
 		require(false, stub_error);
 		owner;
 		operator;
 		dummy;
-		return 0x0000000000000000000000000000000000000000;
+		return false;
 	}
 
 	/// @notice Returns collection helper contract address
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -26,6 +26,7 @@
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
 #![allow(unused_imports)]
+#![allow(missing_docs)]
 #![allow(clippy::unnecessary_cast)]
 
 use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
@@ -47,6 +48,8 @@
 	fn set_token_properties(b: u32, ) -> Weight;
 	fn delete_token_properties(b: u32, ) -> Weight;
 	fn token_owner() -> Weight;
+	fn set_approval_for_all() -> Weight;
+	fn is_approved_for_all() -> Weight;
 }
 
 /// Weights for pallet_nonfungible using the Substrate node and recommended hardware.
@@ -195,6 +198,16 @@
 		Weight::from_ref_time(4_366_000)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 	}
+	// Storage: Nonfungible WalletOperator (r:0 w:1)
+	fn set_approval_for_all() -> Weight {
+		Weight::from_ref_time(16_231_000 as u64)
+			.saturating_add(T::DbWeight::get().writes(1 as u64))
+	}
+	// Storage: Nonfungible WalletOperator (r:1 w:0)
+	fn is_approved_for_all() -> Weight {
+		Weight::from_ref_time(6_161_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
+	}
 }
 
 // For backwards compatibility and tests
@@ -342,4 +355,14 @@
 		Weight::from_ref_time(4_366_000)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 	}
+	// Storage: Nonfungible WalletOperator (r:0 w:1)
+	fn set_approval_for_all() -> Weight {
+		Weight::from_ref_time(16_231_000 as u64)
+			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+	}
+	// Storage: Nonfungible WalletOperator (r:1 w:0)
+	fn is_approved_for_all() -> Weight {
+		Weight::from_ref_time(6_161_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
+	}
 }
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -290,4 +290,18 @@
 		};
 		let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;
 	}: {<Pallet<T>>::token_owner(collection.id, item)}
+
+	set_approval_for_all {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			operator: cross_from_sub(owner); owner: cross_sub;
+		};
+	}: {<Pallet<T>>::set_approval_for_all(&collection, &owner, &operator, true)}
+
+	is_approved_for_all {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			operator: cross_from_sub(owner); owner: cross_sub;
+		};
+	}: {<Pallet<T>>::is_approved_for_all(&collection, &owner, &operator)}
 }
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -152,6 +152,10 @@
 	fn token_owner() -> Weight {
 		<SelfWeightOf<T>>::token_owner()
 	}
+
+	fn set_approval_for_all() -> Weight {
+		<SelfWeightOf<T>>::set_approval_for_all()
+	}
 }
 
 fn map_create_data<T: Config>(
@@ -516,6 +520,22 @@
 	fn total_pieces(&self, token: TokenId) -> Option<u128> {
 		<Pallet<T>>::total_pieces(self.id, token)
 	}
+
+	fn set_approval_for_all(
+		&self,
+		owner: T::CrossAccountId,
+		operator: T::CrossAccountId,
+		approve: bool,
+	) -> DispatchResultWithPostInfo {
+		with_weight(
+			<Pallet<T>>::set_approval_for_all(self, &owner, &operator, approve),
+			<CommonWeights<T>>::set_approval_for_all(),
+		)
+	}
+
+	fn is_approved_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {
+		<Pallet<T>>::is_approved_for_all(self, &owner, &operator)
+	}
 }
 
 impl<T: Config> RefungibleExtensions<T> for RefungibleHandle<T> {
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -461,15 +461,23 @@
 		Err("not implemented".into())
 	}
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
+	#[weight(<SelfWeightOf<T>>::set_approval_for_all())]
 	fn set_approval_for_all(
 		&mut self,
-		_caller: caller,
-		_operator: address,
-		_approved: bool,
+		caller: caller,
+		operator: address,
+		approved: bool,
 	) -> Result<void> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
+		let caller = T::CrossAccountId::from_eth(caller);
+		let operator = T::CrossAccountId::from_eth(operator);
+
+		<Pallet<T>>::set_approval_for_all(self, &caller, &operator, approved)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(())
 	}
 
 	/// @dev Not implemented
@@ -478,10 +486,13 @@
 		Err("not implemented".into())
 	}
 
-	/// @dev Not implemented
-	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
+	/// @notice Tells whether an operator is approved by a given owner.
+	#[weight(<SelfWeightOf<T>>::is_approved_for_all())]
+	fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
+		let owner = T::CrossAccountId::from_eth(owner);
+		let operator = T::CrossAccountId::from_eth(operator);
+
+		Ok(<Pallet<T>>::is_approved_for_all(self, &owner, &operator))
 	}
 
 	/// @notice Returns collection helper contract address
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -273,6 +273,18 @@
 		QueryKind = ValueQuery,
 	>;
 
+	/// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+	#[pallet::storage]
+	pub type WalletOperator<T: Config> = StorageNMap<
+		Key = (
+			Key<Twox64Concat, CollectionId>,
+			Key<Blake2_128Concat, T::CrossAccountId>,
+			Key<Blake2_128Concat, T::CrossAccountId>,
+		),
+		Value = bool,
+		QueryKind = OptionQuery,
+	>;
+
 	#[pallet::hooks]
 	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
 		fn on_runtime_upgrade() -> Weight {
@@ -1161,6 +1173,12 @@
 		}
 		let allowance =
 			<Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);
+
+		// Allowance if any would be reduced if spender is also wallet operator
+		if <WalletOperator<T>>::get((collection.id, from, spender)) == Some(true) {
+			return Ok(allowance);
+		}
+
 		if allowance.is_none() {
 			ensure!(
 				collection.ignores_allowance(spender),
@@ -1387,4 +1405,52 @@
 			Some(res)
 		}
 	}
+
+	/// Sets or unsets the approval of a given operator.
+	///
+	/// An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// - `owner`: Token owner
+	/// - `operator`: Operator
+	/// - `approve`: Is operator enabled or disabled
+	pub fn set_approval_for_all(
+		collection: &RefungibleHandle<T>,
+		owner: &T::CrossAccountId,
+		operator: &T::CrossAccountId,
+		approve: bool,
+	) -> DispatchResult {
+		if collection.permissions.access() == AccessMode::AllowList {
+			collection.check_allowlist(owner)?;
+			collection.check_allowlist(operator)?;
+		}
+
+		<PalletCommon<T>>::ensure_correct_receiver(operator)?;
+
+		// =========
+
+		<WalletOperator<T>>::insert((collection.id, owner, operator), approve);
+		<PalletEvm<T>>::deposit_log(
+			ERC721Events::ApprovalForAll {
+				owner: *owner.as_eth(),
+				operator: *operator.as_eth(),
+				approved: approve,
+			}
+			.to_log(collection_id_to_address(collection.id)),
+		);
+		<PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
+			collection.id,
+			owner.clone(),
+			operator.clone(),
+			approve,
+		));
+		Ok(())
+	}
+
+	/// Tells whether an operator is approved by a given owner.
+	pub fn is_approved_for_all(
+		collection: &RefungibleHandle<T>,
+		owner: &T::CrossAccountId,
+		operator: &T::CrossAccountId,
+	) -> bool {
+		<WalletOperator<T>>::get((collection.id, owner, operator)).unwrap_or(false)
+	}
 }
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -1017,7 +1017,10 @@
 		dummy = 0;
 	}
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
 	/// @dev EVM selector for this function is: 0xa22cb465,
 	///  or in textual repr: setApprovalForAll(address,bool)
 	function setApprovalForAll(address operator, bool approved) public {
@@ -1037,15 +1040,15 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
-	/// @dev Not implemented
+	/// @notice Tells whether an operator is approved by a given owner.
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) public view returns (address) {
+	function isApprovedForAll(address owner, address operator) public view returns (bool) {
 		require(false, stub_error);
 		owner;
 		operator;
 		dummy;
-		return 0x0000000000000000000000000000000000000000;
+		return false;
 	}
 
 	/// @notice Returns collection helper contract address
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -3,7 +3,7 @@
 //! Autogenerated weights for pallet_refungible
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-11-25, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
 
 // Executed Command:
@@ -26,6 +26,7 @@
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
 #![allow(unused_imports)]
+#![allow(missing_docs)]
 #![allow(clippy::unnecessary_cast)]
 
 use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
@@ -54,6 +55,8 @@
 	fn delete_token_properties(b: u32, ) -> Weight;
 	fn repartition_item() -> Weight;
 	fn token_owner() -> Weight;
+	fn set_approval_for_all() -> Weight;
+	fn is_approved_for_all() -> Weight;
 }
 
 /// Weights for pallet_refungible using the Substrate node and recommended hardware.
@@ -259,6 +262,16 @@
 		Weight::from_ref_time(9_431_000)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 	}
+	// Storage: Refungible WalletOperator (r:0 w:1)
+	fn set_approval_for_all() -> Weight {
+		Weight::from_ref_time(16_150_000 as u64)
+			.saturating_add(T::DbWeight::get().writes(1 as u64))
+	}
+	// Storage: Refungible WalletOperator (r:1 w:0)
+	fn is_approved_for_all() -> Weight {
+		Weight::from_ref_time(5_901_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
+	}
 }
 
 // For backwards compatibility and tests
@@ -463,4 +476,14 @@
 		Weight::from_ref_time(9_431_000)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 	}
+	// Storage: Refungible WalletOperator (r:0 w:1)
+	fn set_approval_for_all() -> Weight {
+		Weight::from_ref_time(16_150_000 as u64)
+			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+	}
+	// Storage: Refungible WalletOperator (r:1 w:0)
+	fn is_approved_for_all() -> Weight {
+		Weight::from_ref_time(5_901_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
+	}
 }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -1126,6 +1126,28 @@
 				}
 			})
 		}
+
+		/// Sets or unsets the approval of a given operator.
+		///
+		/// An operator is allowed to transfer all tokens of the sender on their behalf.
+		///
+		/// # Arguments
+		///
+		/// * `owner`: Token owner
+		/// * `operator`: Operator
+		/// * `approve`: Is operator enabled or disabled
+		#[weight = T::CommonWeightInfo::set_approval_for_all()]
+		pub fn set_approval_for_all(
+			origin,
+			collection_id: CollectionId,
+			operator: T::CrossAccountId,
+			approve: bool,
+		) -> DispatchResultWithPostInfo {
+			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
+			dispatch_tx::<T, _>(collection_id, |d| {
+				d.set_approval_for_all(sender, operator, approve)
+			})
+		}
 	}
 }
 
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -132,5 +132,8 @@
 		fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result<Option<u128>>;
 
 		fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
+
+		/// Get whether an operator is approved by a given owner.
+		fn is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result<bool>;
 	}
 }
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -187,6 +187,10 @@
                 fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result<Option<u128>, DispatchError> {
                     dispatch_unique_runtime!(collection.total_pieces(token_id))
                 }
+
+		        fn is_approved_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result<bool, DispatchError> {
+                    dispatch_unique_runtime!(collection.is_approved_for_all(owner, operator))
+                }
             }
 
             impl app_promotion_rpc::AppPromotionApi<Block, BlockNumber, CrossAccountId, AccountId> for Runtime {
modifiedruntime/common/weights.rsdiffbeforeafterboth
--- a/runtime/common/weights.rs
+++ b/runtime/common/weights.rs
@@ -120,6 +120,10 @@
 	fn token_owner() -> Weight {
 		max_weight_of!(token_owner())
 	}
+
+	fn set_approval_for_all() -> Weight {
+		max_weight_of!(set_approval_for_all())
+	}
 }
 
 #[cfg(feature = "refungible")]
modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -603,3 +603,40 @@
     await expect(approveTx()).to.be.rejected;
   });
 });
+
+describe('Normal user can approve other users to be wallet operator:', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({filename: __filename});
+      [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+    });
+  });
+
+  itSub('[nft] Enable and disable approval', async ({helper}) => {
+    const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+    await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+    const checkBeforeApprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkBeforeApprovalTx()).to.be.false;
+    await helper.nft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, true);
+    const checkAfterApprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkAfterApprovalTx()).to.be.true;
+    await helper.nft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, false);
+    const checkAfterDisapprovalTx = () => helper.nft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkAfterDisapprovalTx()).to.be.false;
+  });
+
+  itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {
+    const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+    const checkBeforeApprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkBeforeApprovalTx()).to.be.false;
+    await helper.rft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, true);
+    const checkAfterApprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkAfterApprovalTx()).to.be.true;
+    await helper.rft.setApprovalForAll(alice, collectionId, {Substrate: bob.address}, false);
+    const checkAfterDisapprovalTx = () => helper.rft.isApprovedForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});
+    expect(await checkAfterDisapprovalTx()).to.be.false;
+  });
+});
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -384,7 +384,7 @@
       { "internalType": "address", "name": "operator", "type": "address" }
     ],
     "name": "isApprovedForAll",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "view",
     "type": "function"
   },
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -366,7 +366,7 @@
       { "internalType": "address", "name": "operator", "type": "address" }
     ],
     "name": "isApprovedForAll",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "view",
     "type": "function"
   },
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -671,7 +671,10 @@
 	///  or in textual repr: approve(address,uint256)
 	function approve(address approved, uint256 tokenId) external;
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
 	/// @dev EVM selector for this function is: 0xa22cb465,
 	///  or in textual repr: setApprovalForAll(address,bool)
 	function setApprovalForAll(address operator, bool approved) external;
@@ -681,10 +684,10 @@
 	///  or in textual repr: getApproved(uint256)
 	function getApproved(uint256 tokenId) external view returns (address);
 
-	/// @dev Not implemented
+	/// @notice Tells whether an operator is approved by a given owner.
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) external view returns (address);
+	function isApprovedForAll(address owner, address operator) external view returns (bool);
 
 	/// @notice Returns collection helper contract address
 	/// @dev EVM selector for this function is: 0x1896cce6,
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -668,7 +668,10 @@
 	///  or in textual repr: approve(address,uint256)
 	function approve(address approved, uint256 tokenId) external;
 
-	/// @dev Not implemented
+	/// @notice Sets or unsets the approval of a given operator.
+	///  An operator is allowed to transfer all tokens of the sender on their behalf.
+	/// @param operator Operator
+	/// @param approved Is operator enabled or disabled
 	/// @dev EVM selector for this function is: 0xa22cb465,
 	///  or in textual repr: setApprovalForAll(address,bool)
 	function setApprovalForAll(address operator, bool approved) external;
@@ -678,10 +681,10 @@
 	///  or in textual repr: getApproved(uint256)
 	function getApproved(uint256 tokenId) external view returns (address);
 
-	/// @dev Not implemented
+	/// @notice Tells whether an operator is approved by a given owner.
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) external view returns (address);
+	function isApprovedForAll(address owner, address operator) external view returns (bool);
 
 	/// @notice Returns collection helper contract address
 	/// @dev EVM selector for this function is: 0x1896cce6,
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -249,6 +249,114 @@
     }
   });
 
+  itEth('Can perform setApprovalForAll()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = helper.eth.createAccount();
+
+    const collection = await helper.nft.mintCollection(minter, {});
+
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+    const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
+    expect(approvedBefore).to.be.equal(false);
+
+    {
+      const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+
+      expect(result.events.ApprovalForAll).to.be.like({
+        address: collectionAddress,
+        event: 'ApprovalForAll',
+        returnValues: {
+          owner,
+          operator,
+          approved: true,
+        },
+      });
+
+      const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+      expect(approvedAfter).to.be.equal(true);
+    }
+
+    {
+      const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
+
+      expect(result.events.ApprovalForAll).to.be.like({
+        address: collectionAddress,
+        event: 'ApprovalForAll',
+        returnValues: {
+          owner,
+          operator,
+          approved: false,
+        },
+      });
+
+      const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+      expect(approvedAfter).to.be.equal(false);
+    }
+  });
+
+  itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'nft');
+
+    {
+      await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
+      const events = result.events.Transfer;
+
+      expect(events).to.be.like({
+        address,
+        event: 'Transfer',
+        returnValues: {
+          from: owner,
+          to: '0x0000000000000000000000000000000000000000',
+          tokenId: token.tokenId.toString(),
+        },
+      });
+    }
+  });
+  
+  itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = await helper.eth.createAccountWithBalance(donor);
+    const receiver = charlie;
+
+    const token = await collection.mintToken(minter, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'nft');
+
+    {
+      await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+      const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
+      const event = result.events.Transfer;
+      expect(event).to.be.like({
+        address: helper.ethAddress.fromCollectionId(collection.collectionId),
+        event: 'Transfer',
+        returnValues: {
+          from: owner,
+          to: helper.address.substrateToEth(receiver.address),
+          tokenId: token.tokenId.toString(),
+        },
+      });
+    }
+
+    expect(await token.getOwner()).to.be.like({Substrate: receiver.address});
+  });
+
   itEth('Can perform burnFromCross()', async ({helper}) => {
     const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
     const ownerSub = bob;
@@ -822,3 +930,53 @@
     expect(symbol).to.equal('CHANGE');
   });
 });
+
+describe('Negative tests', () => {
+  let donor: IKeyringPair;
+  let minter: IKeyringPair;
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = await privateKey({filename: __filename});
+      [minter, alice, bob] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+    });
+  });
+
+  itEth('[negative] Cant perform burn without approval', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = bob;
+    const spender = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, {Substrate: owner.address});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'nft');
+
+    {
+      const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+      await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+    }
+  });
+
+  itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+    const owner = bob;
+    const receiver = alice;
+
+    const spender = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, {Substrate: owner.address});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'nft');
+
+    {
+      const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
+      const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+      await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+    }
+  });
+});
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -169,6 +169,136 @@
     }
   });
 
+  itEth('Can perform setApprovalForAll()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = helper.eth.createAccount();
+
+    const collection = await helper.rft.mintCollection(minter, {});
+
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+    const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();
+    expect(approvedBefore).to.be.equal(false);
+
+    {
+      const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+
+      expect(result.events.ApprovalForAll).to.be.like({
+        address: collectionAddress,
+        event: 'ApprovalForAll',
+        returnValues: {
+          owner,
+          operator,
+          approved: true,
+        },
+      });
+
+      const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+      expect(approvedAfter).to.be.equal(true);
+    }
+
+    {
+      const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});
+
+      expect(result.events.ApprovalForAll).to.be.like({
+        address: collectionAddress,
+        event: 'ApprovalForAll',
+        returnValues: {
+          owner,
+          operator,
+          approved: false,
+        },
+      });
+
+      const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();
+      expect(approvedAfter).to.be.equal(false);
+    }
+  });
+
+  itEth('Can perform burn with ApprovalForAll', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'rft');
+
+    {
+      await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});
+      const events = result.events.Transfer;
+
+      expect(events).to.be.like({
+        address,
+        event: 'Transfer',
+        returnValues: {
+          from: owner,
+          to: '0x0000000000000000000000000000000000000000',
+          tokenId: token.tokenId.toString(),
+        },
+      });
+    }
+  });
+
+  itEth('Can perform burn with approve and approvalForAll', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'rft');
+
+    const rftToken = helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner);
+
+    {
+      await rftToken.methods.approve(operator, 15n).send({from: owner});
+      await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+      await rftToken.methods.burnFrom(owner, 10n).send({from: operator});
+      const allowance = await rftToken.methods.allowance(owner, operator).call();
+      expect(allowance).to.be.equal('5');
+    }
+  });
+  
+  itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const operator = await helper.eth.createAccountWithBalance(donor);
+    const receiver = charlie;
+
+    const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'rft');
+
+    {
+      await contract.methods.setApprovalForAll(operator, true).send({from: owner});
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+      const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});
+      const event = result.events.Transfer;
+      expect(event).to.be.like({
+        address: helper.ethAddress.fromCollectionId(collection.collectionId),
+        event: 'Transfer',
+        returnValues: {
+          from: owner,
+          to: helper.address.substrateToEth(receiver.address),
+          tokenId: token.tokenId.toString(),
+        },
+      });
+    }
+
+    expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);
+  });
+
   itEth('Can perform burn()', async ({helper}) => {
     const caller = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6');
@@ -594,3 +724,52 @@
     expect(symbol).to.equal('12');
   });
 });
+
+describe('Negative tests', () => {
+  let donor: IKeyringPair;
+  let minter: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = await privateKey({filename: __filename});
+      [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);
+    });
+  });
+
+  itEth('[negative] Cant perform burn without approval', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+
+    const owner = await helper.eth.createAccountWithBalance(donor, 100n);
+    const spender = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'rft');
+
+    {
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;
+    }
+  });
+
+  itEth('[negative] Cant perform transfer without approval', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+    const owner = await helper.eth.createAccountWithBalance(donor, 100n);
+    const receiver = alice;
+
+    const spender = await helper.eth.createAccountWithBalance(donor, 100n);
+
+    const token = await collection.mintToken(minter, 100n, {Ethereum: owner});
+
+    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(address, 'rft');
+
+    {
+      const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+      const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
+      await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;
+    }
+  });
+});
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
before · tests/src/interfaces/augment-api-errors.ts
1// Auto-generated via `yarn polkadot-types-from-chain`, do not edit2/* eslint-disable */34// import type lookup before we augment - in some environments5// this is required to allow for ambient/previous definitions6import '@polkadot/api-base/types/errors';78import type { ApiTypes, AugmentedError } from '@polkadot/api-base/types';910export type __AugmentedError<ApiType extends ApiTypes> = AugmentedError<ApiType>;1112declare module '@polkadot/api-base/types/errors' {13  interface AugmentedErrors<ApiType extends ApiTypes> {14    appPromotion: {15      /**16       * Error due to action requiring admin to be set.17       **/18      AdminNotSet: AugmentedError<ApiType>;19      /**20       * Errors caused by incorrect actions with a locked balance.21       **/22      IncorrectLockedBalanceOperation: AugmentedError<ApiType>;23      /**24       * No permission to perform an action.25       **/26      NoPermission: AugmentedError<ApiType>;27      /**28       * Insufficient funds to perform an action.29       **/30      NotSufficientFunds: AugmentedError<ApiType>;31      /**32       * Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.33       **/34      PendingForBlockOverflow: AugmentedError<ApiType>;35      /**36       * The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.37       **/38      SponsorNotSet: AugmentedError<ApiType>;39      /**40       * Generic error41       **/42      [key: string]: AugmentedError<ApiType>;43    };44    balances: {45      /**46       * Beneficiary account must pre-exist47       **/48      DeadAccount: AugmentedError<ApiType>;49      /**50       * Value too low to create account due to existential deposit51       **/52      ExistentialDeposit: AugmentedError<ApiType>;53      /**54       * A vesting schedule already exists for this account55       **/56      ExistingVestingSchedule: AugmentedError<ApiType>;57      /**58       * Balance too low to send value59       **/60      InsufficientBalance: AugmentedError<ApiType>;61      /**62       * Transfer/payment would kill account63       **/64      KeepAlive: AugmentedError<ApiType>;65      /**66       * Account liquidity restrictions prevent withdrawal67       **/68      LiquidityRestrictions: AugmentedError<ApiType>;69      /**70       * Number of named reserves exceed MaxReserves71       **/72      TooManyReserves: AugmentedError<ApiType>;73      /**74       * Vesting balance too high to send value75       **/76      VestingBalance: AugmentedError<ApiType>;77      /**78       * Generic error79       **/80      [key: string]: AugmentedError<ApiType>;81    };82    common: {83      /**84       * Account token limit exceeded per collection85       **/86      AccountTokenLimitExceeded: AugmentedError<ApiType>;87      /**88       * Can't transfer tokens to ethereum zero address89       **/90      AddressIsZero: AugmentedError<ApiType>;91      /**92       * Address is not in allow list.93       **/94      AddressNotInAllowlist: AugmentedError<ApiType>;95      /**96       * Requested value is more than the approved97       **/98      ApprovedValueTooLow: AugmentedError<ApiType>;99      /**100       * Tried to approve more than owned101       **/102      CantApproveMoreThanOwned: AugmentedError<ApiType>;103      /**104       * Destroying only empty collections is allowed105       **/106      CantDestroyNotEmptyCollection: AugmentedError<ApiType>;107      /**108       * Exceeded max admin count109       **/110      CollectionAdminCountExceeded: AugmentedError<ApiType>;111      /**112       * Collection description can not be longer than 255 char.113       **/114      CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;115      /**116       * Tried to store more data than allowed in collection field117       **/118      CollectionFieldSizeExceeded: AugmentedError<ApiType>;119      /**120       * Tried to access an external collection with an internal API121       **/122      CollectionIsExternal: AugmentedError<ApiType>;123      /**124       * Tried to access an internal collection with an external API125       **/126      CollectionIsInternal: AugmentedError<ApiType>;127      /**128       * Collection limit bounds per collection exceeded129       **/130      CollectionLimitBoundsExceeded: AugmentedError<ApiType>;131      /**132       * Collection name can not be longer than 63 char.133       **/134      CollectionNameLimitExceeded: AugmentedError<ApiType>;135      /**136       * This collection does not exist.137       **/138      CollectionNotFound: AugmentedError<ApiType>;139      /**140       * Collection token limit exceeded141       **/142      CollectionTokenLimitExceeded: AugmentedError<ApiType>;143      /**144       * Token prefix can not be longer than 15 char.145       **/146      CollectionTokenPrefixLimitExceeded: AugmentedError<ApiType>;147      /**148       * Empty property keys are forbidden149       **/150      EmptyPropertyKey: AugmentedError<ApiType>;151      /**152       * Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed153       **/154      InvalidCharacterInPropertyKey: AugmentedError<ApiType>;155      /**156       * Metadata flag frozen157       **/158      MetadataFlagFrozen: AugmentedError<ApiType>;159      /**160       * Sender parameter and item owner must be equal.161       **/162      MustBeTokenOwner: AugmentedError<ApiType>;163      /**164       * No permission to perform action165       **/166      NoPermission: AugmentedError<ApiType>;167      /**168       * Tried to store more property data than allowed169       **/170      NoSpaceForProperty: AugmentedError<ApiType>;171      /**172       * Insufficient funds to perform an action173       **/174      NotSufficientFounds: AugmentedError<ApiType>;175      /**176       * Tried to enable permissions which are only permitted to be disabled177       **/178      OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;179      /**180       * Property key is too long181       **/182      PropertyKeyIsTooLong: AugmentedError<ApiType>;183      /**184       * Tried to store more property keys than allowed185       **/186      PropertyLimitReached: AugmentedError<ApiType>;187      /**188       * Collection is not in mint mode.189       **/190      PublicMintingNotAllowed: AugmentedError<ApiType>;191      /**192       * Only tokens from specific collections may nest tokens under this one193       **/194      SourceCollectionIsNotAllowedToNest: AugmentedError<ApiType>;195      /**196       * Item does not exist197       **/198      TokenNotFound: AugmentedError<ApiType>;199      /**200       * Item is balance not enough201       **/202      TokenValueTooLow: AugmentedError<ApiType>;203      /**204       * Total collections bound exceeded.205       **/206      TotalCollectionsLimitExceeded: AugmentedError<ApiType>;207      /**208       * Collection settings not allowing items transferring209       **/210      TransferNotAllowed: AugmentedError<ApiType>;211      /**212       * The operation is not supported213       **/214      UnsupportedOperation: AugmentedError<ApiType>;215      /**216       * User does not satisfy the nesting rule217       **/218      UserIsNotAllowedToNest: AugmentedError<ApiType>;219      /**220       * Generic error221       **/222      [key: string]: AugmentedError<ApiType>;223    };224    cumulusXcm: {225      /**226       * Generic error227       **/228      [key: string]: AugmentedError<ApiType>;229    };230    dmpQueue: {231      /**232       * The amount of weight given is possibly not enough for executing the message.233       **/234      OverLimit: AugmentedError<ApiType>;235      /**236       * The message index given is unknown.237       **/238      Unknown: AugmentedError<ApiType>;239      /**240       * Generic error241       **/242      [key: string]: AugmentedError<ApiType>;243    };244    ethereum: {245      /**246       * Signature is invalid.247       **/248      InvalidSignature: AugmentedError<ApiType>;249      /**250       * Pre-log is present, therefore transact is not allowed.251       **/252      PreLogExists: AugmentedError<ApiType>;253      /**254       * Generic error255       **/256      [key: string]: AugmentedError<ApiType>;257    };258    evm: {259      /**260       * Not enough balance to perform action261       **/262      BalanceLow: AugmentedError<ApiType>;263      /**264       * Calculating total fee overflowed265       **/266      FeeOverflow: AugmentedError<ApiType>;267      /**268       * Gas limit is too high.269       **/270      GasLimitTooHigh: AugmentedError<ApiType>;271      /**272       * Gas limit is too low.273       **/274      GasLimitTooLow: AugmentedError<ApiType>;275      /**276       * Gas price is too low.277       **/278      GasPriceTooLow: AugmentedError<ApiType>;279      /**280       * Nonce is invalid281       **/282      InvalidNonce: AugmentedError<ApiType>;283      /**284       * Calculating total payment overflowed285       **/286      PaymentOverflow: AugmentedError<ApiType>;287      /**288       * EVM reentrancy289       **/290      Reentrancy: AugmentedError<ApiType>;291      /**292       * Undefined error.293       **/294      Undefined: AugmentedError<ApiType>;295      /**296       * Withdraw fee failed297       **/298      WithdrawFailed: AugmentedError<ApiType>;299      /**300       * Generic error301       **/302      [key: string]: AugmentedError<ApiType>;303    };304    evmCoderSubstrate: {305      OutOfFund: AugmentedError<ApiType>;306      OutOfGas: AugmentedError<ApiType>;307      /**308       * Generic error309       **/310      [key: string]: AugmentedError<ApiType>;311    };312    evmContractHelpers: {313      /**314       * No pending sponsor for contract.315       **/316      NoPendingSponsor: AugmentedError<ApiType>;317      /**318       * This method is only executable by contract owner319       **/320      NoPermission: AugmentedError<ApiType>;321      /**322       * Number of methods that sponsored limit is defined for exceeds maximum.323       **/324      TooManyMethodsHaveSponsoredLimit: AugmentedError<ApiType>;325      /**326       * Generic error327       **/328      [key: string]: AugmentedError<ApiType>;329    };330    evmMigration: {331      /**332       * Migration of this account is not yet started, or already finished.333       **/334      AccountIsNotMigrating: AugmentedError<ApiType>;335      /**336       * Can only migrate to empty address.337       **/338      AccountNotEmpty: AugmentedError<ApiType>;339      /**340       * Failed to decode event bytes341       **/342      BadEvent: AugmentedError<ApiType>;343      /**344       * Generic error345       **/346      [key: string]: AugmentedError<ApiType>;347    };348    foreignAssets: {349      /**350       * AssetId exists351       **/352      AssetIdExisted: AugmentedError<ApiType>;353      /**354       * AssetId not exists355       **/356      AssetIdNotExists: AugmentedError<ApiType>;357      /**358       * The given location could not be used (e.g. because it cannot be expressed in the359       * desired version of XCM).360       **/361      BadLocation: AugmentedError<ApiType>;362      /**363       * MultiLocation existed364       **/365      MultiLocationExisted: AugmentedError<ApiType>;366      /**367       * Generic error368       **/369      [key: string]: AugmentedError<ApiType>;370    };371    fungible: {372      /**373       * Fungible token does not support nesting.374       **/375      FungibleDisallowsNesting: AugmentedError<ApiType>;376      /**377       * Tried to set data for fungible item.378       **/379      FungibleItemsDontHaveData: AugmentedError<ApiType>;380      /**381       * Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.382       **/383      FungibleItemsHaveNoId: AugmentedError<ApiType>;384      /**385       * Not Fungible item data used to mint in Fungible collection.386       **/387      NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;388      /**389       * Setting item properties is not allowed.390       **/391      SettingPropertiesNotAllowed: AugmentedError<ApiType>;392      /**393       * Generic error394       **/395      [key: string]: AugmentedError<ApiType>;396    };397    maintenance: {398      /**399       * Generic error400       **/401      [key: string]: AugmentedError<ApiType>;402    };403    nonfungible: {404      /**405       * Unable to burn NFT with children406       **/407      CantBurnNftWithChildren: AugmentedError<ApiType>;408      /**409       * Used amount > 1 with NFT410       **/411      NonfungibleItemsHaveNoAmount: AugmentedError<ApiType>;412      /**413       * Not Nonfungible item data used to mint in Nonfungible collection.414       **/415      NotNonfungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;416      /**417       * Generic error418       **/419      [key: string]: AugmentedError<ApiType>;420    };421    parachainSystem: {422      /**423       * The inherent which supplies the host configuration did not run this block424       **/425      HostConfigurationNotAvailable: AugmentedError<ApiType>;426      /**427       * No code upgrade has been authorized.428       **/429      NothingAuthorized: AugmentedError<ApiType>;430      /**431       * No validation function upgrade is currently scheduled.432       **/433      NotScheduled: AugmentedError<ApiType>;434      /**435       * Attempt to upgrade validation function while existing upgrade pending436       **/437      OverlappingUpgrades: AugmentedError<ApiType>;438      /**439       * Polkadot currently prohibits this parachain from upgrading its validation function440       **/441      ProhibitedByPolkadot: AugmentedError<ApiType>;442      /**443       * The supplied validation function has compiled into a blob larger than Polkadot is444       * willing to run445       **/446      TooBig: AugmentedError<ApiType>;447      /**448       * The given code upgrade has not been authorized.449       **/450      Unauthorized: AugmentedError<ApiType>;451      /**452       * The inherent which supplies the validation data did not run this block453       **/454      ValidationDataNotAvailable: AugmentedError<ApiType>;455      /**456       * Generic error457       **/458      [key: string]: AugmentedError<ApiType>;459    };460    polkadotXcm: {461      /**462       * The location is invalid since it already has a subscription from us.463       **/464      AlreadySubscribed: AugmentedError<ApiType>;465      /**466       * The given location could not be used (e.g. because it cannot be expressed in the467       * desired version of XCM).468       **/469      BadLocation: AugmentedError<ApiType>;470      /**471       * The version of the `Versioned` value used is not able to be interpreted.472       **/473      BadVersion: AugmentedError<ApiType>;474      /**475       * Could not re-anchor the assets to declare the fees for the destination chain.476       **/477      CannotReanchor: AugmentedError<ApiType>;478      /**479       * The destination `MultiLocation` provided cannot be inverted.480       **/481      DestinationNotInvertible: AugmentedError<ApiType>;482      /**483       * The assets to be sent are empty.484       **/485      Empty: AugmentedError<ApiType>;486      /**487       * The message execution fails the filter.488       **/489      Filtered: AugmentedError<ApiType>;490      /**491       * Origin is invalid for sending.492       **/493      InvalidOrigin: AugmentedError<ApiType>;494      /**495       * The referenced subscription could not be found.496       **/497      NoSubscription: AugmentedError<ApiType>;498      /**499       * There was some other issue (i.e. not to do with routing) in sending the message. Perhaps500       * a lack of space for buffering the message.501       **/502      SendFailure: AugmentedError<ApiType>;503      /**504       * Too many assets have been attempted for transfer.505       **/506      TooManyAssets: AugmentedError<ApiType>;507      /**508       * The desired destination was unreachable, generally because there is a no way of routing509       * to it.510       **/511      Unreachable: AugmentedError<ApiType>;512      /**513       * The message's weight could not be determined.514       **/515      UnweighableMessage: AugmentedError<ApiType>;516      /**517       * Generic error518       **/519      [key: string]: AugmentedError<ApiType>;520    };521    refungible: {522      /**523       * Not Refungible item data used to mint in Refungible collection.524       **/525      NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;526      /**527       * Refungible token can't nest other tokens.528       **/529      RefungibleDisallowsNesting: AugmentedError<ApiType>;530      /**531       * Refungible token can't be repartitioned by user who isn't owns all pieces.532       **/533      RepartitionWhileNotOwningAllPieces: AugmentedError<ApiType>;534      /**535       * Setting item properties is not allowed.536       **/537      SettingPropertiesNotAllowed: AugmentedError<ApiType>;538      /**539       * Maximum refungibility exceeded.540       **/541      WrongRefungiblePieces: AugmentedError<ApiType>;542      /**543       * Generic error544       **/545      [key: string]: AugmentedError<ApiType>;546    };547    rmrkCore: {548      /**549       * Not the target owner of the sent NFT.550       **/551      CannotAcceptNonOwnedNft: AugmentedError<ApiType>;552      /**553       * Not the target owner of the sent NFT.554       **/555      CannotRejectNonOwnedNft: AugmentedError<ApiType>;556      /**557       * NFT was not sent and is not pending.558       **/559      CannotRejectNonPendingNft: AugmentedError<ApiType>;560      /**561       * If an NFT is sent to a descendant, that would form a nesting loop, an ouroboros.562       * Sending to self is redundant.563       **/564      CannotSendToDescendentOrSelf: AugmentedError<ApiType>;565      /**566       * Too many tokens created in the collection, no new ones are allowed.567       **/568      CollectionFullOrLocked: AugmentedError<ApiType>;569      /**570       * Only destroying collections without tokens is allowed.571       **/572      CollectionNotEmpty: AugmentedError<ApiType>;573      /**574       * Collection does not exist, has a wrong type, or does not map to a Unique ID.575       **/576      CollectionUnknown: AugmentedError<ApiType>;577      /**578       * Property of the type of RMRK collection could not be read successfully.579       **/580      CorruptedCollectionType: AugmentedError<ApiType>;581      /**582       * Could not find an ID for a collection. It is likely there were too many collections created on the chain, causing an overflow.583       **/584      NoAvailableCollectionId: AugmentedError<ApiType>;585      /**586       * Token does not exist, or there is no suitable ID for it, likely too many tokens were created in a collection, causing an overflow.587       **/588      NoAvailableNftId: AugmentedError<ApiType>;589      /**590       * Could not find an ID for the resource. It is likely there were too many resources created on an NFT, causing an overflow.591       **/592      NoAvailableResourceId: AugmentedError<ApiType>;593      /**594       * Token is marked as non-transferable, and thus cannot be transferred.595       **/596      NonTransferable: AugmentedError<ApiType>;597      /**598       * No permission to perform action.599       **/600      NoPermission: AugmentedError<ApiType>;601      /**602       * No such resource found.603       **/604      ResourceDoesntExist: AugmentedError<ApiType>;605      /**606       * Resource is not pending for the operation.607       **/608      ResourceNotPending: AugmentedError<ApiType>;609      /**610       * Could not find a property by the supplied key.611       **/612      RmrkPropertyIsNotFound: AugmentedError<ApiType>;613      /**614       * Too many symbols supplied as the property key. The maximum is [256](up_data_structs::MAX_PROPERTY_KEY_LENGTH).615       **/616      RmrkPropertyKeyIsTooLong: AugmentedError<ApiType>;617      /**618       * Too many bytes supplied as the property value. The maximum is [32768](up_data_structs::MAX_PROPERTY_VALUE_LENGTH).619       **/620      RmrkPropertyValueIsTooLong: AugmentedError<ApiType>;621      /**622       * Something went wrong when decoding encoded data from the storage.623       * Perhaps, there was a wrong key supplied for the type, or the data was improperly stored.624       **/625      UnableToDecodeRmrkData: AugmentedError<ApiType>;626      /**627       * Generic error628       **/629      [key: string]: AugmentedError<ApiType>;630    };631    rmrkEquip: {632      /**633       * Base collection linked to this ID does not exist.634       **/635      BaseDoesntExist: AugmentedError<ApiType>;636      /**637       * No Theme named "default" is associated with the Base.638       **/639      NeedsDefaultThemeFirst: AugmentedError<ApiType>;640      /**641       * Could not find an ID for a Base collection. It is likely there were too many collections created on the chain, causing an overflow.642       **/643      NoAvailableBaseId: AugmentedError<ApiType>;644      /**645       * Could not find a suitable ID for a Part, likely too many Part tokens were created in the Base, causing an overflow646       **/647      NoAvailablePartId: AugmentedError<ApiType>;648      /**649       * Cannot assign equippables to a fixed Part.650       **/651      NoEquippableOnFixedPart: AugmentedError<ApiType>;652      /**653       * Part linked to this ID does not exist.654       **/655      PartDoesntExist: AugmentedError<ApiType>;656      /**657       * No permission to perform action.658       **/659      PermissionError: AugmentedError<ApiType>;660      /**661       * Generic error662       **/663      [key: string]: AugmentedError<ApiType>;664    };665    scheduler: {666      /**667       * There is no place for a new task in the agenda668       **/669      AgendaIsExhausted: AugmentedError<ApiType>;670      /**671       * Failed to schedule a call672       **/673      FailedToSchedule: AugmentedError<ApiType>;674      /**675       * Attempt to use a non-named function on a named task.676       **/677      Named: AugmentedError<ApiType>;678      /**679       * Cannot find the scheduled call.680       **/681      NotFound: AugmentedError<ApiType>;682      /**683       * Scheduled call preimage is not found684       **/685      PreimageNotFound: AugmentedError<ApiType>;686      /**687       * Scheduled call is corrupted688       **/689      ScheduledCallCorrupted: AugmentedError<ApiType>;690      /**691       * Given target block number is in the past.692       **/693      TargetBlockNumberInPast: AugmentedError<ApiType>;694      /**695       * Scheduled call is too big696       **/697      TooBigScheduledCall: AugmentedError<ApiType>;698      /**699       * Generic error700       **/701      [key: string]: AugmentedError<ApiType>;702    };703    structure: {704      /**705       * While nesting, reached the breadth limit of nesting, exceeding the provided budget.706       **/707      BreadthLimit: AugmentedError<ApiType>;708      /**709       * While nesting, reached the depth limit of nesting, exceeding the provided budget.710       **/711      DepthLimit: AugmentedError<ApiType>;712      /**713       * While nesting, encountered an already checked account, detecting a loop.714       **/715      OuroborosDetected: AugmentedError<ApiType>;716      /**717       * Couldn't find the token owner that is itself a token.718       **/719      TokenNotFound: AugmentedError<ApiType>;720      /**721       * Generic error722       **/723      [key: string]: AugmentedError<ApiType>;724    };725    sudo: {726      /**727       * Sender must be the Sudo account728       **/729      RequireSudo: AugmentedError<ApiType>;730      /**731       * Generic error732       **/733      [key: string]: AugmentedError<ApiType>;734    };735    system: {736      /**737       * The origin filter prevent the call to be dispatched.738       **/739      CallFiltered: AugmentedError<ApiType>;740      /**741       * Failed to extract the runtime version from the new runtime.742       * 743       * Either calling `Core_version` or decoding `RuntimeVersion` failed.744       **/745      FailedToExtractRuntimeVersion: AugmentedError<ApiType>;746      /**747       * The name of specification does not match between the current runtime748       * and the new runtime.749       **/750      InvalidSpecName: AugmentedError<ApiType>;751      /**752       * Suicide called when the account has non-default composite data.753       **/754      NonDefaultComposite: AugmentedError<ApiType>;755      /**756       * There is a non-zero reference count preventing the account from being purged.757       **/758      NonZeroRefCount: AugmentedError<ApiType>;759      /**760       * The specification version is not allowed to decrease between the current runtime761       * and the new runtime.762       **/763      SpecVersionNeedsToIncrease: AugmentedError<ApiType>;764      /**765       * Generic error766       **/767      [key: string]: AugmentedError<ApiType>;768    };769    testUtils: {770      TestPalletDisabled: AugmentedError<ApiType>;771      TriggerRollback: AugmentedError<ApiType>;772      /**773       * Generic error774       **/775      [key: string]: AugmentedError<ApiType>;776    };777    tokens: {778      /**779       * Cannot convert Amount into Balance type780       **/781      AmountIntoBalanceFailed: AugmentedError<ApiType>;782      /**783       * The balance is too low784       **/785      BalanceTooLow: AugmentedError<ApiType>;786      /**787       * Beneficiary account must pre-exist788       **/789      DeadAccount: AugmentedError<ApiType>;790      /**791       * Value too low to create account due to existential deposit792       **/793      ExistentialDeposit: AugmentedError<ApiType>;794      /**795       * Transfer/payment would kill account796       **/797      KeepAlive: AugmentedError<ApiType>;798      /**799       * Failed because liquidity restrictions due to locking800       **/801      LiquidityRestrictions: AugmentedError<ApiType>;802      /**803       * Failed because the maximum locks was exceeded804       **/805      MaxLocksExceeded: AugmentedError<ApiType>;806      TooManyReserves: AugmentedError<ApiType>;807      /**808       * Generic error809       **/810      [key: string]: AugmentedError<ApiType>;811    };812    treasury: {813      /**814       * The spend origin is valid but the amount it is allowed to spend is lower than the815       * amount to be spent.816       **/817      InsufficientPermission: AugmentedError<ApiType>;818      /**819       * Proposer's balance is too low.820       **/821      InsufficientProposersBalance: AugmentedError<ApiType>;822      /**823       * No proposal or bounty at that index.824       **/825      InvalidIndex: AugmentedError<ApiType>;826      /**827       * Proposal has not been approved.828       **/829      ProposalNotApproved: AugmentedError<ApiType>;830      /**831       * Too many approvals in the queue.832       **/833      TooManyApprovals: AugmentedError<ApiType>;834      /**835       * Generic error836       **/837      [key: string]: AugmentedError<ApiType>;838    };839    unique: {840      /**841       * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].842       **/843      CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;844      /**845       * This address is not set as sponsor, use setCollectionSponsor first.846       **/847      ConfirmUnsetSponsorFail: AugmentedError<ApiType>;848      /**849       * Length of items properties must be greater than 0.850       **/851      EmptyArgument: AugmentedError<ApiType>;852      /**853       * Repertition is only supported by refungible collection.854       **/855      RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;856      /**857       * Generic error858       **/859      [key: string]: AugmentedError<ApiType>;860    };861    vesting: {862      /**863       * The vested transfer amount is too low864       **/865      AmountLow: AugmentedError<ApiType>;866      /**867       * Insufficient amount of balance to lock868       **/869      InsufficientBalanceToLock: AugmentedError<ApiType>;870      /**871       * Failed because the maximum vesting schedules was exceeded872       **/873      MaxVestingSchedulesExceeded: AugmentedError<ApiType>;874      /**875       * This account have too many vesting schedules876       **/877      TooManyVestingSchedules: AugmentedError<ApiType>;878      /**879       * Vesting period is zero880       **/881      ZeroVestingPeriod: AugmentedError<ApiType>;882      /**883       * Number of vests is zero884       **/885      ZeroVestingPeriodCount: AugmentedError<ApiType>;886      /**887       * Generic error888       **/889      [key: string]: AugmentedError<ApiType>;890    };891    xcmpQueue: {892      /**893       * Bad overweight index.894       **/895      BadOverweightIndex: AugmentedError<ApiType>;896      /**897       * Bad XCM data.898       **/899      BadXcm: AugmentedError<ApiType>;900      /**901       * Bad XCM origin.902       **/903      BadXcmOrigin: AugmentedError<ApiType>;904      /**905       * Failed to send XCM message.906       **/907      FailedToSend: AugmentedError<ApiType>;908      /**909       * Provided weight is possibly not enough to execute the message.910       **/911      WeightOverLimit: AugmentedError<ApiType>;912      /**913       * Generic error914       **/915      [key: string]: AugmentedError<ApiType>;916    };917    xTokens: {918      /**919       * Asset has no reserve location.920       **/921      AssetHasNoReserve: AugmentedError<ApiType>;922      /**923       * The specified index does not exist in a MultiAssets struct.924       **/925      AssetIndexNonExistent: AugmentedError<ApiType>;926      /**927       * The version of the `Versioned` value used is not able to be928       * interpreted.929       **/930      BadVersion: AugmentedError<ApiType>;931      /**932       * Could not re-anchor the assets to declare the fees for the933       * destination chain.934       **/935      CannotReanchor: AugmentedError<ApiType>;936      /**937       * The destination `MultiLocation` provided cannot be inverted.938       **/939      DestinationNotInvertible: AugmentedError<ApiType>;940      /**941       * We tried sending distinct asset and fee but they have different942       * reserve chains.943       **/944      DistinctReserveForAssetAndFee: AugmentedError<ApiType>;945      /**946       * Fee is not enough.947       **/948      FeeNotEnough: AugmentedError<ApiType>;949      /**950       * Could not get ancestry of asset reserve location.951       **/952      InvalidAncestry: AugmentedError<ApiType>;953      /**954       * The MultiAsset is invalid.955       **/956      InvalidAsset: AugmentedError<ApiType>;957      /**958       * Invalid transfer destination.959       **/960      InvalidDest: AugmentedError<ApiType>;961      /**962       * MinXcmFee not registered for certain reserve location963       **/964      MinXcmFeeNotDefined: AugmentedError<ApiType>;965      /**966       * Not cross-chain transfer.967       **/968      NotCrossChainTransfer: AugmentedError<ApiType>;969      /**970       * Currency is not cross-chain transferable.971       **/972      NotCrossChainTransferableCurrency: AugmentedError<ApiType>;973      /**974       * Not supported MultiLocation975       **/976      NotSupportedMultiLocation: AugmentedError<ApiType>;977      /**978       * The number of assets to be sent is over the maximum.979       **/980      TooManyAssetsBeingSent: AugmentedError<ApiType>;981      /**982       * The message's weight could not be determined.983       **/984      UnweighableMessage: AugmentedError<ApiType>;985      /**986       * XCM execution failed.987       **/988      XcmExecutionFailed: AugmentedError<ApiType>;989      /**990       * The transfering asset amount is zero.991       **/992      ZeroAmount: AugmentedError<ApiType>;993      /**994       * The fee is zero.995       **/996      ZeroFee: AugmentedError<ApiType>;997      /**998       * Generic error999       **/1000      [key: string]: AugmentedError<ApiType>;1001    };1002  } // AugmentedErrors1003} // declare module
after · tests/src/interfaces/augment-api-errors.ts
1// Auto-generated via `yarn polkadot-types-from-chain`, do not edit2/* eslint-disable */34// import type lookup before we augment - in some environments5// this is required to allow for ambient/previous definitions6import '@polkadot/api-base/types/errors';78import type { ApiTypes, AugmentedError } from '@polkadot/api-base/types';910export type __AugmentedError<ApiType extends ApiTypes> = AugmentedError<ApiType>;1112declare module '@polkadot/api-base/types/errors' {13  interface AugmentedErrors<ApiType extends ApiTypes> {14    appPromotion: {15      /**16       * Error due to action requiring admin to be set.17       **/18      AdminNotSet: AugmentedError<ApiType>;19      /**20       * Errors caused by incorrect actions with a locked balance.21       **/22      IncorrectLockedBalanceOperation: AugmentedError<ApiType>;23      /**24       * No permission to perform an action.25       **/26      NoPermission: AugmentedError<ApiType>;27      /**28       * Insufficient funds to perform an action.29       **/30      NotSufficientFunds: AugmentedError<ApiType>;31      /**32       * Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.33       **/34      PendingForBlockOverflow: AugmentedError<ApiType>;35      /**36       * The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.37       **/38      SponsorNotSet: AugmentedError<ApiType>;39      /**40       * Generic error41       **/42      [key: string]: AugmentedError<ApiType>;43    };44    balances: {45      /**46       * Beneficiary account must pre-exist47       **/48      DeadAccount: AugmentedError<ApiType>;49      /**50       * Value too low to create account due to existential deposit51       **/52      ExistentialDeposit: AugmentedError<ApiType>;53      /**54       * A vesting schedule already exists for this account55       **/56      ExistingVestingSchedule: AugmentedError<ApiType>;57      /**58       * Balance too low to send value59       **/60      InsufficientBalance: AugmentedError<ApiType>;61      /**62       * Transfer/payment would kill account63       **/64      KeepAlive: AugmentedError<ApiType>;65      /**66       * Account liquidity restrictions prevent withdrawal67       **/68      LiquidityRestrictions: AugmentedError<ApiType>;69      /**70       * Number of named reserves exceed MaxReserves71       **/72      TooManyReserves: AugmentedError<ApiType>;73      /**74       * Vesting balance too high to send value75       **/76      VestingBalance: AugmentedError<ApiType>;77      /**78       * Generic error79       **/80      [key: string]: AugmentedError<ApiType>;81    };82    common: {83      /**84       * Account token limit exceeded per collection85       **/86      AccountTokenLimitExceeded: AugmentedError<ApiType>;87      /**88       * Can't transfer tokens to ethereum zero address89       **/90      AddressIsZero: AugmentedError<ApiType>;91      /**92       * Address is not in allow list.93       **/94      AddressNotInAllowlist: AugmentedError<ApiType>;95      /**96       * Requested value is more than the approved97       **/98      ApprovedValueTooLow: AugmentedError<ApiType>;99      /**100       * Tried to approve more than owned101       **/102      CantApproveMoreThanOwned: AugmentedError<ApiType>;103      /**104       * Destroying only empty collections is allowed105       **/106      CantDestroyNotEmptyCollection: AugmentedError<ApiType>;107      /**108       * Exceeded max admin count109       **/110      CollectionAdminCountExceeded: AugmentedError<ApiType>;111      /**112       * Collection description can not be longer than 255 char.113       **/114      CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;115      /**116       * Tried to store more data than allowed in collection field117       **/118      CollectionFieldSizeExceeded: AugmentedError<ApiType>;119      /**120       * Tried to access an external collection with an internal API121       **/122      CollectionIsExternal: AugmentedError<ApiType>;123      /**124       * Tried to access an internal collection with an external API125       **/126      CollectionIsInternal: AugmentedError<ApiType>;127      /**128       * Collection limit bounds per collection exceeded129       **/130      CollectionLimitBoundsExceeded: AugmentedError<ApiType>;131      /**132       * Collection name can not be longer than 63 char.133       **/134      CollectionNameLimitExceeded: AugmentedError<ApiType>;135      /**136       * This collection does not exist.137       **/138      CollectionNotFound: AugmentedError<ApiType>;139      /**140       * Collection token limit exceeded141       **/142      CollectionTokenLimitExceeded: AugmentedError<ApiType>;143      /**144       * Token prefix can not be longer than 15 char.145       **/146      CollectionTokenPrefixLimitExceeded: AugmentedError<ApiType>;147      /**148       * Empty property keys are forbidden149       **/150      EmptyPropertyKey: AugmentedError<ApiType>;151      /**152       * Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed153       **/154      InvalidCharacterInPropertyKey: AugmentedError<ApiType>;155      /**156       * Metadata flag frozen157       **/158      MetadataFlagFrozen: AugmentedError<ApiType>;159      /**160       * Sender parameter and item owner must be equal.161       **/162      MustBeTokenOwner: AugmentedError<ApiType>;163      /**164       * No permission to perform action165       **/166      NoPermission: AugmentedError<ApiType>;167      /**168       * Tried to store more property data than allowed169       **/170      NoSpaceForProperty: AugmentedError<ApiType>;171      /**172       * Insufficient funds to perform an action173       **/174      NotSufficientFounds: AugmentedError<ApiType>;175      /**176       * Tried to enable permissions which are only permitted to be disabled177       **/178      OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;179      /**180       * Property key is too long181       **/182      PropertyKeyIsTooLong: AugmentedError<ApiType>;183      /**184       * Tried to store more property keys than allowed185       **/186      PropertyLimitReached: AugmentedError<ApiType>;187      /**188       * Collection is not in mint mode.189       **/190      PublicMintingNotAllowed: AugmentedError<ApiType>;191      /**192       * Only tokens from specific collections may nest tokens under this one193       **/194      SourceCollectionIsNotAllowedToNest: AugmentedError<ApiType>;195      /**196       * Item does not exist197       **/198      TokenNotFound: AugmentedError<ApiType>;199      /**200       * Item is balance not enough201       **/202      TokenValueTooLow: AugmentedError<ApiType>;203      /**204       * Total collections bound exceeded.205       **/206      TotalCollectionsLimitExceeded: AugmentedError<ApiType>;207      /**208       * Collection settings not allowing items transferring209       **/210      TransferNotAllowed: AugmentedError<ApiType>;211      /**212       * The operation is not supported213       **/214      UnsupportedOperation: AugmentedError<ApiType>;215      /**216       * User does not satisfy the nesting rule217       **/218      UserIsNotAllowedToNest: AugmentedError<ApiType>;219      /**220       * Generic error221       **/222      [key: string]: AugmentedError<ApiType>;223    };224    cumulusXcm: {225      /**226       * Generic error227       **/228      [key: string]: AugmentedError<ApiType>;229    };230    dmpQueue: {231      /**232       * The amount of weight given is possibly not enough for executing the message.233       **/234      OverLimit: AugmentedError<ApiType>;235      /**236       * The message index given is unknown.237       **/238      Unknown: AugmentedError<ApiType>;239      /**240       * Generic error241       **/242      [key: string]: AugmentedError<ApiType>;243    };244    ethereum: {245      /**246       * Signature is invalid.247       **/248      InvalidSignature: AugmentedError<ApiType>;249      /**250       * Pre-log is present, therefore transact is not allowed.251       **/252      PreLogExists: AugmentedError<ApiType>;253      /**254       * Generic error255       **/256      [key: string]: AugmentedError<ApiType>;257    };258    evm: {259      /**260       * Not enough balance to perform action261       **/262      BalanceLow: AugmentedError<ApiType>;263      /**264       * Calculating total fee overflowed265       **/266      FeeOverflow: AugmentedError<ApiType>;267      /**268       * Gas limit is too high.269       **/270      GasLimitTooHigh: AugmentedError<ApiType>;271      /**272       * Gas limit is too low.273       **/274      GasLimitTooLow: AugmentedError<ApiType>;275      /**276       * Gas price is too low.277       **/278      GasPriceTooLow: AugmentedError<ApiType>;279      /**280       * Nonce is invalid281       **/282      InvalidNonce: AugmentedError<ApiType>;283      /**284       * Calculating total payment overflowed285       **/286      PaymentOverflow: AugmentedError<ApiType>;287      /**288       * EVM reentrancy289       **/290      Reentrancy: AugmentedError<ApiType>;291      /**292       * Undefined error.293       **/294      Undefined: AugmentedError<ApiType>;295      /**296       * Withdraw fee failed297       **/298      WithdrawFailed: AugmentedError<ApiType>;299      /**300       * Generic error301       **/302      [key: string]: AugmentedError<ApiType>;303    };304    evmCoderSubstrate: {305      OutOfFund: AugmentedError<ApiType>;306      OutOfGas: AugmentedError<ApiType>;307      /**308       * Generic error309       **/310      [key: string]: AugmentedError<ApiType>;311    };312    evmContractHelpers: {313      /**314       * No pending sponsor for contract.315       **/316      NoPendingSponsor: AugmentedError<ApiType>;317      /**318       * This method is only executable by contract owner319       **/320      NoPermission: AugmentedError<ApiType>;321      /**322       * Number of methods that sponsored limit is defined for exceeds maximum.323       **/324      TooManyMethodsHaveSponsoredLimit: AugmentedError<ApiType>;325      /**326       * Generic error327       **/328      [key: string]: AugmentedError<ApiType>;329    };330    evmMigration: {331      /**332       * Migration of this account is not yet started, or already finished.333       **/334      AccountIsNotMigrating: AugmentedError<ApiType>;335      /**336       * Can only migrate to empty address.337       **/338      AccountNotEmpty: AugmentedError<ApiType>;339      /**340       * Failed to decode event bytes341       **/342      BadEvent: AugmentedError<ApiType>;343      /**344       * Generic error345       **/346      [key: string]: AugmentedError<ApiType>;347    };348    foreignAssets: {349      /**350       * AssetId exists351       **/352      AssetIdExisted: AugmentedError<ApiType>;353      /**354       * AssetId not exists355       **/356      AssetIdNotExists: AugmentedError<ApiType>;357      /**358       * The given location could not be used (e.g. because it cannot be expressed in the359       * desired version of XCM).360       **/361      BadLocation: AugmentedError<ApiType>;362      /**363       * MultiLocation existed364       **/365      MultiLocationExisted: AugmentedError<ApiType>;366      /**367       * Generic error368       **/369      [key: string]: AugmentedError<ApiType>;370    };371    fungible: {372      /**373       * Fungible token does not support nesting.374       **/375      FungibleDisallowsNesting: AugmentedError<ApiType>;376      /**377       * Tried to set data for fungible item.378       **/379      FungibleItemsDontHaveData: AugmentedError<ApiType>;380      /**381       * Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.382       **/383      FungibleItemsHaveNoId: AugmentedError<ApiType>;384      /**385       * Not Fungible item data used to mint in Fungible collection.386       **/387      NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;388      /**389       * Setting approval for all is not allowed.390       **/391      SettingApprovalForAllNotAllowed: AugmentedError<ApiType>;392      /**393       * Setting item properties is not allowed.394       **/395      SettingPropertiesNotAllowed: AugmentedError<ApiType>;396      /**397       * Generic error398       **/399      [key: string]: AugmentedError<ApiType>;400    };401    maintenance: {402      /**403       * Generic error404       **/405      [key: string]: AugmentedError<ApiType>;406    };407    nonfungible: {408      /**409       * Unable to burn NFT with children410       **/411      CantBurnNftWithChildren: AugmentedError<ApiType>;412      /**413       * Used amount > 1 with NFT414       **/415      NonfungibleItemsHaveNoAmount: AugmentedError<ApiType>;416      /**417       * Not Nonfungible item data used to mint in Nonfungible collection.418       **/419      NotNonfungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;420      /**421       * Generic error422       **/423      [key: string]: AugmentedError<ApiType>;424    };425    parachainSystem: {426      /**427       * The inherent which supplies the host configuration did not run this block428       **/429      HostConfigurationNotAvailable: AugmentedError<ApiType>;430      /**431       * No code upgrade has been authorized.432       **/433      NothingAuthorized: AugmentedError<ApiType>;434      /**435       * No validation function upgrade is currently scheduled.436       **/437      NotScheduled: AugmentedError<ApiType>;438      /**439       * Attempt to upgrade validation function while existing upgrade pending440       **/441      OverlappingUpgrades: AugmentedError<ApiType>;442      /**443       * Polkadot currently prohibits this parachain from upgrading its validation function444       **/445      ProhibitedByPolkadot: AugmentedError<ApiType>;446      /**447       * The supplied validation function has compiled into a blob larger than Polkadot is448       * willing to run449       **/450      TooBig: AugmentedError<ApiType>;451      /**452       * The given code upgrade has not been authorized.453       **/454      Unauthorized: AugmentedError<ApiType>;455      /**456       * The inherent which supplies the validation data did not run this block457       **/458      ValidationDataNotAvailable: AugmentedError<ApiType>;459      /**460       * Generic error461       **/462      [key: string]: AugmentedError<ApiType>;463    };464    polkadotXcm: {465      /**466       * The location is invalid since it already has a subscription from us.467       **/468      AlreadySubscribed: AugmentedError<ApiType>;469      /**470       * The given location could not be used (e.g. because it cannot be expressed in the471       * desired version of XCM).472       **/473      BadLocation: AugmentedError<ApiType>;474      /**475       * The version of the `Versioned` value used is not able to be interpreted.476       **/477      BadVersion: AugmentedError<ApiType>;478      /**479       * Could not re-anchor the assets to declare the fees for the destination chain.480       **/481      CannotReanchor: AugmentedError<ApiType>;482      /**483       * The destination `MultiLocation` provided cannot be inverted.484       **/485      DestinationNotInvertible: AugmentedError<ApiType>;486      /**487       * The assets to be sent are empty.488       **/489      Empty: AugmentedError<ApiType>;490      /**491       * The message execution fails the filter.492       **/493      Filtered: AugmentedError<ApiType>;494      /**495       * Origin is invalid for sending.496       **/497      InvalidOrigin: AugmentedError<ApiType>;498      /**499       * The referenced subscription could not be found.500       **/501      NoSubscription: AugmentedError<ApiType>;502      /**503       * There was some other issue (i.e. not to do with routing) in sending the message. Perhaps504       * a lack of space for buffering the message.505       **/506      SendFailure: AugmentedError<ApiType>;507      /**508       * Too many assets have been attempted for transfer.509       **/510      TooManyAssets: AugmentedError<ApiType>;511      /**512       * The desired destination was unreachable, generally because there is a no way of routing513       * to it.514       **/515      Unreachable: AugmentedError<ApiType>;516      /**517       * The message's weight could not be determined.518       **/519      UnweighableMessage: AugmentedError<ApiType>;520      /**521       * Generic error522       **/523      [key: string]: AugmentedError<ApiType>;524    };525    refungible: {526      /**527       * Not Refungible item data used to mint in Refungible collection.528       **/529      NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;530      /**531       * Refungible token can't nest other tokens.532       **/533      RefungibleDisallowsNesting: AugmentedError<ApiType>;534      /**535       * Refungible token can't be repartitioned by user who isn't owns all pieces.536       **/537      RepartitionWhileNotOwningAllPieces: AugmentedError<ApiType>;538      /**539       * Setting item properties is not allowed.540       **/541      SettingPropertiesNotAllowed: AugmentedError<ApiType>;542      /**543       * Maximum refungibility exceeded.544       **/545      WrongRefungiblePieces: AugmentedError<ApiType>;546      /**547       * Generic error548       **/549      [key: string]: AugmentedError<ApiType>;550    };551    rmrkCore: {552      /**553       * Not the target owner of the sent NFT.554       **/555      CannotAcceptNonOwnedNft: AugmentedError<ApiType>;556      /**557       * Not the target owner of the sent NFT.558       **/559      CannotRejectNonOwnedNft: AugmentedError<ApiType>;560      /**561       * NFT was not sent and is not pending.562       **/563      CannotRejectNonPendingNft: AugmentedError<ApiType>;564      /**565       * If an NFT is sent to a descendant, that would form a nesting loop, an ouroboros.566       * Sending to self is redundant.567       **/568      CannotSendToDescendentOrSelf: AugmentedError<ApiType>;569      /**570       * Too many tokens created in the collection, no new ones are allowed.571       **/572      CollectionFullOrLocked: AugmentedError<ApiType>;573      /**574       * Only destroying collections without tokens is allowed.575       **/576      CollectionNotEmpty: AugmentedError<ApiType>;577      /**578       * Collection does not exist, has a wrong type, or does not map to a Unique ID.579       **/580      CollectionUnknown: AugmentedError<ApiType>;581      /**582       * Property of the type of RMRK collection could not be read successfully.583       **/584      CorruptedCollectionType: AugmentedError<ApiType>;585      /**586       * Could not find an ID for a collection. It is likely there were too many collections created on the chain, causing an overflow.587       **/588      NoAvailableCollectionId: AugmentedError<ApiType>;589      /**590       * Token does not exist, or there is no suitable ID for it, likely too many tokens were created in a collection, causing an overflow.591       **/592      NoAvailableNftId: AugmentedError<ApiType>;593      /**594       * Could not find an ID for the resource. It is likely there were too many resources created on an NFT, causing an overflow.595       **/596      NoAvailableResourceId: AugmentedError<ApiType>;597      /**598       * Token is marked as non-transferable, and thus cannot be transferred.599       **/600      NonTransferable: AugmentedError<ApiType>;601      /**602       * No permission to perform action.603       **/604      NoPermission: AugmentedError<ApiType>;605      /**606       * No such resource found.607       **/608      ResourceDoesntExist: AugmentedError<ApiType>;609      /**610       * Resource is not pending for the operation.611       **/612      ResourceNotPending: AugmentedError<ApiType>;613      /**614       * Could not find a property by the supplied key.615       **/616      RmrkPropertyIsNotFound: AugmentedError<ApiType>;617      /**618       * Too many symbols supplied as the property key. The maximum is [256](up_data_structs::MAX_PROPERTY_KEY_LENGTH).619       **/620      RmrkPropertyKeyIsTooLong: AugmentedError<ApiType>;621      /**622       * Too many bytes supplied as the property value. The maximum is [32768](up_data_structs::MAX_PROPERTY_VALUE_LENGTH).623       **/624      RmrkPropertyValueIsTooLong: AugmentedError<ApiType>;625      /**626       * Something went wrong when decoding encoded data from the storage.627       * Perhaps, there was a wrong key supplied for the type, or the data was improperly stored.628       **/629      UnableToDecodeRmrkData: AugmentedError<ApiType>;630      /**631       * Generic error632       **/633      [key: string]: AugmentedError<ApiType>;634    };635    rmrkEquip: {636      /**637       * Base collection linked to this ID does not exist.638       **/639      BaseDoesntExist: AugmentedError<ApiType>;640      /**641       * No Theme named "default" is associated with the Base.642       **/643      NeedsDefaultThemeFirst: AugmentedError<ApiType>;644      /**645       * Could not find an ID for a Base collection. It is likely there were too many collections created on the chain, causing an overflow.646       **/647      NoAvailableBaseId: AugmentedError<ApiType>;648      /**649       * Could not find a suitable ID for a Part, likely too many Part tokens were created in the Base, causing an overflow650       **/651      NoAvailablePartId: AugmentedError<ApiType>;652      /**653       * Cannot assign equippables to a fixed Part.654       **/655      NoEquippableOnFixedPart: AugmentedError<ApiType>;656      /**657       * Part linked to this ID does not exist.658       **/659      PartDoesntExist: AugmentedError<ApiType>;660      /**661       * No permission to perform action.662       **/663      PermissionError: AugmentedError<ApiType>;664      /**665       * Generic error666       **/667      [key: string]: AugmentedError<ApiType>;668    };669    scheduler: {670      /**671       * There is no place for a new task in the agenda672       **/673      AgendaIsExhausted: AugmentedError<ApiType>;674      /**675       * Failed to schedule a call676       **/677      FailedToSchedule: AugmentedError<ApiType>;678      /**679       * Attempt to use a non-named function on a named task.680       **/681      Named: AugmentedError<ApiType>;682      /**683       * Cannot find the scheduled call.684       **/685      NotFound: AugmentedError<ApiType>;686      /**687       * Scheduled call preimage is not found688       **/689      PreimageNotFound: AugmentedError<ApiType>;690      /**691       * Scheduled call is corrupted692       **/693      ScheduledCallCorrupted: AugmentedError<ApiType>;694      /**695       * Given target block number is in the past.696       **/697      TargetBlockNumberInPast: AugmentedError<ApiType>;698      /**699       * Scheduled call is too big700       **/701      TooBigScheduledCall: AugmentedError<ApiType>;702      /**703       * Generic error704       **/705      [key: string]: AugmentedError<ApiType>;706    };707    structure: {708      /**709       * While nesting, reached the breadth limit of nesting, exceeding the provided budget.710       **/711      BreadthLimit: AugmentedError<ApiType>;712      /**713       * While nesting, reached the depth limit of nesting, exceeding the provided budget.714       **/715      DepthLimit: AugmentedError<ApiType>;716      /**717       * While nesting, encountered an already checked account, detecting a loop.718       **/719      OuroborosDetected: AugmentedError<ApiType>;720      /**721       * Couldn't find the token owner that is itself a token.722       **/723      TokenNotFound: AugmentedError<ApiType>;724      /**725       * Generic error726       **/727      [key: string]: AugmentedError<ApiType>;728    };729    sudo: {730      /**731       * Sender must be the Sudo account732       **/733      RequireSudo: AugmentedError<ApiType>;734      /**735       * Generic error736       **/737      [key: string]: AugmentedError<ApiType>;738    };739    system: {740      /**741       * The origin filter prevent the call to be dispatched.742       **/743      CallFiltered: AugmentedError<ApiType>;744      /**745       * Failed to extract the runtime version from the new runtime.746       * 747       * Either calling `Core_version` or decoding `RuntimeVersion` failed.748       **/749      FailedToExtractRuntimeVersion: AugmentedError<ApiType>;750      /**751       * The name of specification does not match between the current runtime752       * and the new runtime.753       **/754      InvalidSpecName: AugmentedError<ApiType>;755      /**756       * Suicide called when the account has non-default composite data.757       **/758      NonDefaultComposite: AugmentedError<ApiType>;759      /**760       * There is a non-zero reference count preventing the account from being purged.761       **/762      NonZeroRefCount: AugmentedError<ApiType>;763      /**764       * The specification version is not allowed to decrease between the current runtime765       * and the new runtime.766       **/767      SpecVersionNeedsToIncrease: AugmentedError<ApiType>;768      /**769       * Generic error770       **/771      [key: string]: AugmentedError<ApiType>;772    };773    testUtils: {774      TestPalletDisabled: AugmentedError<ApiType>;775      TriggerRollback: AugmentedError<ApiType>;776      /**777       * Generic error778       **/779      [key: string]: AugmentedError<ApiType>;780    };781    tokens: {782      /**783       * Cannot convert Amount into Balance type784       **/785      AmountIntoBalanceFailed: AugmentedError<ApiType>;786      /**787       * The balance is too low788       **/789      BalanceTooLow: AugmentedError<ApiType>;790      /**791       * Beneficiary account must pre-exist792       **/793      DeadAccount: AugmentedError<ApiType>;794      /**795       * Value too low to create account due to existential deposit796       **/797      ExistentialDeposit: AugmentedError<ApiType>;798      /**799       * Transfer/payment would kill account800       **/801      KeepAlive: AugmentedError<ApiType>;802      /**803       * Failed because liquidity restrictions due to locking804       **/805      LiquidityRestrictions: AugmentedError<ApiType>;806      /**807       * Failed because the maximum locks was exceeded808       **/809      MaxLocksExceeded: AugmentedError<ApiType>;810      TooManyReserves: AugmentedError<ApiType>;811      /**812       * Generic error813       **/814      [key: string]: AugmentedError<ApiType>;815    };816    treasury: {817      /**818       * The spend origin is valid but the amount it is allowed to spend is lower than the819       * amount to be spent.820       **/821      InsufficientPermission: AugmentedError<ApiType>;822      /**823       * Proposer's balance is too low.824       **/825      InsufficientProposersBalance: AugmentedError<ApiType>;826      /**827       * No proposal or bounty at that index.828       **/829      InvalidIndex: AugmentedError<ApiType>;830      /**831       * Proposal has not been approved.832       **/833      ProposalNotApproved: AugmentedError<ApiType>;834      /**835       * Too many approvals in the queue.836       **/837      TooManyApprovals: AugmentedError<ApiType>;838      /**839       * Generic error840       **/841      [key: string]: AugmentedError<ApiType>;842    };843    unique: {844      /**845       * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].846       **/847      CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;848      /**849       * This address is not set as sponsor, use setCollectionSponsor first.850       **/851      ConfirmUnsetSponsorFail: AugmentedError<ApiType>;852      /**853       * Length of items properties must be greater than 0.854       **/855      EmptyArgument: AugmentedError<ApiType>;856      /**857       * Repertition is only supported by refungible collection.858       **/859      RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;860      /**861       * Generic error862       **/863      [key: string]: AugmentedError<ApiType>;864    };865    vesting: {866      /**867       * The vested transfer amount is too low868       **/869      AmountLow: AugmentedError<ApiType>;870      /**871       * Insufficient amount of balance to lock872       **/873      InsufficientBalanceToLock: AugmentedError<ApiType>;874      /**875       * Failed because the maximum vesting schedules was exceeded876       **/877      MaxVestingSchedulesExceeded: AugmentedError<ApiType>;878      /**879       * This account have too many vesting schedules880       **/881      TooManyVestingSchedules: AugmentedError<ApiType>;882      /**883       * Vesting period is zero884       **/885      ZeroVestingPeriod: AugmentedError<ApiType>;886      /**887       * Number of vests is zero888       **/889      ZeroVestingPeriodCount: AugmentedError<ApiType>;890      /**891       * Generic error892       **/893      [key: string]: AugmentedError<ApiType>;894    };895    xcmpQueue: {896      /**897       * Bad overweight index.898       **/899      BadOverweightIndex: AugmentedError<ApiType>;900      /**901       * Bad XCM data.902       **/903      BadXcm: AugmentedError<ApiType>;904      /**905       * Bad XCM origin.906       **/907      BadXcmOrigin: AugmentedError<ApiType>;908      /**909       * Failed to send XCM message.910       **/911      FailedToSend: AugmentedError<ApiType>;912      /**913       * Provided weight is possibly not enough to execute the message.914       **/915      WeightOverLimit: AugmentedError<ApiType>;916      /**917       * Generic error918       **/919      [key: string]: AugmentedError<ApiType>;920    };921    xTokens: {922      /**923       * Asset has no reserve location.924       **/925      AssetHasNoReserve: AugmentedError<ApiType>;926      /**927       * The specified index does not exist in a MultiAssets struct.928       **/929      AssetIndexNonExistent: AugmentedError<ApiType>;930      /**931       * The version of the `Versioned` value used is not able to be932       * interpreted.933       **/934      BadVersion: AugmentedError<ApiType>;935      /**936       * Could not re-anchor the assets to declare the fees for the937       * destination chain.938       **/939      CannotReanchor: AugmentedError<ApiType>;940      /**941       * The destination `MultiLocation` provided cannot be inverted.942       **/943      DestinationNotInvertible: AugmentedError<ApiType>;944      /**945       * We tried sending distinct asset and fee but they have different946       * reserve chains.947       **/948      DistinctReserveForAssetAndFee: AugmentedError<ApiType>;949      /**950       * Fee is not enough.951       **/952      FeeNotEnough: AugmentedError<ApiType>;953      /**954       * Could not get ancestry of asset reserve location.955       **/956      InvalidAncestry: AugmentedError<ApiType>;957      /**958       * The MultiAsset is invalid.959       **/960      InvalidAsset: AugmentedError<ApiType>;961      /**962       * Invalid transfer destination.963       **/964      InvalidDest: AugmentedError<ApiType>;965      /**966       * MinXcmFee not registered for certain reserve location967       **/968      MinXcmFeeNotDefined: AugmentedError<ApiType>;969      /**970       * Not cross-chain transfer.971       **/972      NotCrossChainTransfer: AugmentedError<ApiType>;973      /**974       * Currency is not cross-chain transferable.975       **/976      NotCrossChainTransferableCurrency: AugmentedError<ApiType>;977      /**978       * Not supported MultiLocation979       **/980      NotSupportedMultiLocation: AugmentedError<ApiType>;981      /**982       * The number of assets to be sent is over the maximum.983       **/984      TooManyAssetsBeingSent: AugmentedError<ApiType>;985      /**986       * The message's weight could not be determined.987       **/988      UnweighableMessage: AugmentedError<ApiType>;989      /**990       * XCM execution failed.991       **/992      XcmExecutionFailed: AugmentedError<ApiType>;993      /**994       * The transfering asset amount is zero.995       **/996      ZeroAmount: AugmentedError<ApiType>;997      /**998       * The fee is zero.999       **/1000      ZeroFee: AugmentedError<ApiType>;1001      /**1002       * Generic error1003       **/1004      [key: string]: AugmentedError<ApiType>;1005    };1006  } // AugmentedErrors1007} // declare module
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -107,6 +107,10 @@
        **/
       Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
+       * Amount pieces of token owned by `sender` was approved for `spender`.
+       **/
+      ApprovedForAll: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+      /**
        * New collection was created
        **/
       CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -442,6 +442,10 @@
        **/
       tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
+       * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+       **/
+      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]>;
+      /**
        * Generic query
        **/
       [key: string]: QueryableStorageEntry<ApiType>;
@@ -645,6 +649,10 @@
        **/
       totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
+       * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.
+       **/
+      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]>;
+      /**
        * Generic query
        **/
       [key: string]: QueryableStorageEntry<ApiType>;
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -720,6 +720,10 @@
        **/
       effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;
       /**
+       * Tells whether an operator is approved by a given owner.
+       **/
+      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>>>;
+      /**
        * Get the last token ID created in a collection
        **/
       lastTokenId: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -1545,6 +1545,18 @@
        **/
       repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
       /**
+       * Sets or unsets the approval of a given operator.
+       * 
+       * An operator is allowed to transfer all tokens of the sender on their behalf.
+       * 
+       * # Arguments
+       * 
+       * * `owner`: Token owner
+       * * `operator`: Operator
+       * * `approve`: Is operator enabled or disabled
+       **/
+      setApprovalForAll: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
+      /**
        * Set specific limits of a collection. Empty, or None fields mean chain default.
        * 
        * # Permissions
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1286,6 +1286,8 @@
   readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
   readonly isApproved: boolean;
   readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+  readonly isApprovedForAll: boolean;
+  readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
   readonly isCollectionPropertySet: boolean;
   readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
   readonly isCollectionPropertyDeleted: boolean;
@@ -1296,7 +1298,7 @@
   readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
   readonly isPropertyPermissionSet: boolean;
   readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
-  readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
+  readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
 }
 
 /** @name PalletConfigurationCall */
@@ -1603,7 +1605,8 @@
   readonly isFungibleItemsDontHaveData: boolean;
   readonly isFungibleDisallowsNesting: boolean;
   readonly isSettingPropertiesNotAllowed: boolean;
-  readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
+  readonly isSettingApprovalForAllNotAllowed: boolean;
+  readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingApprovalForAllNotAllowed';
 }
 
 /** @name PalletInflationCall */
@@ -2309,7 +2312,13 @@
     readonly tokenId: u32;
     readonly amount: u128;
   } & Struct;
-  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';
+  readonly isSetApprovalForAll: boolean;
+  readonly asSetApprovalForAll: {
+    readonly collectionId: u32;
+    readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
+    readonly approve: bool;
+  } & Struct;
+  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';
 }
 
 /** @name PalletUniqueError */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1046,6 +1046,7 @@
       ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
       Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
       Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',
+      ApprovedForAll: '(u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,bool)',
       CollectionPropertySet: '(u32,Bytes)',
       CollectionPropertyDeleted: '(u32,Bytes)',
       TokenPropertySet: '(u32,u32,Bytes)',
@@ -1054,7 +1055,7 @@
     }
   },
   /**
-   * Lookup99: pallet_structure::pallet::Event<T>
+   * Lookup100: pallet_structure::pallet::Event<T>
    **/
   PalletStructureEvent: {
     _enum: {
@@ -1062,7 +1063,7 @@
     }
   },
   /**
-   * Lookup100: pallet_rmrk_core::pallet::Event<T>
+   * Lookup101: pallet_rmrk_core::pallet::Event<T>
    **/
   PalletRmrkCoreEvent: {
     _enum: {
@@ -1139,7 +1140,7 @@
     }
   },
   /**
-   * Lookup101: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
+   * Lookup102: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
    **/
   RmrkTraitsNftAccountIdOrCollectionNftTuple: {
     _enum: {
@@ -2302,7 +2303,12 @@
       repartition: {
         collectionId: 'u32',
         tokenId: 'u32',
-        amount: 'u128'
+        amount: 'u128',
+      },
+      set_approval_for_all: {
+        collectionId: 'u32',
+        operator: 'PalletEvmAccountBasicCrossAccountIdRepr',
+        approve: 'bool'
       }
     }
   },
@@ -3445,7 +3451,7 @@
    * Lookup430: pallet_fungible::pallet::Error<T>
    **/
   PalletFungibleError: {
-    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
+    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingApprovalForAllNotAllowed']
   },
   /**
    * Lookup431: pallet_refungible::ItemData
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1182,6 +1182,8 @@
     readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
     readonly isApproved: boolean;
     readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
+    readonly isApprovedForAll: boolean;
+    readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
     readonly isCollectionPropertySet: boolean;
     readonly asCollectionPropertySet: ITuple<[u32, Bytes]>;
     readonly isCollectionPropertyDeleted: boolean;
@@ -1192,17 +1194,17 @@
     readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
     readonly isPropertyPermissionSet: boolean;
     readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
-    readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
+    readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
   }
 
-  /** @name PalletStructureEvent (99) */
+  /** @name PalletStructureEvent (100) */
   interface PalletStructureEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
     readonly type: 'Executed';
   }
 
-  /** @name PalletRmrkCoreEvent (100) */
+  /** @name PalletRmrkCoreEvent (101) */
   interface PalletRmrkCoreEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: {
@@ -1292,7 +1294,7 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet';
   }
 
-  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (101) */
+  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (102) */
   interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum {
     readonly isAccountId: boolean;
     readonly asAccountId: AccountId32;
@@ -2539,7 +2541,13 @@
       readonly tokenId: u32;
       readonly amount: u128;
     } & Struct;
-    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';
+    readonly isSetApprovalForAll: boolean;
+    readonly asSetApprovalForAll: {
+      readonly collectionId: u32;
+      readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
+      readonly approve: bool;
+    } & Struct;
+    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';
   }
 
   /** @name UpDataStructsCollectionMode (240) */
@@ -3655,7 +3663,8 @@
     readonly isFungibleItemsDontHaveData: boolean;
     readonly isFungibleDisallowsNesting: boolean;
     readonly isSettingPropertiesNotAllowed: boolean;
-    readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
+    readonly isSettingApprovalForAllNotAllowed: boolean;
+    readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingApprovalForAllNotAllowed';
   }
 
   /** @name PalletRefungibleItemData (431) */
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -175,5 +175,10 @@
       [collectionParam, tokenParam], 
       'Option<u128>',
     ),
+    isApprovedForAll: fun(
+      'Tells whether an operator is approved by a given owner.', 
+      [collectionParam, crossAccountParam('owner'), crossAccountParam('operator')], 
+      'Option<bool>',
+    ),
   },
 };
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -1413,6 +1413,32 @@
   getTokenObject(_collectionId: number, _tokenId: number): any {
     return null;
   }
+
+  /**
+   * Tells whether an operator is approved by a given owner.
+   * @param collectionId ID of collection
+   * @param owner owner address
+	 * @param operator operator addrees
+   * @returns true if operator is enabled
+   */
+  async isApprovedForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {
+    return (await this.helper.callRpc('api.rpc.unique.isApprovedForAll', [collectionId, owner, operator])).toJSON();
+  }
+
+  /** Sets or unsets the approval of a given operator.
+	 *  An operator is allowed to transfer all tokens of the sender on their behalf.
+	 *  @param operator Operator
+	 *  @param approved Is operator enabled or disabled
+   *  @returns ```true``` if extrinsic success, otherwise ```false```
+   */
+  async setApprovalForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {
+    const result = await this.helper.executeExtrinsic(
+      signer,
+      'api.tx.unique.setApprovalForAll', [collectionId, operator, approved],
+      true,
+    );
+    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');
+  }
 }