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

difftreelog

Merge pull request #184 from UniqueNetwork/feature/evm-gas-fees

kozyrevdev2021-08-30parents: #b7be484 #28500d1.patch.diff
in: master
Evm gas metering

9 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -34,7 +34,7 @@
 use frame_system::{self as system, ensure_signed};
 use sp_core::H160;
 use sp_std::vec;
-use sp_runtime::sp_std::prelude::Vec;
+use sp_runtime::{DispatchError, sp_std::prelude::Vec};
 use core::ops::{Deref, DerefMut};
 use nft_data_structs::{
 	MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,
@@ -203,9 +203,16 @@
 	pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult {
 		self.recorder.log_sub(log)
 	}
+	#[allow(dead_code)]
 	fn consume_gas(&self, gas: u64) -> DispatchResult {
 		self.recorder.consume_gas_sub(gas)
 	}
+	fn consume_sload(&self) -> DispatchResult {
+		self.recorder.consume_sload_sub()
+	}
+	fn consume_sstore(&self) -> DispatchResult {
+		self.recorder.consume_sstore_sub()
+	}
 	pub fn submit_logs(self) -> DispatchResult {
 		self.recorder.submit_logs()
 	}
@@ -1255,14 +1262,13 @@
 		item_id: TokenId,
 		value: u128,
 	) -> DispatchResult {
-		target_collection.consume_gas(2000000)?;
 		// Limits check
 		Self::is_correct_transfer(target_collection, recipient)?;
 
 		// Transfer permissions check
 		ensure!(
-			Self::is_item_owner(sender, target_collection, item_id)
-				|| Self::is_owner_or_admin_permissions(target_collection, sender),
+			Self::is_item_owner(sender, target_collection, item_id)?
+				|| Self::is_owner_or_admin_permissions(target_collection, sender)?,
 			Error::<T>::NoPermission
 		);
 
@@ -1309,16 +1315,15 @@
 		item_id: TokenId,
 		amount: u128,
 	) -> DispatchResult {
-		collection.consume_gas(2000000)?;
 		Self::token_exists(collection, item_id)?;
 
 		// Transfer permissions check
 		let bypasses_limits = collection.limits.owner_can_transfer
-			&& Self::is_owner_or_admin_permissions(collection, sender);
+			&& Self::is_owner_or_admin_permissions(collection, sender)?;
 
 		let allowance_limit = if bypasses_limits {
 			None
-		} else if let Some(amount) = Self::owned_amount(sender, collection, item_id) {
+		} else if let Some(amount) = Self::owned_amount(sender, collection, item_id)? {
 			Some(amount)
 		} else {
 			fail!(Error::<T>::NoPermission);
@@ -1329,6 +1334,7 @@
 			Self::check_white_list(collection, spender)?;
 		}
 
+		collection.consume_sload()?;
 		let allowance: u128 = amount
 			.checked_add(<Allowances<T>>::get(
 				collection.id,
@@ -1338,6 +1344,7 @@
 		if let Some(limit) = allowance_limit {
 			ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);
 		}
+		collection.consume_sstore()?;
 		<Allowances<T>>::insert(
 			collection.id,
 			(item_id, sender.as_sub(), spender.as_sub()),
@@ -1380,8 +1387,8 @@
 		item_id: TokenId,
 		amount: u128,
 	) -> DispatchResult {
-		collection.consume_gas(2000000)?;
 		// Check approval
+		collection.consume_sload()?;
 		let approval: u128 =
 			<Allowances<T>>::get(collection.id, (item_id, from.as_sub(), sender.as_sub()));
 
@@ -1392,7 +1399,7 @@
 		ensure!(
 			approval >= amount
 				|| (collection.limits.owner_can_transfer
-					&& Self::is_owner_or_admin_permissions(collection, sender)),
+					&& Self::is_owner_or_admin_permissions(collection, sender)?),
 			Error::<T>::NoPermission
 		);
 
@@ -1403,6 +1410,7 @@
 
 		// Reduce approval by transferred amount or remove if remaining approval drops to 0
 		let allowance = approval.saturating_sub(amount);
+		collection.consume_sstore()?;
 		if allowance > 0 {
 			<Allowances<T>>::insert(
 				collection.id,
@@ -1456,8 +1464,8 @@
 
 		// Modify permissions check
 		ensure!(
-			Self::is_item_owner(sender, collection, item_id)
-				|| Self::is_owner_or_admin_permissions(collection, sender),
+			Self::is_item_owner(sender, collection, item_id)?
+				|| Self::is_owner_or_admin_permissions(collection, sender)?,
 			Error::<T>::NoPermission
 		);
 
@@ -1498,9 +1506,9 @@
 		value: u128,
 	) -> DispatchResult {
 		ensure!(
-			Self::is_item_owner(sender, collection, item_id)
+			Self::is_item_owner(sender, collection, item_id)?
 				|| (collection.limits.owner_can_transfer
-					&& Self::is_owner_or_admin_permissions(collection, sender)),
+					&& Self::is_owner_or_admin_permissions(collection, sender)?),
 			Error::<T>::NoPermission
 		);
 
@@ -1542,6 +1550,7 @@
 		let collection_id = collection.id;
 
 		// check token limit and account token limit
+		collection.consume_sload()?;
 		let account_items: u32 =
 			<AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;
 		ensure!(
@@ -1580,7 +1589,7 @@
 			Error::<T>::AccountTokenLimitExceeded
 		);
 
-		if !Self::is_owner_or_admin_permissions(collection, sender) {
+		if !Self::is_owner_or_admin_permissions(collection, sender)? {
 			ensure!(collection.mint_mode, Error::<T>::PublicMintingNotAllowed);
 			Self::check_white_list(collection, owner)?;
 			Self::check_white_list(collection, sender)?;
@@ -1669,20 +1678,29 @@
 		let collection_id = collection.id;
 
 		// Does new owner already have an account?
+		collection.consume_sload()?;
 		let balance: u128 = <FungibleItemList<T>>::get(collection_id, owner.as_sub()).value;
 
 		// Mint
 		let item = FungibleItemType {
 			value: balance.checked_add(value).ok_or(Error::<T>::NumOverflow)?,
 		};
+		collection.consume_sstore()?;
 		<FungibleItemList<T>>::insert(collection_id, owner.as_sub(), item);
 
 		// Update balance
+		collection.consume_sload()?;
 		let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())
 			.checked_add(value)
 			.ok_or(Error::<T>::NumOverflow)?;
+		collection.consume_sstore()?;
 		<Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);
 
+		collection.log(ERC20Events::Transfer {
+			from: H160::default(),
+			to: *owner.as_eth(),
+			value: value.into(),
+		})?;
 		Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));
 		Ok(())
 	}
@@ -1704,7 +1722,7 @@
 		let value = item_owner.fraction;
 		let owner = item_owner.owner.clone();
 
-		Self::add_token_index(collection_id, current_index, &owner)?;
+		Self::add_token_index(collection, current_index, &owner)?;
 
 		<ItemListIndex>::insert(collection_id, current_index);
 		<ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);
@@ -1730,7 +1748,7 @@
 			.ok_or(Error::<T>::NumOverflow)?;
 
 		let item_owner = item.owner.clone();
-		Self::add_token_index(collection_id, current_index, &item.owner)?;
+		Self::add_token_index(collection, current_index, &item.owner)?;
 
 		<ItemListIndex>::insert(collection_id, current_index);
 		<NftItemList<T>>::insert(collection_id, current_index, item);
@@ -1768,7 +1786,7 @@
 			.iter()
 			.find(|&i| i.owner == *owner)
 			.ok_or(Error::<T>::TokenNotFound)?;
-		Self::remove_token_index(collection_id, item_id, owner)?;
+		Self::remove_token_index(collection, item_id, owner)?;
 
 		// update balance
 		let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.as_sub())
@@ -1801,7 +1819,7 @@
 
 		let item =
 			<NftItemList<T>>::get(collection_id, item_id).ok_or(Error::<T>::TokenNotFound)?;
-		Self::remove_token_index(collection_id, item_id, &item.owner)?;
+		Self::remove_token_index(collection, item_id, &item.owner)?;
 
 		// update balance
 		let new_balance = <Balance<T>>::get(collection_id, item.owner.as_sub())
@@ -1867,9 +1885,10 @@
 	fn is_owner_or_admin_permissions(
 		collection: &CollectionHandle<T>,
 		subject: &T::CrossAccountId,
-	) -> bool {
-		*subject.as_sub() == collection.owner
-			|| <AdminList<T>>::get(collection.id).contains(subject)
+	) -> Result<bool, DispatchError> {
+		collection.consume_sload()?;
+		Ok(*subject.as_sub() == collection.owner
+			|| <AdminList<T>>::get(collection.id).contains(subject))
 	}
 
 	fn check_owner_or_admin_permissions(
@@ -1877,7 +1896,7 @@
 		subject: &T::CrossAccountId,
 	) -> DispatchResult {
 		ensure!(
-			Self::is_owner_or_admin_permissions(collection, subject),
+			Self::is_owner_or_admin_permissions(collection, subject)?,
 			Error::<T>::NoPermission
 		);
 
@@ -1886,6 +1905,15 @@
 
 	fn owned_amount(
 		subject: &T::CrossAccountId,
+		collection: &CollectionHandle<T>,
+		item_id: TokenId,
+	) -> Result<Option<u128>, DispatchError> {
+		collection.consume_sload()?;
+		Ok(Self::owned_amount_unchecked(subject, collection, item_id))
+	}
+
+	fn owned_amount_unchecked(
+		subject: &T::CrossAccountId,
 		target_collection: &CollectionHandle<T>,
 		item_id: TokenId,
 	) -> Option<u128> {
@@ -1911,25 +1939,22 @@
 		subject: &T::CrossAccountId,
 		target_collection: &CollectionHandle<T>,
 		item_id: TokenId,
-	) -> bool {
-		match target_collection.mode {
+	) -> Result<bool, DispatchError> {
+		Ok(match target_collection.mode {
 			CollectionMode::Fungible(_) => true,
-			_ => Self::owned_amount(subject, target_collection, item_id).is_some(),
-		}
+			_ => Self::owned_amount(subject, target_collection, item_id)?.is_some(),
+		})
 	}
 
 	fn check_white_list(
 		collection: &CollectionHandle<T>,
 		address: &T::CrossAccountId,
 	) -> DispatchResult {
-		let collection_id = collection.id;
-
-		let mes = Error::<T>::AddresNotInWhiteList;
+		collection.consume_sload()?;
 		ensure!(
-			<WhiteList<T>>::contains_key(collection_id, address.as_sub()),
-			mes
+			<WhiteList<T>>::contains_key(collection.id, address.as_sub()),
+			Error::<T>::AddresNotInWhiteList,
 		);
-
 		Ok(())
 	}
 
@@ -1958,22 +1983,39 @@
 	) -> DispatchResult {
 		let collection_id = collection.id;
 
+		collection.consume_sload()?;
+		collection.consume_sload()?;
+		let mut recipient_balance = <FungibleItemList<T>>::get(collection_id, recipient.as_sub());
 		let mut balance = <FungibleItemList<T>>::get(collection_id, owner.as_sub());
-		ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);
 
-		// Send balance to recipient (updates balanceOf of recipient)
-		Self::add_fungible_item(collection, recipient, value)?;
+		recipient_balance.value = recipient_balance
+			.value
+			.checked_add(value)
+			.ok_or(Error::<T>::NumOverflow)?;
+		balance.value = balance
+			.value
+			.checked_sub(value)
+			.ok_or(Error::<T>::TokenValueTooLow)?;
 
-		// update balanceOf of sender
-		<Balance<T>>::insert(collection_id, owner.as_sub(), balance.value - value);
+		// update balanceOf
+		collection.consume_sstore()?;
+		collection.consume_sstore()?;
+		if balance.value != 0 {
+			<Balance<T>>::insert(collection_id, owner.as_sub(), balance.value);
+		} else {
+			<Balance<T>>::remove(collection_id, owner.as_sub());
+		}
+		<Balance<T>>::insert(collection_id, recipient.as_sub(), recipient_balance.value);
 
 		// Reduce or remove sender
-		if balance.value == value {
+		collection.consume_sstore()?;
+		collection.consume_sstore()?;
+		if balance.value != 0 {
+			<FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);
+		} else {
 			<FungibleItemList<T>>::remove(collection_id, owner.as_sub());
-		} else {
-			balance.value -= value;
-			<FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);
 		}
+		<FungibleItemList<T>>::insert(collection_id, recipient.as_sub(), recipient_balance);
 
 		collection.log(ERC20Events::Transfer {
 			from: *owner.as_eth(),
@@ -1999,6 +2041,7 @@
 		new_owner: T::CrossAccountId,
 	) -> DispatchResult {
 		let collection_id = collection.id;
+		collection.consume_sload()?;
 		let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id)
 			.ok_or(Error::<T>::TokenNotFound)?;
 
@@ -2011,15 +2054,19 @@
 
 		ensure!(amount >= value, Error::<T>::TokenValueTooLow);
 
+		collection.consume_sload()?;
 		// update balance
 		let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())
 			.checked_sub(value)
 			.ok_or(Error::<T>::NumOverflow)?;
+		collection.consume_sstore()?;
 		<Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);
 
+		collection.consume_sload()?;
 		let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())
 			.checked_add(value)
 			.ok_or(Error::<T>::NumOverflow)?;
+		collection.consume_sstore()?;
 		<Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);
 
 		let old_owner = item.owner.clone();
@@ -2036,10 +2083,11 @@
 				.find(|i| i.owner == owner)
 				.expect("old owner does present in refungible")
 				.owner = new_owner.clone();
+			collection.consume_sstore()?;
 			<ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
 
 			// update index collection
-			Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;
+			Self::move_token_index(collection, item_id, &old_owner, &new_owner)?;
 		} else {
 			new_full_item
 				.owner
@@ -2063,9 +2111,10 @@
 					owner: new_owner.clone(),
 					fraction: value,
 				});
-				Self::add_token_index(collection_id, item_id, &new_owner)?;
+				Self::add_token_index(collection, item_id, &new_owner)?;
 			}
 
+			collection.consume_sstore()?;
 			<ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
 		}
 
@@ -2087,29 +2136,35 @@
 		new_owner: T::CrossAccountId,
 	) -> DispatchResult {
 		let collection_id = collection.id;
+		collection.consume_sload()?;
 		let mut item =
 			<NftItemList<T>>::get(collection_id, item_id).ok_or(Error::<T>::TokenNotFound)?;
 
 		ensure!(sender == item.owner, Error::<T>::MustBeTokenOwner);
 
+		collection.consume_sload()?;
 		// update balance
 		let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())
 			.checked_sub(1)
 			.ok_or(Error::<T>::NumOverflow)?;
+		collection.consume_sstore()?;
 		<Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);
 
+		collection.consume_sload()?;
 		let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())
 			.checked_add(1)
 			.ok_or(Error::<T>::NumOverflow)?;
+		collection.consume_sstore()?;
 		<Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);
 
 		// change owner
 		let old_owner = item.owner.clone();
 		item.owner = new_owner.clone();
+		collection.consume_sstore()?;
 		<NftItemList<T>>::insert(collection_id, item_id, item);
 
 		// update index collection
-		Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;
+		Self::move_token_index(collection, item_id, &old_owner, &new_owner)?;
 
 		collection.log(ERC721Events::Transfer {
 			from: *sender.as_eth(),
@@ -2189,7 +2244,12 @@
 	fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::CrossAccountId>) {
 		let current_index = <ItemListIndex>::get(collection_id).checked_add(1).unwrap();
 
-		Self::add_token_index(collection_id, current_index, &item.owner).unwrap();
+		Self::add_token_index(
+			&CollectionHandle::get(collection_id).unwrap(),
+			current_index,
+			&item.owner,
+		)
+		.unwrap();
 
 		<ItemListIndex>::insert(collection_id, current_index);
 
@@ -2208,7 +2268,12 @@
 	) {
 		let current_index = <ItemListIndex>::get(collection_id).checked_add(1).unwrap();
 
-		Self::add_token_index(collection_id, current_index, owner).unwrap();
+		Self::add_token_index(
+			&CollectionHandle::get(collection_id).unwrap(),
+			current_index,
+			owner,
+		)
+		.unwrap();
 
 		<ItemListIndex>::insert(collection_id, current_index);
 
@@ -2229,7 +2294,12 @@
 		let value = item.owner.first().unwrap().fraction;
 		let owner = item.owner.first().unwrap().owner.clone();
 
-		Self::add_token_index(collection_id, current_index, &owner).unwrap();
+		Self::add_token_index(
+			&CollectionHandle::get(collection_id).unwrap(),
+			current_index,
+			&owner,
+		)
+		.unwrap();
 
 		<ItemListIndex>::insert(collection_id, current_index);
 
@@ -2241,51 +2311,61 @@
 	}
 
 	fn add_token_index(
-		collection_id: CollectionId,
+		collection: &CollectionHandle<T>,
 		item_index: TokenId,
 		owner: &T::CrossAccountId,
 	) -> DispatchResult {
 		// add to account limit
+		collection.consume_sload()?;
 		if <AccountItemCount<T>>::contains_key(owner.as_sub()) {
 			// bound Owned tokens by a single address
+			collection.consume_sload()?;
 			let count = <AccountItemCount<T>>::get(owner.as_sub());
 			ensure!(
 				count < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,
 				Error::<T>::AddressOwnershipLimitExceeded
 			);
 
+			collection.consume_sstore()?;
 			<AccountItemCount<T>>::insert(
 				owner.as_sub(),
 				count.checked_add(1).ok_or(Error::<T>::NumOverflow)?,
 			);
 		} else {
+			collection.consume_sstore()?;
 			<AccountItemCount<T>>::insert(owner.as_sub(), 1);
 		}
 
-		let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());
+		collection.consume_sload()?;
+		let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());
 		if list_exists {
-			let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());
+			collection.consume_sload()?;
+			let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());
 			let item_contains = list.contains(&item_index.clone());
 
 			if !item_contains {
 				list.push(item_index);
 			}
 
-			<AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);
+			collection.consume_sstore()?;
+			<AddressTokens<T>>::insert(collection.id, owner.as_sub(), list);
 		} else {
 			let itm = vec![item_index];
-			<AddressTokens<T>>::insert(collection_id, owner.as_sub(), itm);
+			collection.consume_sstore()?;
+			<AddressTokens<T>>::insert(collection.id, owner.as_sub(), itm);
 		}
 
 		Ok(())
 	}
 
 	fn remove_token_index(
-		collection_id: CollectionId,
+		collection: &CollectionHandle<T>,
 		item_index: TokenId,
 		owner: &T::CrossAccountId,
 	) -> DispatchResult {
 		// update counter
+		collection.consume_sload()?;
+		collection.consume_sstore()?;
 		<AccountItemCount<T>>::insert(
 			owner.as_sub(),
 			<AccountItemCount<T>>::get(owner.as_sub())
@@ -2293,14 +2373,17 @@
 				.ok_or(Error::<T>::NumOverflow)?,
 		);
 
-		let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());
+		collection.consume_sload()?;
+		let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());
 		if list_exists {
-			let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());
+			collection.consume_sload()?;
+			let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());
 			let item_contains = list.contains(&item_index.clone());
 
 			if item_contains {
 				list.retain(|&item| item != item_index);
-				<AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);
+				collection.consume_sstore()?;
+				<AddressTokens<T>>::insert(collection.id, owner.as_sub(), list);
 			}
 		}
 
@@ -2308,13 +2391,13 @@
 	}
 
 	fn move_token_index(
-		collection_id: CollectionId,
+		collection: &CollectionHandle<T>,
 		item_index: TokenId,
 		old_owner: &T::CrossAccountId,
 		new_owner: &T::CrossAccountId,
 	) -> DispatchResult {
-		Self::remove_token_index(collection_id, item_index, old_owner)?;
-		Self::add_token_index(collection_id, item_index, new_owner)?;
+		Self::remove_token_index(collection, item_index, old_owner)?;
+		Self::add_token_index(collection, item_index, new_owner)?;
 
 		Ok(())
 	}
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -4,9 +4,9 @@
   "description": "Substrate Nft tests",
   "main": "",
   "devDependencies": {
-    "@polkadot/dev": "0.62.43",
-    "@polkadot/ts": "0.3.89",
-    "@polkadot/typegen": "5.0.1",
+    "@polkadot/dev": "0.62.60",
+    "@polkadot/ts": "0.4.4",
+    "@polkadot/typegen": "5.5.1",
     "@types/chai": "^4.2.17",
     "@types/chai-as-promised": "^7.1.3",
     "@types/mocha": "^8.2.2",
@@ -66,8 +66,9 @@
   "license": "SEE LICENSE IN ../LICENSE",
   "homepage": "",
   "dependencies": {
-    "@polkadot/api": "5.0.1",
-    "@polkadot/api-contract": "5.0.1",
+    "@polkadot/api": "5.5.1",
+    "@polkadot/api-contract": "5.5.1",
+    "@polkadot/util-crypto": "^7.2.1",
     "bignumber.js": "^9.0.1",
     "chai-as-promised": "^7.1.1",
     "solc": "^0.8.6",
addedtests/src/eth/base.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/base.test.ts
@@ -0,0 +1,22 @@
+
+import { createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee } from './util/helpers';
+import { expect } from 'chai';
+import { UNIQUE } from '../util/helpers';
+
+describe('Contract calls', () => {
+  itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({ web3, api }) => {
+    const deployer = await createEthAccountWithBalance(api, web3);
+    const flipper = await deployFlipper(web3 as any, deployer);
+
+    const cost = await recordEthFee(api, deployer, () => flipper.methods.flip().send({from: deployer}));
+    expect(cost < BigInt(0.2 * Number(UNIQUE))).to.be.true;
+  });
+
+  itWeb3('Balance transfer fee is less than 0.2 UNQ', async ({ web3, api }) => {
+    const userA = await createEthAccountWithBalance(api, web3);
+    const userB = createEthAccount(web3);
+
+    const cost = await recordEthFee(api, userA, () => web3.eth.sendTransaction({ from: userA, to: userB, value: '1000000', ...GAS_ARGS }));
+    expect(cost - await ethBalanceViaSub(api, userB) < BigInt(0.2 * Number(UNIQUE))).to.be.true;
+  });
+});
\ No newline at end of file
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -4,8 +4,8 @@
 //
 
 import privateKey from '../substrate/privateKey';
-import { approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess } from '../util/helpers';
-import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';
+import { approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';
+import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';
 import fungibleAbi from './fungibleAbi.json';
 import { expect } from 'chai';
 
@@ -192,6 +192,64 @@
   });
 });
 
+describe('Fungible: Fees', () => {
+  itWeb3('approve() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'Fungible', decimalPoints: 0 },
+    });
+    const alice = privateKey('//Alice');
+
+    const owner = await createEthAccountWithBalance(api, web3);
+    const spender = createEthAccount(web3);
+
+    await createFungibleItemExpectSuccess(alice, collection, { Value: 200n }, { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(fungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({ from: owner }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: {type: 'Fungible', decimalPoints: 0},
+    });
+    const alice = privateKey('//Alice');
+  
+    const owner = await createEthAccountWithBalance(api, web3);
+    const spender = await createEthAccountWithBalance(api, web3);
+
+    await createFungibleItemExpectSuccess(alice, collection, { Value: 200n }, { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(fungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    await contract.methods.approve(spender, 100).send({ from: owner });
+
+    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({ from: spender }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transfer() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'Fungible', decimalPoints: 0 },
+    });
+    const alice = privateKey('//Alice');
+
+    const owner = await createEthAccountWithBalance(api, web3);
+    const receiver = createEthAccount(web3);
+
+    await createFungibleItemExpectSuccess(alice, collection, { Value: 200n }, { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(fungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({ from: owner }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+});
+
 describe('Fungible: Substrate calls', () => {
   itWeb3('Events emitted for approve()', async ({ web3 }) => {
     const collection = await createCollectionExpectSuccess({
modifiedtests/src/eth/helpersSmoke.test.tsdiffbeforeafterboth
--- a/tests/src/eth/helpersSmoke.test.ts
+++ b/tests/src/eth/helpersSmoke.test.ts
@@ -1,26 +1,24 @@
 import { expect } from 'chai';
 import waitNewBlocks from '../substrate/wait-new-blocks';
-import { createEthAccountWithBalance, deployFlipper, itWeb3, usingWeb3Http, contractHelpers } from './util/helpers';
+import { createEthAccountWithBalance, deployFlipper, itWeb3, contractHelpers } from './util/helpers';
 
-itWeb3('Contract owner is recorded', async ({ api, web3 }) => {
-  await usingWeb3Http(async web3Http => {
-    const owner = await createEthAccountWithBalance(api, web3Http);
+describe('Helpers sanity check', () => {
+  itWeb3('Contract owner is recorded', async ({ api, web3 }) => {
+    const owner = await createEthAccountWithBalance(api, web3);
 
-    const flipper = await deployFlipper(web3Http, owner);
+    const flipper = await deployFlipper(web3, owner);
     await waitNewBlocks(api, 1);
 
     expect(await contractHelpers(web3, owner).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner);
   });
-});
 
-itWeb3('Flipper is working', async({api}) => {
-  await usingWeb3Http(async web3Http => {
-    const owner = await createEthAccountWithBalance(api, web3Http);
-    const flipper = await deployFlipper(web3Http, owner);
+  itWeb3('Flipper is working', async ({ api, web3 }) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const flipper = await deployFlipper(web3, owner);
     await waitNewBlocks(api, 1);
 
     expect(await flipper.methods.getValue().call()).to.be.false;
-    await flipper.methods.flip().send({from: owner});
+    await flipper.methods.flip().send({ from: owner });
     await waitNewBlocks(api, 1);
     expect(await flipper.methods.getValue().call()).to.be.true;
   });
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -4,8 +4,8 @@
 //
 
 import privateKey from '../substrate/privateKey';
-import { approveExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess } from '../util/helpers';
-import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';
+import { approveExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';
+import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import { expect } from 'chai';
 import waitNewBlocks from '../substrate/wait-new-blocks';
@@ -192,6 +192,64 @@
   });
 });
 
+describe('NFT: Fees', () => {
+  itWeb3('approve() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+
+    const owner = await createEthAccountWithBalance(api, web3);
+    const spender = createEthAccount(web3);
+
+    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({ from: owner }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+  
+    const owner = await createEthAccountWithBalance(api, web3);
+    const spender = await createEthAccountWithBalance(api, web3);
+
+    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    await contract.methods.approve(spender, tokenId).send({ from: owner });
+
+    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({ from: spender }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transfer() call fee is less than 0.2UNQ', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+
+    const owner = await createEthAccountWithBalance(api, web3);
+    const receiver = createEthAccount(web3);
+
+    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({ from: owner }));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+});
+
 describe('NFT: Substrate calls', () => {
   itWeb3('Events emitted for approve()', async ({ web3 }) => {
     const collection = await createCollectionExpectSuccess({
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -17,6 +17,8 @@
 import config from '../../config';
 import privateKey from '../../substrate/privateKey';
 import contractHelpersAbi from './contractHelpersAbi.json';
+import getBalance from '../../substrate/get-balance';
+import waitNewBlocks from '../../substrate/wait-new-blocks';
 
 export const GAS_ARGS = { gas: 0x1000000, gasPrice: '0x01' };
 
@@ -37,12 +39,12 @@
   }
 }
 
-type Web3HttpMarker = {web3Http: true};
-
-export async function usingWeb3Http<T>(cb: (web3: Web3 & Web3HttpMarker) => Promise<T> | T): Promise<T> {
+/**
+ * @deprecated Web3 update solved issue with deployment over ws provider
+ */
+export async function usingWeb3Http<T>(cb: (web3: Web3) => Promise<T> | T): Promise<T> {
   const provider = new Web3.providers.HttpProvider(config.frontierUrl);
-  const web3: Web3 & Web3HttpMarker = new Web3(provider) as any;
-  web3.web3Http = true;
+  const web3: Web3 = new Web3(provider);
 
   return await cb(web3);
 }
@@ -175,7 +177,7 @@
   };
 }
 
-export async function deployFlipper(web3: Web3 & Web3HttpMarker, deployer: string) {
+export async function deployFlipper(web3: Web3, deployer: string) {
   const compiled = compileContract('Flipper', `
     contract Flipper {
       bool value = false;
@@ -232,4 +234,22 @@
 
 export function contractHelpers(web3: Web3, caller: string) {
   return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});
+}
+
+export async function ethBalanceViaSub(api: ApiPromise, address: string): Promise<bigint> {
+  return (await getBalance(api, [evmToAddress(address)]))[0];
+}
+
+export async function recordEthFee(api: ApiPromise, user: string, call: () => Promise<any>): Promise<bigint> {
+  const before = await ethBalanceViaSub(api, user);
+
+  await call();
+  await waitNewBlocks(api, 1);
+
+  const after = await ethBalanceViaSub(api, user);
+
+  // Can't use .to.be.less, because chai doesn't supports bigint
+  expect(after < before).to.be.true;
+
+  return before - after;
 }
\ No newline at end of file
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
before · tests/src/util/helpers.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { ApiPromise, Keyring } from '@polkadot/api';7import type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import { IKeyringPair } from '@polkadot/types/types';9import { evmToAddress } from '@polkadot/util-crypto';10import { BigNumber } from 'bignumber.js';11import BN from 'bn.js';12import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14import { alicesPublicKey } from '../accounts';15import privateKey from '../substrate/privateKey';16import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { ICollectionInterface } from '../types';18import { hexToStr, strToUTF16, utf16ToStr } from './util';1920chai.use(chaiAsPromised);21const expect = chai.expect;2223export type CrossAccountId = {24  substrate: string,25} | {26  ethereum: string,27};28export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {29  if (typeof input === 'string')30    return { substrate: input };31  if ('address' in input) {32    return { substrate: input.address };33  }34  if ('ethereum' in input) {35    input.ethereum = input.ethereum.toLowerCase();36    return input;37  }38  if ('substrate' in input) {39    return input;40  }4142  // AccountId43  return {substrate: input.toString()};44}45export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {46  input = normalizeAccountId(input);47  if ('substrate' in input) {48    return input.substrate;49  } else {50    return evmToAddress(input.ethereum);51  }52}5354export const U128_MAX = (1n << 128n) - 1n;5556type GenericResult = {57  success: boolean,58};5960interface CreateCollectionResult {61  success: boolean;62  collectionId: number;63}6465interface CreateItemResult {66  success: boolean;67  collectionId: number;68  itemId: number;69  recipient?: CrossAccountId;70}7172interface TransferResult {73  success: boolean;74  collectionId: number;75  itemId: number;76  sender?: CrossAccountId;77  recipient?: CrossAccountId;78  value: bigint;79}8081interface IReFungibleOwner {82  Fraction: BN;83  Owner: number[];84}8586interface ITokenDataType {87  Owner: IKeyringPair;88  ConstData: number[];89  VariableData: number[];90}9192interface IGetMessage {93  checkMsgNftMethod: string;94  checkMsgTrsMethod: string;95  checkMsgSysMethod: string;96}9798export interface IFungibleTokenDataType {99  Value: number;100}101102export interface IChainLimits {103  CollectionNumbersLimit: number;104	AccountTokenOwnershipLimit: number;105	CollectionsAdminsLimit: number;106	CustomDataLimit: number;107	NftSponsorTransferTimeout: number;108	FungibleSponsorTransferTimeout: number;109	RefungibleSponsorTransferTimeout: number;110	OffchainSchemaLimit: number;111	VariableOnChainSchemaLimit: number;112	ConstOnChainSchemaLimit: number;113}114115export interface IReFungibleTokenDataType {116  Owner: IReFungibleOwner[];117  ConstData: number[];118  VariableData: number[];119}120121export function nftEventMessage(events: EventRecord[]): IGetMessage {122  let checkMsgNftMethod = '';123  let checkMsgTrsMethod = '';124  let checkMsgSysMethod = '';125  events.forEach(({ event: { method, section } }) => {126    if (section === 'nft') {127      checkMsgNftMethod = method;128    } else if (section === 'treasury') {129      checkMsgTrsMethod = method;130    } else if (section === 'system') {131      checkMsgSysMethod = method;132    } else { return null; }133  });134  const result: IGetMessage = {135    checkMsgNftMethod,136    checkMsgTrsMethod,137    checkMsgSysMethod,138  };139  return result;140}141142export function getGenericResult(events: EventRecord[]): GenericResult {143  const result: GenericResult = {144    success: false,145  };146  events.forEach(({ event: { method } }) => {147    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);148    if (method === 'ExtrinsicSuccess') {149      result.success = true;150    }151  });152  return result;153}154155156157export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {158  let success = false;159  let collectionId = 0;160  events.forEach(({ event: { data, method, section } }) => {161    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);162    if (method == 'ExtrinsicSuccess') {163      success = true;164    } else if ((section == 'nft') && (method == 'CollectionCreated')) {165      collectionId = parseInt(data[0].toString());166    }167  });168  const result: CreateCollectionResult = {169    success,170    collectionId,171  };172  return result;173}174175export function getCreateItemResult(events: EventRecord[]): CreateItemResult {176  let success = false;177  let collectionId = 0;178  let itemId = 0;179  let recipient;180  events.forEach(({ event: { data, method, section } }) => {181    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);182    if (method == 'ExtrinsicSuccess') {183      success = true;184    } else if ((section == 'nft') && (method == 'ItemCreated')) {185      collectionId = parseInt(data[0].toString());186      itemId = parseInt(data[1].toString());187      recipient = data[2].toJSON();188    }189  });190  const result: CreateItemResult = {191    success,192    collectionId,193    itemId,194    recipient,195  };196  return result;197}198199export function getTransferResult(events: EventRecord[]): TransferResult {200  const result: TransferResult = {201    success: false,202    collectionId: 0,203    itemId: 0,204    value: 0n,205  };206207  events.forEach(({ event: { data, method, section } }) => {208    if (method === 'ExtrinsicSuccess') {209      result.success = true;210    } else if (section === 'nft' && method === 'Transfer') {211      result.collectionId = +data[0].toString();212      result.itemId = +data[1].toString();213      result.sender = data[2].toJSON() as CrossAccountId;214      result.recipient = data[3].toJSON() as CrossAccountId;215      result.value = BigInt(data[4].toString());216    }217  });218219  return result;220}221222interface Invalid {223  type: 'Invalid';224}225226interface Nft {227  type: 'NFT';228}229230interface Fungible {231  type: 'Fungible';232  decimalPoints: number;233}234235interface ReFungible {236  type: 'ReFungible';237}238239type CollectionMode = Nft | Fungible | ReFungible | Invalid;240241export type CreateCollectionParams = {242  mode: CollectionMode,243  name: string,244  description: string,245  tokenPrefix: string,246};247248const defaultCreateCollectionParams: CreateCollectionParams = {249  description: 'description',250  mode: { type: 'NFT' },251  name: 'name',252  tokenPrefix: 'prefix',253};254255export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {256  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };257258  let collectionId = 0;259  await usingApi(async (api) => {260    // Get number of collections before the transaction261    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);262263    // Run the CreateCollection transaction264    const alicePrivateKey = privateKey('//Alice');265266    let modeprm = {};267    if (mode.type === 'NFT') {268      modeprm = { nft: null };269    } else if (mode.type === 'Fungible') {270      modeprm = { fungible: mode.decimalPoints };271    } else if (mode.type === 'ReFungible') {272      modeprm = { refungible: null };273    } else if (mode.type === 'Invalid') {274      modeprm = { invalid: null };275    }276277    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);278    const events = await submitTransactionAsync(alicePrivateKey, tx);279    const result = getCreateCollectionResult(events);280281    // Get number of collections after the transaction282    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);283284    // Get the collection285    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();286287    // What to expect288    // tslint:disable-next-line:no-unused-expression289    expect(result.success).to.be.true;290    expect(result.collectionId).to.be.equal(BcollectionCount);291    // tslint:disable-next-line:no-unused-expression292    expect(collection).to.be.not.null;293    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');294    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));295    expect(utf16ToStr(collection.Name)).to.be.equal(name);296    expect(utf16ToStr(collection.Description)).to.be.equal(description);297    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);298299    collectionId = result.collectionId;300  });301302  return collectionId;303}304305export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {306  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };307308  let modeprm = {};309  if (mode.type === 'NFT') {310    modeprm = { nft: null };311  } else if (mode.type === 'Fungible') {312    modeprm = { fungible: mode.decimalPoints };313  } else if (mode.type === 'ReFungible') {314    modeprm = { refungible: null };315  } else if (mode.type === 'Invalid') {316    modeprm = { invalid: null };317  }318319  await usingApi(async (api) => {320    // Get number of collections before the transaction321    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());322323    // Run the CreateCollection transaction324    const alicePrivateKey = privateKey('//Alice');325    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);326    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;327    const result = getCreateCollectionResult(events);328329    // Get number of collections after the transaction330    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());331332    // What to expect333    // tslint:disable-next-line:no-unused-expression334    expect(result.success).to.be.false;335    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');336  });337}338339export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {340  let bal = new BigNumber(0);341  let unused;342  do {343    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;344    const keyring = new Keyring({ type: 'sr25519' });345    unused = keyring.addFromUri(`//${randomSeed}`);346    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());347  } while (bal.toFixed() != '0');348  return unused;349}350351export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {352  return await usingApi(async (api) => {353    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;354    return BigInt(bn.toString());355  });356}357358export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {359  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));360}361362export async function findNotExistingCollection(api: ApiPromise): Promise<number> {363  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;364  const newCollection: number = totalNumber + 1;365  return newCollection;366}367368function getDestroyResult(events: EventRecord[]): boolean {369  let success = false;370  events.forEach(({ event: { method } }) => {371    if (method == 'ExtrinsicSuccess') {372      success = true;373    }374  });375  return success;376}377378export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {379  await usingApi(async (api) => {380    // Run the DestroyCollection transaction381    const alicePrivateKey = privateKey(senderSeed);382    const tx = api.tx.nft.destroyCollection(collectionId);383    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;384  });385}386387export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {388  await usingApi(async (api) => {389    // Run the DestroyCollection transaction390    const alicePrivateKey = privateKey(senderSeed);391    const tx = api.tx.nft.destroyCollection(collectionId);392    const events = await submitTransactionAsync(alicePrivateKey, tx);393    const result = getDestroyResult(events);394395    // Get the collection396    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();397398    // What to expect399    expect(result).to.be.true;400    expect(collection).to.be.null;401  });402}403404export async function queryCollectionLimits(collectionId: number) {405  return await usingApi(async (api) => {406    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;407  });408}409410export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {411  await usingApi(async (api) => {412    const oldLimits = await queryCollectionLimits(collectionId);413    const newLimits = { ...oldLimits as any, ...limits };414    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);415    const events = await submitTransactionAsync(sender, tx);416    const result = getGenericResult(events);417418    expect(result.success).to.be.true;419  });420}421422export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {423  await usingApi(async (api) => {424    const oldLimits = await queryCollectionLimits(collectionId);425    const newLimits = { ...oldLimits as any, ...limits };426    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);427    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;428    const result = getGenericResult(events);429430    expect(result.success).to.be.false;431  });432}433434export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {435  await usingApi(async (api) => {436437    // Run the transaction438    const senderPrivateKey = privateKey(sender);439    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);440    const events = await submitTransactionAsync(senderPrivateKey, tx);441    const result = getGenericResult(events);442443    // Get the collection444    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();445446    // What to expect447    expect(result.success).to.be.true;448    expect(collection.Sponsorship).to.deep.equal({449      unconfirmed: sponsor,450    });451  });452}453454export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {455  await usingApi(async (api) => {456457    // Run the transaction458    const alicePrivateKey = privateKey(sender);459    const tx = api.tx.nft.removeCollectionSponsor(collectionId);460    const events = await submitTransactionAsync(alicePrivateKey, tx);461    const result = getGenericResult(events);462463    // Get the collection464    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();465466    // What to expect467    expect(result.success).to.be.true;468    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });469  });470}471472export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {473  await usingApi(async (api) => {474475    // Run the transaction476    const alicePrivateKey = privateKey(senderSeed);477    const tx = api.tx.nft.removeCollectionSponsor(collectionId);478    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;479  });480}481482export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {483  await usingApi(async (api) => {484485    // Run the transaction486    const alicePrivateKey = privateKey(senderSeed);487    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);488    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;489  });490}491492export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {493  await usingApi(async (api) => {494495    // Run the transaction496    const sender = privateKey(senderSeed);497    const tx = api.tx.nft.confirmSponsorship(collectionId);498    const events = await submitTransactionAsync(sender, tx);499    const result = getGenericResult(events);500501    // Get the collection502    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();503504    // What to expect505    expect(result.success).to.be.true;506    expect(collection.Sponsorship).to.be.deep.equal({507      confirmed: sender.address,508    });509  });510}511512513export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {514  await usingApi(async (api) => {515516    // Run the transaction517    const sender = privateKey(senderSeed);518    const tx = api.tx.nft.confirmSponsorship(collectionId);519    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;520  });521}522523export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {524  await usingApi(async (api) => {525    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);526    const events = await submitTransactionAsync(sender, tx);527    const result = getGenericResult(events);528529    expect(result.success).to.be.true;530  });531}532533export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {534  await usingApi(async (api) => {535    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);536    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;537    const result = getGenericResult(events);538539    expect(result.success).to.be.false;540  });541}542543export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {544545  await usingApi(async (api) => {546547    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);548    const events = await submitTransactionAsync(sender, tx);549    const result = getGenericResult(events);550551    expect(result.success).to.be.true;552  }); 553}554555export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {556557  await usingApi(async (api) => {558559    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);560    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;561    const result = getGenericResult(events);562563    expect(result.success).to.be.false;564  }); 565}566567export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {568  await usingApi(async (api) => {569    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);570    const events = await submitTransactionAsync(sender, tx);571    const result = getGenericResult(events);572573    expect(result.success).to.be.true;574  });575}576577export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {578  await usingApi(async (api) => {579    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);580    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;581    const result = getGenericResult(events);582583    expect(result.success).to.be.false;584  });585}586587export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {588  await usingApi(async (api) => {589    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, value);590    const events = await submitTransactionAsync(sender, tx);591    const result = getGenericResult(events);592593    expect(result.success).to.be.true;594  });595}596597export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {598  let whitelisted = false;599  await usingApi(async (api) => {600    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;601  });602  return whitelisted;603}604605export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {606  await usingApi(async (api) => {607    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());608    const events = await submitTransactionAsync(sender, tx);609    const result = getGenericResult(events);610611    expect(result.success).to.be.true;612  });613}614615export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {616  await usingApi(async (api) => {617    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());618    const events = await submitTransactionAsync(sender, tx);619    const result = getGenericResult(events);620621    expect(result.success).to.be.true;622  });623}624625export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {626  await usingApi(async (api) => {627    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());628    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;629    const result = getGenericResult(events);630631    expect(result.success).to.be.false;632  });633}634635export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {636  await usingApi(async (api) => {637    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));638    const events = await submitTransactionAsync(sender, tx);639    const result = getGenericResult(events);640641    expect(result.success).to.be.true;642  });643}644645export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {646  await usingApi(async (api) => {647    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));648    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;649  });650}651652export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {653  await usingApi(async (api) => {654    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));655    const events = await submitTransactionAsync(sender, tx);656    const result = getGenericResult(events);657658    expect(result.success).to.be.true;659  });660}661662export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {663  await usingApi(async (api) => {664    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));665    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;666  });667}668669export interface CreateFungibleData {670  readonly Value: bigint;671}672673export interface CreateReFungibleData { }674export interface CreateNftData { }675676export type CreateItemData = {677  NFT: CreateNftData;678} | {679  Fungible: CreateFungibleData;680} | {681  ReFungible: CreateReFungibleData;682};683684export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {685  await usingApi(async (api) => {686    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);687    const events = await submitTransactionAsync(owner, tx);688    const result = getGenericResult(events);689    // Get the item690    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();691    // What to expect692    // tslint:disable-next-line:no-unused-expression693    expect(result.success).to.be.true;694    // tslint:disable-next-line:no-unused-expression695    expect(item).to.be.null;696  });697}698699export async function700approveExpectSuccess(701  collectionId: number,702  tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1,703) {704  await usingApi(async (api: ApiPromise) => {705    approved = normalizeAccountId(approved);706    const allowanceBefore =707      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;708    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);709    const events = await submitTransactionAsync(owner, approveNftTx);710    const result = getCreateItemResult(events);711    // tslint:disable-next-line:no-unused-expression712    expect(result.success).to.be.true;713    const allowanceAfter =714      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;715    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());716  });717}718719export async function720transferFromExpectSuccess(721  collectionId: number,722  tokenId: number,723  accountApproved: IKeyringPair,724  accountFrom: IKeyringPair | CrossAccountId,725  accountTo: IKeyringPair | CrossAccountId,726  value: number | bigint = 1,727  type = 'NFT',728) {729  await usingApi(async (api: ApiPromise) => {730    const to = normalizeAccountId(accountTo);731    let balanceBefore = new BN(0);732    if (type === 'Fungible') {733      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;734    }735    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);736    const events = await submitTransactionAsync(accountApproved, transferFromTx);737    const result = getCreateItemResult(events);738    // tslint:disable-next-line:no-unused-expression739    expect(result.success).to.be.true;740    if (type === 'NFT') {741      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;742      expect(nftItemData.Owner).to.be.deep.equal(to);743    }744    if (type === 'Fungible') {745      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;746      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());747    }748    if (type === 'ReFungible') {749      const nftItemData =750        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;751      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));752      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);753    }754  });755}756757export async function758transferFromExpectFail(759  collectionId: number,760  tokenId: number,761  accountApproved: IKeyringPair,762  accountFrom: IKeyringPair,763  accountTo: IKeyringPair,764  value: number | bigint = 1,765) {766  await usingApi(async (api: ApiPromise) => {767    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);768    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;769    const result = getCreateCollectionResult(events);770    // tslint:disable-next-line:no-unused-expression771    expect(result.success).to.be.false;772  });773}774775/* eslint no-async-promise-executor: "off" */776async function getBlockNumber(api: ApiPromise): Promise<number> {777  return new Promise<number>(async (resolve) => {778    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {779      unsubscribe();780      resolve(head.number.toNumber());781    });782  });783}784785export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: IKeyringPair) {786  await usingApi(async (api) => {787    const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(address.address));788    const events = await submitTransactionAsync(sender, changeAdminTx);789    const result = getCreateCollectionResult(events);790    expect(result.success).to.be.true;791  });792}793794export async function795scheduleTransferExpectSuccess(796  collectionId: number,797  tokenId: number,798  sender: IKeyringPair,799  recipient: IKeyringPair,800  value: number | bigint = 1,801  blockTimeMs: number,802  blockSchedule: number,803) {804  await usingApi(async (api: ApiPromise) => {805    const blockNumber: number | undefined = await getBlockNumber(api);806    const expectedBlockNumber = blockNumber + blockSchedule;807808    expect(blockNumber).to.be.greaterThan(0);809    const transferTx = await api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value); 810    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);811812    await submitTransactionAsync(sender, scheduleTx);813814    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());815816    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as any as ITokenDataType;817    expect(toSubstrateAddress(nftItemDataBefore.Owner)).to.be.equal(sender.address);818819    // sleep for 4 blocks820    await new Promise(resolve => setTimeout(resolve, blockTimeMs * (blockSchedule + 1)));821822    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());823824    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;825    expect(toSubstrateAddress(nftItemData.Owner)).to.be.equal(recipient.address);826    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());827  });828}829830831export async function832transferExpectSuccess(833  collectionId: number,834  tokenId: number,835  sender: IKeyringPair,836  recipient: IKeyringPair | CrossAccountId,837  value: number | bigint = 1,838  type = 'NFT',839) {840  await usingApi(async (api: ApiPromise) => {841    const to = normalizeAccountId(recipient);842843    let balanceBefore = new BN(0);844    if (type === 'Fungible') {845      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;846    }847    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);848    const events = await submitTransactionAsync(sender, transferTx);849    const result = getTransferResult(events);850    // tslint:disable-next-line:no-unused-expression851    expect(result.success).to.be.true;852    expect(result.collectionId).to.be.equal(collectionId);853    expect(result.itemId).to.be.equal(tokenId);854    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));855    expect(result.recipient).to.be.deep.equal(to);856    expect(result.value.toString()).to.be.equal(value.toString());857    if (type === 'NFT') {858      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;859      expect(nftItemData.Owner).to.be.deep.equal(to);860    }861    if (type === 'Fungible') {862      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;863      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());864    }865    if (type === 'ReFungible') {866      const nftItemData =867        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;868      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);869      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());870    }871  });872}873874export async function875transferExpectFailure(876  collectionId: number,877  tokenId: number,878  sender: IKeyringPair,879  recipient: IKeyringPair,880  value: number | bigint = 1,881) {882  await usingApi(async (api: ApiPromise) => {883    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);884    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;885    if (events && Array.isArray(events)) {886      const result = getCreateCollectionResult(events);887      // tslint:disable-next-line:no-unused-expression888      expect(result.success).to.be.false;889    }890  });891}892893export async function894approveExpectFail(895  collectionId: number,896  tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,897) {898  await usingApi(async (api: ApiPromise) => {899    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);900    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;901    const result = getCreateCollectionResult(events);902    // tslint:disable-next-line:no-unused-expression903    expect(result.success).to.be.false;904  });905}906907export async function getFungibleBalance(908  collectionId: number,909  owner: string,910) {911  return await usingApi(async (api) => {912    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };913    return BigInt(response.Value);914  });915}916917export async function createFungibleItemExpectSuccess(918  sender: IKeyringPair,919  collectionId: number,920  data: CreateFungibleData,921  owner: CrossAccountId | string = sender.address,922) {923  return await usingApi(async (api) => {924    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });925926    const events = await submitTransactionAsync(sender, tx);927    const result = getCreateItemResult(events);928929    expect(result.success).to.be.true;930    return result.itemId;931  });932}933934export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {935  let newItemId = 0;936  await usingApi(async (api) => {937    const to = normalizeAccountId(owner);938    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);939    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();940    const AItemBalance = new BigNumber(Aitem.Value);941942    let tx;943    if (createMode === 'Fungible') {944      const createData = { fungible: { value: 10 } };945      tx = api.tx.nft.createItem(collectionId, to, createData);946    } else if (createMode === 'ReFungible') {947      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };948      tx = api.tx.nft.createItem(collectionId, to, createData);949    } else {950      const createData = { nft: { const_data: [], variable_data: [] } };951      tx = api.tx.nft.createItem(collectionId, to, createData);952    }953954    const events = await submitTransactionAsync(sender, tx);955    const result = getCreateItemResult(events);956957    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);958    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();959    const BItemBalance = new BigNumber(Bitem.Value);960961    // What to expect962    // tslint:disable-next-line:no-unused-expression963    expect(result.success).to.be.true;964    if (createMode === 'Fungible') {965      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);966    } else {967      expect(BItemCount).to.be.equal(AItemCount + 1);968    }969    expect(collectionId).to.be.equal(result.collectionId);970    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());971    expect(to).to.be.deep.equal(result.recipient);972    newItemId = result.itemId;973  });974  return newItemId;975}976977export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {978  await usingApi(async (api) => {979    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);980    981    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;982    const result = getCreateItemResult(events);983984    expect(result.success).to.be.false;985  });986}987988export async function setPublicAccessModeExpectSuccess(989  sender: IKeyringPair, collectionId: number,990  accessMode: 'Normal' | 'WhiteList',991) {992  await usingApi(async (api) => {993994    // Run the transaction995    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);996    const events = await submitTransactionAsync(sender, tx);997    const result = getGenericResult(events);998999    // Get the collection1000    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10011002    // What to expect1003    // tslint:disable-next-line:no-unused-expression1004    expect(result.success).to.be.true;1005    expect(collection.Access).to.be.equal(accessMode);1006  });1007}10081009export async function setPublicAccessModeExpectFail(1010  sender: IKeyringPair, collectionId: number,1011  accessMode: 'Normal' | 'WhiteList',1012) {1013  await usingApi(async (api) => {10141015    // Run the transaction1016    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1017    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1018    const result = getGenericResult(events);10191020    // What to expect1021    // tslint:disable-next-line:no-unused-expression1022    expect(result.success).to.be.false;1023  });1024}10251026export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1027  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');1028}10291030export async function enableWhiteListExpectFail(sender: IKeyringPair, collectionId: number) {1031  await setPublicAccessModeExpectFail(sender, collectionId, 'WhiteList');1032}10331034export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1035  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1036}10371038export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1039  await usingApi(async (api) => {10401041    // Run the transaction1042    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1043    const events = await submitTransactionAsync(sender, tx);1044    const result = getGenericResult(events);10451046    // Get the collection1047    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10481049    // What to expect1050    // tslint:disable-next-line:no-unused-expression1051    expect(result.success).to.be.true;1052    expect(collection.MintMode).to.be.equal(enabled);1053  });1054}10551056export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1057  await setMintPermissionExpectSuccess(sender, collectionId, true);1058}10591060export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1061  await usingApi(async (api) => {1062    // Run the transaction1063    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1064    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1065    const result = getCreateCollectionResult(events);1066    // tslint:disable-next-line:no-unused-expression1067    expect(result.success).to.be.false;1068  });1069}10701071export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1072  await usingApi(async (api) => {1073    // Run the transaction1074    const tx = api.tx.nft.setChainLimits(limits);1075    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1076    const result = getCreateCollectionResult(events);1077    // tslint:disable-next-line:no-unused-expression1078    expect(result.success).to.be.false;1079  });1080}10811082export async function isWhitelisted(collectionId: number, address: string) {1083  let whitelisted = false;1084  await usingApi(async (api) => {1085    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1086  });1087  return whitelisted;1088}10891090export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1091  await usingApi(async (api) => {10921093    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10941095    // Run the transaction1096    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1097    const events = await submitTransactionAsync(sender, tx);1098    const result = getGenericResult(events);10991100    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();11011102    // What to expect1103    // tslint:disable-next-line:no-unused-expression1104    expect(result.success).to.be.true;1105    // tslint:disable-next-line: no-unused-expression1106    expect(whiteListedBefore).to.be.false;1107    // tslint:disable-next-line: no-unused-expression1108    expect(whiteListedAfter).to.be.true;1109  });1110}11111112export async function addToWhiteListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1113  await usingApi(async (api) => {1114    // Run the transaction1115    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1116    const events = await expect(submitTransactionAsync(sender, tx)).to.be.rejected;1117    const result = getGenericResult(events);11181119    // What to expect1120    // tslint:disable-next-line:no-unused-expression1121    expect(result.success).to.be.false;1122  });1123}11241125export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1126  await usingApi(async (api) => {1127    // Run the transaction1128    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1129    const events = await submitTransactionAsync(sender, tx);1130    const result = getGenericResult(events);11311132    // What to expect1133    // tslint:disable-next-line:no-unused-expression1134    expect(result.success).to.be.true;1135  });1136}11371138export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1139  await usingApi(async (api) => {1140    // Run the transaction1141    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1142    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1143    const result = getGenericResult(events);11441145    // What to expect1146    // tslint:disable-next-line:no-unused-expression1147    expect(result.success).to.be.false;1148  });1149}11501151export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1152  : Promise<ICollectionInterface | null> => {1153  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1154};11551156export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1157  // set global object - collectionsCount1158  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1159};11601161export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1162  return await usingApi(async (api) => {1163    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1164  });1165}
after · tests/src/util/helpers.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { ApiPromise, Keyring } from '@polkadot/api';7import type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import { IKeyringPair } from '@polkadot/types/types';9import { evmToAddress } from '@polkadot/util-crypto';10import { BigNumber } from 'bignumber.js';11import BN from 'bn.js';12import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14import { alicesPublicKey } from '../accounts';15import privateKey from '../substrate/privateKey';16import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { ICollectionInterface } from '../types';18import { hexToStr, strToUTF16, utf16ToStr } from './util';1920chai.use(chaiAsPromised);21const expect = chai.expect;2223export type CrossAccountId = {24  substrate: string,25} | {26  ethereum: string,27};28export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {29  if (typeof input === 'string')30    return { substrate: input };31  if ('address' in input) {32    return { substrate: input.address };33  }34  if ('ethereum' in input) {35    input.ethereum = input.ethereum.toLowerCase();36    return input;37  }38  if ('substrate' in input) {39    return input;40  }4142  // AccountId43  return {substrate: input.toString()};44}45export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {46  input = normalizeAccountId(input);47  if ('substrate' in input) {48    return input.substrate;49  } else {50    return evmToAddress(input.ethereum);51  }52}5354export const U128_MAX = (1n << 128n) - 1n;5556const MICROUNIQUE = 1_000_000_000n;57const MILLIUNIQUE = 1_000n * MICROUNIQUE;58const CENTIUNIQUE = 10n * MILLIUNIQUE;59export const UNIQUE = 100n * CENTIUNIQUE;6061type GenericResult = {62  success: boolean,63};6465interface CreateCollectionResult {66  success: boolean;67  collectionId: number;68}6970interface CreateItemResult {71  success: boolean;72  collectionId: number;73  itemId: number;74  recipient?: CrossAccountId;75}7677interface TransferResult {78  success: boolean;79  collectionId: number;80  itemId: number;81  sender?: CrossAccountId;82  recipient?: CrossAccountId;83  value: bigint;84}8586interface IReFungibleOwner {87  Fraction: BN;88  Owner: number[];89}9091interface ITokenDataType {92  Owner: IKeyringPair;93  ConstData: number[];94  VariableData: number[];95}9697interface IGetMessage {98  checkMsgNftMethod: string;99  checkMsgTrsMethod: string;100  checkMsgSysMethod: string;101}102103export interface IFungibleTokenDataType {104  Value: number;105}106107export interface IChainLimits {108  CollectionNumbersLimit: number;109	AccountTokenOwnershipLimit: number;110	CollectionsAdminsLimit: number;111	CustomDataLimit: number;112	NftSponsorTransferTimeout: number;113	FungibleSponsorTransferTimeout: number;114	RefungibleSponsorTransferTimeout: number;115	OffchainSchemaLimit: number;116	VariableOnChainSchemaLimit: number;117	ConstOnChainSchemaLimit: number;118}119120export interface IReFungibleTokenDataType {121  Owner: IReFungibleOwner[];122  ConstData: number[];123  VariableData: number[];124}125126export function nftEventMessage(events: EventRecord[]): IGetMessage {127  let checkMsgNftMethod = '';128  let checkMsgTrsMethod = '';129  let checkMsgSysMethod = '';130  events.forEach(({ event: { method, section } }) => {131    if (section === 'nft') {132      checkMsgNftMethod = method;133    } else if (section === 'treasury') {134      checkMsgTrsMethod = method;135    } else if (section === 'system') {136      checkMsgSysMethod = method;137    } else { return null; }138  });139  const result: IGetMessage = {140    checkMsgNftMethod,141    checkMsgTrsMethod,142    checkMsgSysMethod,143  };144  return result;145}146147export function getGenericResult(events: EventRecord[]): GenericResult {148  const result: GenericResult = {149    success: false,150  };151  events.forEach(({ event: { method } }) => {152    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);153    if (method === 'ExtrinsicSuccess') {154      result.success = true;155    }156  });157  return result;158}159160161162export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {163  let success = false;164  let collectionId = 0;165  events.forEach(({ event: { data, method, section } }) => {166    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);167    if (method == 'ExtrinsicSuccess') {168      success = true;169    } else if ((section == 'nft') && (method == 'CollectionCreated')) {170      collectionId = parseInt(data[0].toString());171    }172  });173  const result: CreateCollectionResult = {174    success,175    collectionId,176  };177  return result;178}179180export function getCreateItemResult(events: EventRecord[]): CreateItemResult {181  let success = false;182  let collectionId = 0;183  let itemId = 0;184  let recipient;185  events.forEach(({ event: { data, method, section } }) => {186    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);187    if (method == 'ExtrinsicSuccess') {188      success = true;189    } else if ((section == 'nft') && (method == 'ItemCreated')) {190      collectionId = parseInt(data[0].toString());191      itemId = parseInt(data[1].toString());192      recipient = data[2].toJSON();193    }194  });195  const result: CreateItemResult = {196    success,197    collectionId,198    itemId,199    recipient,200  };201  return result;202}203204export function getTransferResult(events: EventRecord[]): TransferResult {205  const result: TransferResult = {206    success: false,207    collectionId: 0,208    itemId: 0,209    value: 0n,210  };211212  events.forEach(({ event: { data, method, section } }) => {213    if (method === 'ExtrinsicSuccess') {214      result.success = true;215    } else if (section === 'nft' && method === 'Transfer') {216      result.collectionId = +data[0].toString();217      result.itemId = +data[1].toString();218      result.sender = data[2].toJSON() as CrossAccountId;219      result.recipient = data[3].toJSON() as CrossAccountId;220      result.value = BigInt(data[4].toString());221    }222  });223224  return result;225}226227interface Invalid {228  type: 'Invalid';229}230231interface Nft {232  type: 'NFT';233}234235interface Fungible {236  type: 'Fungible';237  decimalPoints: number;238}239240interface ReFungible {241  type: 'ReFungible';242}243244type CollectionMode = Nft | Fungible | ReFungible | Invalid;245246export type CreateCollectionParams = {247  mode: CollectionMode,248  name: string,249  description: string,250  tokenPrefix: string,251};252253const defaultCreateCollectionParams: CreateCollectionParams = {254  description: 'description',255  mode: { type: 'NFT' },256  name: 'name',257  tokenPrefix: 'prefix',258};259260export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {261  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };262263  let collectionId = 0;264  await usingApi(async (api) => {265    // Get number of collections before the transaction266    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);267268    // Run the CreateCollection transaction269    const alicePrivateKey = privateKey('//Alice');270271    let modeprm = {};272    if (mode.type === 'NFT') {273      modeprm = { nft: null };274    } else if (mode.type === 'Fungible') {275      modeprm = { fungible: mode.decimalPoints };276    } else if (mode.type === 'ReFungible') {277      modeprm = { refungible: null };278    } else if (mode.type === 'Invalid') {279      modeprm = { invalid: null };280    }281282    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);283    const events = await submitTransactionAsync(alicePrivateKey, tx);284    const result = getCreateCollectionResult(events);285286    // Get number of collections after the transaction287    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);288289    // Get the collection290    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();291292    // What to expect293    // tslint:disable-next-line:no-unused-expression294    expect(result.success).to.be.true;295    expect(result.collectionId).to.be.equal(BcollectionCount);296    // tslint:disable-next-line:no-unused-expression297    expect(collection).to.be.not.null;298    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');299    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));300    expect(utf16ToStr(collection.Name)).to.be.equal(name);301    expect(utf16ToStr(collection.Description)).to.be.equal(description);302    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);303304    collectionId = result.collectionId;305  });306307  return collectionId;308}309310export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {311  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };312313  let modeprm = {};314  if (mode.type === 'NFT') {315    modeprm = { nft: null };316  } else if (mode.type === 'Fungible') {317    modeprm = { fungible: mode.decimalPoints };318  } else if (mode.type === 'ReFungible') {319    modeprm = { refungible: null };320  } else if (mode.type === 'Invalid') {321    modeprm = { invalid: null };322  }323324  await usingApi(async (api) => {325    // Get number of collections before the transaction326    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());327328    // Run the CreateCollection transaction329    const alicePrivateKey = privateKey('//Alice');330    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);331    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;332    const result = getCreateCollectionResult(events);333334    // Get number of collections after the transaction335    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());336337    // What to expect338    // tslint:disable-next-line:no-unused-expression339    expect(result.success).to.be.false;340    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');341  });342}343344export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {345  let bal = new BigNumber(0);346  let unused;347  do {348    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;349    const keyring = new Keyring({ type: 'sr25519' });350    unused = keyring.addFromUri(`//${randomSeed}`);351    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());352  } while (bal.toFixed() != '0');353  return unused;354}355356export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {357  return await usingApi(async (api) => {358    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;359    return BigInt(bn.toString());360  });361}362363export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {364  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));365}366367export async function findNotExistingCollection(api: ApiPromise): Promise<number> {368  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;369  const newCollection: number = totalNumber + 1;370  return newCollection;371}372373function getDestroyResult(events: EventRecord[]): boolean {374  let success = false;375  events.forEach(({ event: { method } }) => {376    if (method == 'ExtrinsicSuccess') {377      success = true;378    }379  });380  return success;381}382383export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {384  await usingApi(async (api) => {385    // Run the DestroyCollection transaction386    const alicePrivateKey = privateKey(senderSeed);387    const tx = api.tx.nft.destroyCollection(collectionId);388    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;389  });390}391392export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {393  await usingApi(async (api) => {394    // Run the DestroyCollection transaction395    const alicePrivateKey = privateKey(senderSeed);396    const tx = api.tx.nft.destroyCollection(collectionId);397    const events = await submitTransactionAsync(alicePrivateKey, tx);398    const result = getDestroyResult(events);399400    // Get the collection401    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();402403    // What to expect404    expect(result).to.be.true;405    expect(collection).to.be.null;406  });407}408409export async function queryCollectionLimits(collectionId: number) {410  return await usingApi(async (api) => {411    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;412  });413}414415export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {416  await usingApi(async (api) => {417    const oldLimits = await queryCollectionLimits(collectionId);418    const newLimits = { ...oldLimits as any, ...limits };419    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);420    const events = await submitTransactionAsync(sender, tx);421    const result = getGenericResult(events);422423    expect(result.success).to.be.true;424  });425}426427export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {428  await usingApi(async (api) => {429    const oldLimits = await queryCollectionLimits(collectionId);430    const newLimits = { ...oldLimits as any, ...limits };431    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);432    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;433    const result = getGenericResult(events);434435    expect(result.success).to.be.false;436  });437}438439export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {440  await usingApi(async (api) => {441442    // Run the transaction443    const senderPrivateKey = privateKey(sender);444    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);445    const events = await submitTransactionAsync(senderPrivateKey, tx);446    const result = getGenericResult(events);447448    // Get the collection449    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();450451    // What to expect452    expect(result.success).to.be.true;453    expect(collection.Sponsorship).to.deep.equal({454      unconfirmed: sponsor,455    });456  });457}458459export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {460  await usingApi(async (api) => {461462    // Run the transaction463    const alicePrivateKey = privateKey(sender);464    const tx = api.tx.nft.removeCollectionSponsor(collectionId);465    const events = await submitTransactionAsync(alicePrivateKey, tx);466    const result = getGenericResult(events);467468    // Get the collection469    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();470471    // What to expect472    expect(result.success).to.be.true;473    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });474  });475}476477export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {478  await usingApi(async (api) => {479480    // Run the transaction481    const alicePrivateKey = privateKey(senderSeed);482    const tx = api.tx.nft.removeCollectionSponsor(collectionId);483    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;484  });485}486487export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {488  await usingApi(async (api) => {489490    // Run the transaction491    const alicePrivateKey = privateKey(senderSeed);492    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);493    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;494  });495}496497export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {498  await usingApi(async (api) => {499500    // Run the transaction501    const sender = privateKey(senderSeed);502    const tx = api.tx.nft.confirmSponsorship(collectionId);503    const events = await submitTransactionAsync(sender, tx);504    const result = getGenericResult(events);505506    // Get the collection507    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();508509    // What to expect510    expect(result.success).to.be.true;511    expect(collection.Sponsorship).to.be.deep.equal({512      confirmed: sender.address,513    });514  });515}516517518export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {519  await usingApi(async (api) => {520521    // Run the transaction522    const sender = privateKey(senderSeed);523    const tx = api.tx.nft.confirmSponsorship(collectionId);524    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;525  });526}527528export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {529  await usingApi(async (api) => {530    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);531    const events = await submitTransactionAsync(sender, tx);532    const result = getGenericResult(events);533534    expect(result.success).to.be.true;535  });536}537538export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {539  await usingApi(async (api) => {540    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);541    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;542    const result = getGenericResult(events);543544    expect(result.success).to.be.false;545  });546}547548export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {549550  await usingApi(async (api) => {551552    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);553    const events = await submitTransactionAsync(sender, tx);554    const result = getGenericResult(events);555556    expect(result.success).to.be.true;557  }); 558}559560export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {561562  await usingApi(async (api) => {563564    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);565    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;566    const result = getGenericResult(events);567568    expect(result.success).to.be.false;569  }); 570}571572export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {573  await usingApi(async (api) => {574    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);575    const events = await submitTransactionAsync(sender, tx);576    const result = getGenericResult(events);577578    expect(result.success).to.be.true;579  });580}581582export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {583  await usingApi(async (api) => {584    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);585    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;586    const result = getGenericResult(events);587588    expect(result.success).to.be.false;589  });590}591592export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {593  await usingApi(async (api) => {594    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, value);595    const events = await submitTransactionAsync(sender, tx);596    const result = getGenericResult(events);597598    expect(result.success).to.be.true;599  });600}601602export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {603  let whitelisted = false;604  await usingApi(async (api) => {605    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;606  });607  return whitelisted;608}609610export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {611  await usingApi(async (api) => {612    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());613    const events = await submitTransactionAsync(sender, tx);614    const result = getGenericResult(events);615616    expect(result.success).to.be.true;617  });618}619620export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {621  await usingApi(async (api) => {622    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());623    const events = await submitTransactionAsync(sender, tx);624    const result = getGenericResult(events);625626    expect(result.success).to.be.true;627  });628}629630export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {631  await usingApi(async (api) => {632    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());633    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;634    const result = getGenericResult(events);635636    expect(result.success).to.be.false;637  });638}639640export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {641  await usingApi(async (api) => {642    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));643    const events = await submitTransactionAsync(sender, tx);644    const result = getGenericResult(events);645646    expect(result.success).to.be.true;647  });648}649650export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {651  await usingApi(async (api) => {652    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));653    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;654  });655}656657export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {658  await usingApi(async (api) => {659    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));660    const events = await submitTransactionAsync(sender, tx);661    const result = getGenericResult(events);662663    expect(result.success).to.be.true;664  });665}666667export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {668  await usingApi(async (api) => {669    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));670    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;671  });672}673674export interface CreateFungibleData {675  readonly Value: bigint;676}677678export interface CreateReFungibleData { }679export interface CreateNftData { }680681export type CreateItemData = {682  NFT: CreateNftData;683} | {684  Fungible: CreateFungibleData;685} | {686  ReFungible: CreateReFungibleData;687};688689export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {690  await usingApi(async (api) => {691    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);692    const events = await submitTransactionAsync(owner, tx);693    const result = getGenericResult(events);694    // Get the item695    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();696    // What to expect697    // tslint:disable-next-line:no-unused-expression698    expect(result.success).to.be.true;699    // tslint:disable-next-line:no-unused-expression700    expect(item).to.be.null;701  });702}703704export async function705approveExpectSuccess(706  collectionId: number,707  tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1,708) {709  await usingApi(async (api: ApiPromise) => {710    approved = normalizeAccountId(approved);711    const allowanceBefore =712      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;713    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);714    const events = await submitTransactionAsync(owner, approveNftTx);715    const result = getCreateItemResult(events);716    // tslint:disable-next-line:no-unused-expression717    expect(result.success).to.be.true;718    const allowanceAfter =719      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;720    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());721  });722}723724export async function725transferFromExpectSuccess(726  collectionId: number,727  tokenId: number,728  accountApproved: IKeyringPair,729  accountFrom: IKeyringPair | CrossAccountId,730  accountTo: IKeyringPair | CrossAccountId,731  value: number | bigint = 1,732  type = 'NFT',733) {734  await usingApi(async (api: ApiPromise) => {735    const to = normalizeAccountId(accountTo);736    let balanceBefore = new BN(0);737    if (type === 'Fungible') {738      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;739    }740    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);741    const events = await submitTransactionAsync(accountApproved, transferFromTx);742    const result = getCreateItemResult(events);743    // tslint:disable-next-line:no-unused-expression744    expect(result.success).to.be.true;745    if (type === 'NFT') {746      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;747      expect(nftItemData.Owner).to.be.deep.equal(to);748    }749    if (type === 'Fungible') {750      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;751      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());752    }753    if (type === 'ReFungible') {754      const nftItemData =755        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;756      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));757      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);758    }759  });760}761762export async function763transferFromExpectFail(764  collectionId: number,765  tokenId: number,766  accountApproved: IKeyringPair,767  accountFrom: IKeyringPair,768  accountTo: IKeyringPair,769  value: number | bigint = 1,770) {771  await usingApi(async (api: ApiPromise) => {772    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);773    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;774    const result = getCreateCollectionResult(events);775    // tslint:disable-next-line:no-unused-expression776    expect(result.success).to.be.false;777  });778}779780/* eslint no-async-promise-executor: "off" */781async function getBlockNumber(api: ApiPromise): Promise<number> {782  return new Promise<number>(async (resolve) => {783    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {784      unsubscribe();785      resolve(head.number.toNumber());786    });787  });788}789790export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: IKeyringPair) {791  await usingApi(async (api) => {792    const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(address.address));793    const events = await submitTransactionAsync(sender, changeAdminTx);794    const result = getCreateCollectionResult(events);795    expect(result.success).to.be.true;796  });797}798799export async function800scheduleTransferExpectSuccess(801  collectionId: number,802  tokenId: number,803  sender: IKeyringPair,804  recipient: IKeyringPair,805  value: number | bigint = 1,806  blockTimeMs: number,807  blockSchedule: number,808) {809  await usingApi(async (api: ApiPromise) => {810    const blockNumber: number | undefined = await getBlockNumber(api);811    const expectedBlockNumber = blockNumber + blockSchedule;812813    expect(blockNumber).to.be.greaterThan(0);814    const transferTx = await api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value); 815    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);816817    await submitTransactionAsync(sender, scheduleTx);818819    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());820821    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as any as ITokenDataType;822    expect(toSubstrateAddress(nftItemDataBefore.Owner)).to.be.equal(sender.address);823824    // sleep for 4 blocks825    await new Promise(resolve => setTimeout(resolve, blockTimeMs * (blockSchedule + 1)));826827    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());828829    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;830    expect(toSubstrateAddress(nftItemData.Owner)).to.be.equal(recipient.address);831    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());832  });833}834835836export async function837transferExpectSuccess(838  collectionId: number,839  tokenId: number,840  sender: IKeyringPair,841  recipient: IKeyringPair | CrossAccountId,842  value: number | bigint = 1,843  type = 'NFT',844) {845  await usingApi(async (api: ApiPromise) => {846    const to = normalizeAccountId(recipient);847848    let balanceBefore = new BN(0);849    if (type === 'Fungible') {850      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;851    }852    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);853    const events = await submitTransactionAsync(sender, transferTx);854    const result = getTransferResult(events);855    // tslint:disable-next-line:no-unused-expression856    expect(result.success).to.be.true;857    expect(result.collectionId).to.be.equal(collectionId);858    expect(result.itemId).to.be.equal(tokenId);859    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));860    expect(result.recipient).to.be.deep.equal(to);861    expect(result.value.toString()).to.be.equal(value.toString());862    if (type === 'NFT') {863      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;864      expect(nftItemData.Owner).to.be.deep.equal(to);865    }866    if (type === 'Fungible') {867      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;868      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());869    }870    if (type === 'ReFungible') {871      const nftItemData =872        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;873      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);874      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());875    }876  });877}878879export async function880transferExpectFailure(881  collectionId: number,882  tokenId: number,883  sender: IKeyringPair,884  recipient: IKeyringPair,885  value: number | bigint = 1,886) {887  await usingApi(async (api: ApiPromise) => {888    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);889    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;890    if (events && Array.isArray(events)) {891      const result = getCreateCollectionResult(events);892      // tslint:disable-next-line:no-unused-expression893      expect(result.success).to.be.false;894    }895  });896}897898export async function899approveExpectFail(900  collectionId: number,901  tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,902) {903  await usingApi(async (api: ApiPromise) => {904    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);905    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;906    const result = getCreateCollectionResult(events);907    // tslint:disable-next-line:no-unused-expression908    expect(result.success).to.be.false;909  });910}911912export async function getFungibleBalance(913  collectionId: number,914  owner: string,915) {916  return await usingApi(async (api) => {917    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };918    return BigInt(response.Value);919  });920}921922export async function createFungibleItemExpectSuccess(923  sender: IKeyringPair,924  collectionId: number,925  data: CreateFungibleData,926  owner: CrossAccountId | string = sender.address,927) {928  return await usingApi(async (api) => {929    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });930931    const events = await submitTransactionAsync(sender, tx);932    const result = getCreateItemResult(events);933934    expect(result.success).to.be.true;935    return result.itemId;936  });937}938939export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {940  let newItemId = 0;941  await usingApi(async (api) => {942    const to = normalizeAccountId(owner);943    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);944    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();945    const AItemBalance = new BigNumber(Aitem.Value);946947    let tx;948    if (createMode === 'Fungible') {949      const createData = { fungible: { value: 10 } };950      tx = api.tx.nft.createItem(collectionId, to, createData);951    } else if (createMode === 'ReFungible') {952      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };953      tx = api.tx.nft.createItem(collectionId, to, createData);954    } else {955      const createData = { nft: { const_data: [], variable_data: [] } };956      tx = api.tx.nft.createItem(collectionId, to, createData);957    }958959    const events = await submitTransactionAsync(sender, tx);960    const result = getCreateItemResult(events);961962    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);963    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();964    const BItemBalance = new BigNumber(Bitem.Value);965966    // What to expect967    // tslint:disable-next-line:no-unused-expression968    expect(result.success).to.be.true;969    if (createMode === 'Fungible') {970      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);971    } else {972      expect(BItemCount).to.be.equal(AItemCount + 1);973    }974    expect(collectionId).to.be.equal(result.collectionId);975    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());976    expect(to).to.be.deep.equal(result.recipient);977    newItemId = result.itemId;978  });979  return newItemId;980}981982export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {983  await usingApi(async (api) => {984    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);985    986    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;987    const result = getCreateItemResult(events);988989    expect(result.success).to.be.false;990  });991}992993export async function setPublicAccessModeExpectSuccess(994  sender: IKeyringPair, collectionId: number,995  accessMode: 'Normal' | 'WhiteList',996) {997  await usingApi(async (api) => {998999    // Run the transaction1000    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1001    const events = await submitTransactionAsync(sender, tx);1002    const result = getGenericResult(events);10031004    // Get the collection1005    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10061007    // What to expect1008    // tslint:disable-next-line:no-unused-expression1009    expect(result.success).to.be.true;1010    expect(collection.Access).to.be.equal(accessMode);1011  });1012}10131014export async function setPublicAccessModeExpectFail(1015  sender: IKeyringPair, collectionId: number,1016  accessMode: 'Normal' | 'WhiteList',1017) {1018  await usingApi(async (api) => {10191020    // Run the transaction1021    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1022    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1023    const result = getGenericResult(events);10241025    // What to expect1026    // tslint:disable-next-line:no-unused-expression1027    expect(result.success).to.be.false;1028  });1029}10301031export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1032  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');1033}10341035export async function enableWhiteListExpectFail(sender: IKeyringPair, collectionId: number) {1036  await setPublicAccessModeExpectFail(sender, collectionId, 'WhiteList');1037}10381039export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1040  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1041}10421043export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1044  await usingApi(async (api) => {10451046    // Run the transaction1047    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1048    const events = await submitTransactionAsync(sender, tx);1049    const result = getGenericResult(events);10501051    // Get the collection1052    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10531054    // What to expect1055    // tslint:disable-next-line:no-unused-expression1056    expect(result.success).to.be.true;1057    expect(collection.MintMode).to.be.equal(enabled);1058  });1059}10601061export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1062  await setMintPermissionExpectSuccess(sender, collectionId, true);1063}10641065export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1066  await usingApi(async (api) => {1067    // Run the transaction1068    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1069    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1070    const result = getCreateCollectionResult(events);1071    // tslint:disable-next-line:no-unused-expression1072    expect(result.success).to.be.false;1073  });1074}10751076export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1077  await usingApi(async (api) => {1078    // Run the transaction1079    const tx = api.tx.nft.setChainLimits(limits);1080    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1081    const result = getCreateCollectionResult(events);1082    // tslint:disable-next-line:no-unused-expression1083    expect(result.success).to.be.false;1084  });1085}10861087export async function isWhitelisted(collectionId: number, address: string) {1088  let whitelisted = false;1089  await usingApi(async (api) => {1090    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1091  });1092  return whitelisted;1093}10941095export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1096  await usingApi(async (api) => {10971098    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10991100    // Run the transaction1101    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1102    const events = await submitTransactionAsync(sender, tx);1103    const result = getGenericResult(events);11041105    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();11061107    // What to expect1108    // tslint:disable-next-line:no-unused-expression1109    expect(result.success).to.be.true;1110    // tslint:disable-next-line: no-unused-expression1111    expect(whiteListedBefore).to.be.false;1112    // tslint:disable-next-line: no-unused-expression1113    expect(whiteListedAfter).to.be.true;1114  });1115}11161117export async function addToWhiteListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1118  await usingApi(async (api) => {1119    // Run the transaction1120    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1121    const events = await expect(submitTransactionAsync(sender, tx)).to.be.rejected;1122    const result = getGenericResult(events);11231124    // What to expect1125    // tslint:disable-next-line:no-unused-expression1126    expect(result.success).to.be.false;1127  });1128}11291130export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1131  await usingApi(async (api) => {1132    // Run the transaction1133    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1134    const events = await submitTransactionAsync(sender, tx);1135    const result = getGenericResult(events);11361137    // What to expect1138    // tslint:disable-next-line:no-unused-expression1139    expect(result.success).to.be.true;1140  });1141}11421143export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1144  await usingApi(async (api) => {1145    // Run the transaction1146    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1147    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1148    const result = getGenericResult(events);11491150    // What to expect1151    // tslint:disable-next-line:no-unused-expression1152    expect(result.success).to.be.false;1153  });1154}11551156export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1157  : Promise<ICollectionInterface | null> => {1158  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1159};11601161export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1162  // set global object - collectionsCount1163  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1164};11651166export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1167  return await usingApi(async (api) => {1168    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1169  });1170}
modifiedtests/yarn.lockdiffbeforeafterboth
--- a/tests/yarn.lock
+++ b/tests/yarn.lock
@@ -2,10 +2,10 @@
 # yarn lockfile v1
 
 
-"@babel/cli@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.14.5.tgz#9551b194f02360729de6060785bbdcce52c69f0a"
-  integrity sha512-poegjhRvXHWO0EAsnYajwYZuqcz7gyfxwfaecUESxDujrqOivf3zrjFbub8IJkrqEaz3fvJWh001EzxBub54fg==
+"@babel/cli@^7.14.8":
+  version "7.14.8"
+  resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.14.8.tgz#fac73c0e2328a8af9fd3560c06b096bfa3730933"
+  integrity sha512-lcy6Lymft9Rpfqmrqdd4oTDdUx9ZwaAhAfywVrHG4771Pa6PPT0danJ1kDHBXYqh4HHSmIdA+nlmfxfxSDPtBg==
   dependencies:
     commander "^4.0.1"
     convert-source-map "^1.1.0"
@@ -42,7 +42,12 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08"
   integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==
 
-"@babel/core@^7.1.0", "@babel/core@^7.14.6", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
+"@babel/compat-data@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176"
+  integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==
+
+"@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
   version "7.14.6"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab"
   integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==
@@ -63,6 +68,27 @@
     semver "^6.3.0"
     source-map "^0.5.0"
 
+"@babel/core@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8"
+  integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==
+  dependencies:
+    "@babel/code-frame" "^7.14.5"
+    "@babel/generator" "^7.15.0"
+    "@babel/helper-compilation-targets" "^7.15.0"
+    "@babel/helper-module-transforms" "^7.15.0"
+    "@babel/helpers" "^7.14.8"
+    "@babel/parser" "^7.15.0"
+    "@babel/template" "^7.14.5"
+    "@babel/traverse" "^7.15.0"
+    "@babel/types" "^7.15.0"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.2"
+    json5 "^2.1.2"
+    semver "^6.3.0"
+    source-map "^0.5.0"
+
 "@babel/generator@^7.14.5", "@babel/generator@^7.7.2":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785"
@@ -72,6 +98,15 @@
     jsesc "^2.5.1"
     source-map "^0.5.0"
 
+"@babel/generator@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15"
+  integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==
+  dependencies:
+    "@babel/types" "^7.15.0"
+    jsesc "^2.5.1"
+    source-map "^0.5.0"
+
 "@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61"
@@ -97,7 +132,17 @@
     browserslist "^4.16.6"
     semver "^6.3.0"
 
-"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.14.6":
+"@babel/helper-compilation-targets@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818"
+  integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==
+  dependencies:
+    "@babel/compat-data" "^7.15.0"
+    "@babel/helper-validator-option" "^7.14.5"
+    browserslist "^4.16.6"
+    semver "^6.3.0"
+
+"@babel/helper-create-class-features-plugin@^7.14.5":
   version "7.14.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz#f114469b6c06f8b5c59c6c4e74621f5085362542"
   integrity sha512-Z6gsfGofTxH/+LQXqYEK45kxmcensbzmk/oi8DmaQytlQCgqNZt9XQF8iqlI/SeXWVjaMNxvYvzaYw+kh42mDg==
@@ -109,6 +154,18 @@
     "@babel/helper-replace-supers" "^7.14.5"
     "@babel/helper-split-export-declaration" "^7.14.5"
 
+"@babel/helper-create-class-features-plugin@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7"
+  integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.14.5"
+    "@babel/helper-function-name" "^7.14.5"
+    "@babel/helper-member-expression-to-functions" "^7.15.0"
+    "@babel/helper-optimise-call-expression" "^7.14.5"
+    "@babel/helper-replace-supers" "^7.15.0"
+    "@babel/helper-split-export-declaration" "^7.14.5"
+
 "@babel/helper-create-regexp-features-plugin@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4"
@@ -168,6 +225,13 @@
   dependencies:
     "@babel/types" "^7.14.5"
 
+"@babel/helper-member-expression-to-functions@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b"
+  integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==
+  dependencies:
+    "@babel/types" "^7.15.0"
+
 "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3"
@@ -189,6 +253,20 @@
     "@babel/traverse" "^7.14.5"
     "@babel/types" "^7.14.5"
 
+"@babel/helper-module-transforms@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08"
+  integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==
+  dependencies:
+    "@babel/helper-module-imports" "^7.14.5"
+    "@babel/helper-replace-supers" "^7.15.0"
+    "@babel/helper-simple-access" "^7.14.8"
+    "@babel/helper-split-export-declaration" "^7.14.5"
+    "@babel/helper-validator-identifier" "^7.14.9"
+    "@babel/template" "^7.14.5"
+    "@babel/traverse" "^7.15.0"
+    "@babel/types" "^7.15.0"
+
 "@babel/helper-optimise-call-expression@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c"
@@ -220,6 +298,16 @@
     "@babel/traverse" "^7.14.5"
     "@babel/types" "^7.14.5"
 
+"@babel/helper-replace-supers@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4"
+  integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.15.0"
+    "@babel/helper-optimise-call-expression" "^7.14.5"
+    "@babel/traverse" "^7.15.0"
+    "@babel/types" "^7.15.0"
+
 "@babel/helper-simple-access@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz#66ea85cf53ba0b4e588ba77fc813f53abcaa41c4"
@@ -227,6 +315,13 @@
   dependencies:
     "@babel/types" "^7.14.5"
 
+"@babel/helper-simple-access@^7.14.8":
+  version "7.14.8"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924"
+  integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==
+  dependencies:
+    "@babel/types" "^7.14.8"
+
 "@babel/helper-skip-transparent-expression-wrappers@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4"
@@ -246,6 +341,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
   integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
 
+"@babel/helper-validator-identifier@^7.14.9":
+  version "7.14.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
+  integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
+
 "@babel/helper-validator-option@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
@@ -270,6 +370,15 @@
     "@babel/traverse" "^7.14.5"
     "@babel/types" "^7.14.5"
 
+"@babel/helpers@^7.14.8":
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357"
+  integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==
+  dependencies:
+    "@babel/template" "^7.14.5"
+    "@babel/traverse" "^7.15.0"
+    "@babel/types" "^7.15.0"
+
 "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
@@ -284,6 +393,11 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2"
   integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==
 
+"@babel/parser@^7.15.0":
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862"
+  integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==
+
 "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e"
@@ -293,10 +407,10 @@
     "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
     "@babel/plugin-proposal-optional-chaining" "^7.14.5"
 
-"@babel/plugin-proposal-async-generator-functions@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz#784a48c3d8ed073f65adcf30b57bcbf6c8119ace"
-  integrity sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==
+"@babel/plugin-proposal-async-generator-functions@^7.14.9":
+  version "7.14.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz#7028dc4fa21dc199bbacf98b39bab1267d0eaf9a"
+  integrity sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
     "@babel/helper-remap-async-to-generator" "^7.14.5"
@@ -577,10 +691,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/plugin-transform-classes@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz#0e98e82097b38550b03b483f9b51a78de0acb2cf"
-  integrity sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA==
+"@babel/plugin-transform-classes@^7.14.9":
+  version "7.14.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz#2a391ffb1e5292710b00f2e2c210e1435e7d449f"
+  integrity sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==
   dependencies:
     "@babel/helper-annotate-as-pure" "^7.14.5"
     "@babel/helper-function-name" "^7.14.5"
@@ -665,14 +779,14 @@
     "@babel/helper-plugin-utils" "^7.14.5"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-commonjs@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97"
-  integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==
+"@babel/plugin-transform-modules-commonjs@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz#3305896e5835f953b5cdb363acd9e8c2219a5281"
+  integrity sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==
   dependencies:
-    "@babel/helper-module-transforms" "^7.14.5"
+    "@babel/helper-module-transforms" "^7.15.0"
     "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-simple-access" "^7.14.5"
+    "@babel/helper-simple-access" "^7.14.8"
     babel-plugin-dynamic-import-node "^2.3.3"
 
 "@babel/plugin-transform-modules-systemjs@^7.14.5":
@@ -694,10 +808,10 @@
     "@babel/helper-module-transforms" "^7.14.5"
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/plugin-transform-named-capturing-groups-regex@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz#60c06892acf9df231e256c24464bfecb0908fd4e"
-  integrity sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9":
+  version "7.14.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2"
+  integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==
   dependencies:
     "@babel/helper-create-regexp-features-plugin" "^7.14.5"
 
@@ -777,10 +891,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/plugin-transform-runtime@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523"
-  integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg==
+"@babel/plugin-transform-runtime@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3"
+  integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==
   dependencies:
     "@babel/helper-module-imports" "^7.14.5"
     "@babel/helper-plugin-utils" "^7.14.5"
@@ -825,12 +939,12 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/plugin-transform-typescript@^7.14.5":
-  version "7.14.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.6.tgz#6e9c2d98da2507ebe0a883b100cde3c7279df36c"
-  integrity sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA==
+"@babel/plugin-transform-typescript@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.0.tgz#553f230b9d5385018716586fc48db10dd228eb7e"
+  integrity sha512-WIIEazmngMEEHDaPTx0IZY48SaAmjVWe3TRSX7cmJXn0bEv9midFzAjxiruOWYIVf5iQ10vFx7ASDpgEO08L5w==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.14.6"
+    "@babel/helper-create-class-features-plugin" "^7.15.0"
     "@babel/helper-plugin-utils" "^7.14.5"
     "@babel/plugin-syntax-typescript" "^7.14.5"
 
@@ -849,17 +963,17 @@
     "@babel/helper-create-regexp-features-plugin" "^7.14.5"
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/preset-env@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.7.tgz#5c70b22d4c2d893b03d8c886a5c17422502b932a"
-  integrity sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==
+"@babel/preset-env@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.0.tgz#e2165bf16594c9c05e52517a194bf6187d6fe464"
+  integrity sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q==
   dependencies:
-    "@babel/compat-data" "^7.14.7"
-    "@babel/helper-compilation-targets" "^7.14.5"
+    "@babel/compat-data" "^7.15.0"
+    "@babel/helper-compilation-targets" "^7.15.0"
     "@babel/helper-plugin-utils" "^7.14.5"
     "@babel/helper-validator-option" "^7.14.5"
     "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5"
-    "@babel/plugin-proposal-async-generator-functions" "^7.14.7"
+    "@babel/plugin-proposal-async-generator-functions" "^7.14.9"
     "@babel/plugin-proposal-class-properties" "^7.14.5"
     "@babel/plugin-proposal-class-static-block" "^7.14.5"
     "@babel/plugin-proposal-dynamic-import" "^7.14.5"
@@ -892,7 +1006,7 @@
     "@babel/plugin-transform-async-to-generator" "^7.14.5"
     "@babel/plugin-transform-block-scoped-functions" "^7.14.5"
     "@babel/plugin-transform-block-scoping" "^7.14.5"
-    "@babel/plugin-transform-classes" "^7.14.5"
+    "@babel/plugin-transform-classes" "^7.14.9"
     "@babel/plugin-transform-computed-properties" "^7.14.5"
     "@babel/plugin-transform-destructuring" "^7.14.7"
     "@babel/plugin-transform-dotall-regex" "^7.14.5"
@@ -903,10 +1017,10 @@
     "@babel/plugin-transform-literals" "^7.14.5"
     "@babel/plugin-transform-member-expression-literals" "^7.14.5"
     "@babel/plugin-transform-modules-amd" "^7.14.5"
-    "@babel/plugin-transform-modules-commonjs" "^7.14.5"
+    "@babel/plugin-transform-modules-commonjs" "^7.15.0"
     "@babel/plugin-transform-modules-systemjs" "^7.14.5"
     "@babel/plugin-transform-modules-umd" "^7.14.5"
-    "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.7"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9"
     "@babel/plugin-transform-new-target" "^7.14.5"
     "@babel/plugin-transform-object-super" "^7.14.5"
     "@babel/plugin-transform-parameters" "^7.14.5"
@@ -921,11 +1035,11 @@
     "@babel/plugin-transform-unicode-escapes" "^7.14.5"
     "@babel/plugin-transform-unicode-regex" "^7.14.5"
     "@babel/preset-modules" "^0.1.4"
-    "@babel/types" "^7.14.5"
+    "@babel/types" "^7.15.0"
     babel-plugin-polyfill-corejs2 "^0.2.2"
     babel-plugin-polyfill-corejs3 "^0.2.2"
     babel-plugin-polyfill-regenerator "^0.2.2"
-    core-js-compat "^3.15.0"
+    core-js-compat "^3.16.0"
     semver "^6.3.0"
 
 "@babel/preset-modules@^0.1.4":
@@ -951,19 +1065,19 @@
     "@babel/plugin-transform-react-jsx-development" "^7.14.5"
     "@babel/plugin-transform-react-pure-annotations" "^7.14.5"
 
-"@babel/preset-typescript@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.14.5.tgz#aa98de119cf9852b79511f19e7f44a2d379bcce0"
-  integrity sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw==
+"@babel/preset-typescript@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945"
+  integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow==
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
     "@babel/helper-validator-option" "^7.14.5"
-    "@babel/plugin-transform-typescript" "^7.14.5"
+    "@babel/plugin-transform-typescript" "^7.15.0"
 
-"@babel/register@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.14.5.tgz#d0eac615065d9c2f1995842f85d6e56c345f3233"
-  integrity sha512-TjJpGz/aDjFGWsItRBQMOFTrmTI9tr79CHOK+KIvLeCkbxuOAk2M5QHjvruIMGoo9OuccMh5euplPzc5FjAKGg==
+"@babel/register@^7.15.3":
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.15.3.tgz#6b40a549e06ec06c885b2ec42c3dd711f55fe752"
+  integrity sha512-mj4IY1ZJkorClxKTImccn4T81+UKTo4Ux0+OFSV9hME1ooqS9UV+pJ6BjD0qXPK4T3XW/KNa79XByjeEMZz+fw==
   dependencies:
     clone-deep "^4.0.1"
     find-cache-dir "^2.0.0"
@@ -978,6 +1092,13 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.15.3":
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
+  integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/template@^7.14.5", "@babel/template@^7.3.3":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
@@ -1002,6 +1123,21 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
+"@babel/traverse@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98"
+  integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==
+  dependencies:
+    "@babel/code-frame" "^7.14.5"
+    "@babel/generator" "^7.15.0"
+    "@babel/helper-function-name" "^7.14.5"
+    "@babel/helper-hoist-variables" "^7.14.5"
+    "@babel/helper-split-export-declaration" "^7.14.5"
+    "@babel/parser" "^7.15.0"
+    "@babel/types" "^7.15.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
 "@babel/types@^7.0.0", "@babel/types@^7.14.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
@@ -1010,26 +1146,19 @@
     "@babel/helper-validator-identifier" "^7.14.5"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.14.8", "@babel/types@^7.15.0":
+  version "7.15.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd"
+  integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.14.9"
+    to-fast-properties "^2.0.0"
+
 "@bcoe/v8-coverage@^0.2.3":
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
   integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
 
-"@eslint/eslintrc@^0.4.2":
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.2.tgz#f63d0ef06f5c0c57d76c4ab5f63d3835c51b0179"
-  integrity sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==
-  dependencies:
-    ajv "^6.12.4"
-    debug "^4.1.1"
-    espree "^7.3.0"
-    globals "^13.9.0"
-    ignore "^4.0.6"
-    import-fresh "^3.2.1"
-    js-yaml "^3.13.1"
-    minimatch "^3.0.4"
-    strip-json-comments "^3.1.1"
-
 "@eslint/eslintrc@^0.4.3":
   version "0.4.3"
   resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@@ -1251,94 +1380,94 @@
   resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
   integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
 
-"@jest/console@^27.0.2":
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.0.2.tgz#b8eeff8f21ac51d224c851e1729d2630c18631e6"
-  integrity sha512-/zYigssuHLImGeMAACkjI4VLAiiJznHgAl3xnFT19iWyct2LhrH3KXOjHRmxBGTkiPLZKKAJAgaPpiU9EZ9K+w==
+"@jest/console@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.0.6.tgz#3eb72ea80897495c3d73dd97aab7f26770e2260f"
+  integrity sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     chalk "^4.0.0"
-    jest-message-util "^27.0.2"
-    jest-util "^27.0.2"
+    jest-message-util "^27.0.6"
+    jest-util "^27.0.6"
     slash "^3.0.0"
 
-"@jest/core@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.0.5.tgz#59e9e69e7374d65dbb22e3fc1bd52e80991eae72"
-  integrity sha512-g73//jF0VwsOIrWUC9Cqg03lU3QoAMFxVjsm6n6yNmwZcQPN/o8w+gLWODw5VfKNFZT38otXHWxc6b8eGDUpEA==
+"@jest/core@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.0.6.tgz#c5f642727a0b3bf0f37c4b46c675372d0978d4a1"
+  integrity sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==
   dependencies:
-    "@jest/console" "^27.0.2"
-    "@jest/reporters" "^27.0.5"
-    "@jest/test-result" "^27.0.2"
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/console" "^27.0.6"
+    "@jest/reporters" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     ansi-escapes "^4.2.1"
     chalk "^4.0.0"
     emittery "^0.8.1"
     exit "^0.1.2"
     graceful-fs "^4.2.4"
-    jest-changed-files "^27.0.2"
-    jest-config "^27.0.5"
-    jest-haste-map "^27.0.5"
-    jest-message-util "^27.0.2"
-    jest-regex-util "^27.0.1"
-    jest-resolve "^27.0.5"
-    jest-resolve-dependencies "^27.0.5"
-    jest-runner "^27.0.5"
-    jest-runtime "^27.0.5"
-    jest-snapshot "^27.0.5"
-    jest-util "^27.0.2"
-    jest-validate "^27.0.2"
-    jest-watcher "^27.0.2"
+    jest-changed-files "^27.0.6"
+    jest-config "^27.0.6"
+    jest-haste-map "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-regex-util "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-resolve-dependencies "^27.0.6"
+    jest-runner "^27.0.6"
+    jest-runtime "^27.0.6"
+    jest-snapshot "^27.0.6"
+    jest-util "^27.0.6"
+    jest-validate "^27.0.6"
+    jest-watcher "^27.0.6"
     micromatch "^4.0.4"
     p-each-series "^2.1.0"
     rimraf "^3.0.0"
     slash "^3.0.0"
     strip-ansi "^6.0.0"
 
-"@jest/environment@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.0.5.tgz#a294ad4acda2e250f789fb98dc667aad33d3adc9"
-  integrity sha512-IAkJPOT7bqn0GiX5LPio6/e1YpcmLbrd8O5EFYpAOZ6V+9xJDsXjdgN2vgv9WOKIs/uA1kf5WeD96HhlBYO+FA==
+"@jest/environment@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.0.6.tgz#ee293fe996db01d7d663b8108fa0e1ff436219d2"
+  integrity sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==
   dependencies:
-    "@jest/fake-timers" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/fake-timers" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
-    jest-mock "^27.0.3"
+    jest-mock "^27.0.6"
 
-"@jest/fake-timers@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.0.5.tgz#304d5aedadf4c75cff3696995460b39d6c6e72f6"
-  integrity sha512-d6Tyf7iDoKqeUdwUKrOBV/GvEZRF67m7lpuWI0+SCD9D3aaejiOQZxAOxwH2EH/W18gnfYaBPLi0VeTGBHtQBg==
+"@jest/fake-timers@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.0.6.tgz#cbad52f3fe6abe30e7acb8cd5fa3466b9588e3df"
+  integrity sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@sinonjs/fake-timers" "^7.0.2"
     "@types/node" "*"
-    jest-message-util "^27.0.2"
-    jest-mock "^27.0.3"
-    jest-util "^27.0.2"
+    jest-message-util "^27.0.6"
+    jest-mock "^27.0.6"
+    jest-util "^27.0.6"
 
-"@jest/globals@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.0.5.tgz#f63b8bfa6ea3716f8df50f6a604b5c15b36ffd20"
-  integrity sha512-qqKyjDXUaZwDuccpbMMKCCMBftvrbXzigtIsikAH/9ca+kaae8InP2MDf+Y/PdCSMuAsSpHS6q6M25irBBUh+Q==
+"@jest/globals@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.0.6.tgz#48e3903f99a4650673d8657334d13c9caf0e8f82"
+  integrity sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==
   dependencies:
-    "@jest/environment" "^27.0.5"
-    "@jest/types" "^27.0.2"
-    expect "^27.0.2"
+    "@jest/environment" "^27.0.6"
+    "@jest/types" "^27.0.6"
+    expect "^27.0.6"
 
-"@jest/reporters@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.0.5.tgz#cd730b77d9667b8ff700ad66d4edc293bb09716a"
-  integrity sha512-4uNg5+0eIfRafnpgu3jCZws3NNcFzhu5JdRd1mKQ4/53+vkIqwB6vfZ4gn5BdGqOaLtYhlOsPaL5ATkKzyBrJw==
+"@jest/reporters@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.0.6.tgz#91e7f2d98c002ad5df94d5b5167c1eb0b9fd5b00"
+  integrity sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==
   dependencies:
     "@bcoe/v8-coverage" "^0.2.3"
-    "@jest/console" "^27.0.2"
-    "@jest/test-result" "^27.0.2"
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/console" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     chalk "^4.0.0"
     collect-v8-coverage "^1.0.0"
     exit "^0.1.2"
@@ -1349,70 +1478,70 @@
     istanbul-lib-report "^3.0.0"
     istanbul-lib-source-maps "^4.0.0"
     istanbul-reports "^3.0.2"
-    jest-haste-map "^27.0.5"
-    jest-resolve "^27.0.5"
-    jest-util "^27.0.2"
-    jest-worker "^27.0.2"
+    jest-haste-map "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-util "^27.0.6"
+    jest-worker "^27.0.6"
     slash "^3.0.0"
     source-map "^0.6.0"
     string-length "^4.0.1"
     terminal-link "^2.0.0"
     v8-to-istanbul "^8.0.0"
 
-"@jest/source-map@^27.0.1":
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.0.1.tgz#2afbf73ddbaddcb920a8e62d0238a0a9e0a8d3e4"
-  integrity sha512-yMgkF0f+6WJtDMdDYNavmqvbHtiSpwRN2U/W+6uztgfqgkq/PXdKPqjBTUF1RD/feth4rH5N3NW0T5+wIuln1A==
+"@jest/source-map@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f"
+  integrity sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==
   dependencies:
     callsites "^3.0.0"
     graceful-fs "^4.2.4"
     source-map "^0.6.0"
 
-"@jest/test-result@^27.0.2":
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.0.2.tgz#0451049e32ceb609b636004ccc27c8fa22263f10"
-  integrity sha512-gcdWwL3yP5VaIadzwQtbZyZMgpmes8ryBAJp70tuxghiA8qL4imJyZex+i+USQH2H4jeLVVszhwntgdQ97fccA==
+"@jest/test-result@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.0.6.tgz#3fa42015a14e4fdede6acd042ce98c7f36627051"
+  integrity sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==
   dependencies:
-    "@jest/console" "^27.0.2"
-    "@jest/types" "^27.0.2"
+    "@jest/console" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/istanbul-lib-coverage" "^2.0.0"
     collect-v8-coverage "^1.0.0"
 
-"@jest/test-sequencer@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.0.5.tgz#c58b21db49afc36c0e3921d7ddf1fb7954abfded"
-  integrity sha512-opztnGs+cXzZ5txFG2+omBaV5ge/0yuJNKbhE3DREMiXE0YxBuzyEa6pNv3kk2JuucIlH2Xvgmn9kEEHSNt/SA==
+"@jest/test-sequencer@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz#80a913ed7a1130545b1cd777ff2735dd3af5d34b"
+  integrity sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==
   dependencies:
-    "@jest/test-result" "^27.0.2"
+    "@jest/test-result" "^27.0.6"
     graceful-fs "^4.2.4"
-    jest-haste-map "^27.0.5"
-    jest-runtime "^27.0.5"
+    jest-haste-map "^27.0.6"
+    jest-runtime "^27.0.6"
 
-"@jest/transform@^27.0.5":
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.0.5.tgz#2dcb78953708af713941ac845b06078bc74ed873"
-  integrity sha512-lBD6OwKXSc6JJECBNk4mVxtSVuJSBsQrJ9WCBisfJs7EZuYq4K6vM9HmoB7hmPiLIDGeyaerw3feBV/bC4z8tg==
+"@jest/transform@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.0.6.tgz#189ad7107413208f7600f4719f81dd2f7278cc95"
+  integrity sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==
   dependencies:
     "@babel/core" "^7.1.0"
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     babel-plugin-istanbul "^6.0.0"
     chalk "^4.0.0"
     convert-source-map "^1.4.0"
     fast-json-stable-stringify "^2.0.0"
     graceful-fs "^4.2.4"
-    jest-haste-map "^27.0.5"
-    jest-regex-util "^27.0.1"
-    jest-util "^27.0.2"
+    jest-haste-map "^27.0.6"
+    jest-regex-util "^27.0.6"
+    jest-util "^27.0.6"
     micromatch "^4.0.4"
     pirates "^4.0.1"
     slash "^3.0.0"
     source-map "^0.6.1"
     write-file-atomic "^3.0.0"
 
-"@jest/types@^27.0.2":
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.0.2.tgz#e153d6c46bda0f2589f0702b071f9898c7bbd37e"
-  integrity sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==
+"@jest/types@^27.0.6":
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.0.6.tgz#9a992bc517e0c49f035938b8549719c2de40706b"
+  integrity sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==
   dependencies:
     "@types/istanbul-lib-coverage" "^2.0.0"
     "@types/istanbul-reports" "^3.0.0"
@@ -1559,54 +1688,54 @@
   dependencies:
     "@octokit/openapi-types" "^7.3.2"
 
-"@polkadot/api-contract@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-5.0.1.tgz#520a7b3cd990a76374b79e12eca5bf629cc565a1"
-  integrity sha512-qZ2wnXHDyU2c1/V9GKpbcZKBfVua4YFsU/LHKevZLkJfnGFBgNRdwAuKgVe5h2FCt2W2/pt618WgxG0UDWwjcw==
+"@polkadot/api-contract@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-5.5.1.tgz#4cdd0d6f4352050c58464d5958bdb779770bd2dc"
+  integrity sha512-/1O1AnpCu+LM2EKhRY83r36blG8KOr0JCVFeSfT0u52tM4wMdLlUy1XV/XTZayuCucdJ6I0pjUudCljm92aiGw==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/api" "5.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
-    rxjs "^7.2.0"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/api" "5.5.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/util" "^7.2.1"
+    rxjs "^7.3.0"
 
-"@polkadot/api-derive@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-5.0.1.tgz#08064c10ed159826ffd07013dcdde1d8b63186a0"
-  integrity sha512-JZpH1JVLu3PvX4+A71iDLtNr6LL103dAFou61DxyJF4obyTmS2lzigG3xXqUFShiPDb19ywxQpsE4gAOP6emuQ==
+"@polkadot/api-derive@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-5.5.1.tgz#6fdba748d90024f2fcdeb7827d178ff8d0ad308e"
+  integrity sha512-dkpl3CnroBYAlLx571KoyjI72TqRweWI61z7tzNeR8qwniNyWDEILTErUfzy5jYAO7XrZpW1Gn4WMMH+kEcqZQ==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/api" "5.0.1"
-    "@polkadot/rpc-core" "5.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
-    "@polkadot/util-crypto" "^7.0.1"
-    rxjs "^7.2.0"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/api" "5.5.1"
+    "@polkadot/rpc-core" "5.5.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/util" "^7.2.1"
+    "@polkadot/util-crypto" "^7.2.1"
+    rxjs "^7.3.0"
 
-"@polkadot/api@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-5.0.1.tgz#9607b53009322f9264f7dcc8705c466bd33aa516"
-  integrity sha512-5JDpM2Fjc80gHBju1B/rMBGDfAvY8UiU4XVlivJRk+mTVD3OTwbtTro4nmwJOub05xQCJvD/bnCuxG8eFSoq+Q==
+"@polkadot/api@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-5.5.1.tgz#0298c6d883c2264a68ae93a3b59b98263aed53d3"
+  integrity sha512-GS/MoRc7NB61jz7TzwX0WAA3JS7DSj3xH4ac39LcuPHXu0VMQw6LgT/5KIzYxTx+79Iwth62bKelW/Mgk23wUg==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/api-derive" "5.0.1"
-    "@polkadot/keyring" "^7.0.1"
-    "@polkadot/rpc-core" "5.0.1"
-    "@polkadot/rpc-provider" "5.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/types-known" "5.0.1"
-    "@polkadot/util" "^7.0.1"
-    "@polkadot/util-crypto" "^7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/api-derive" "5.5.1"
+    "@polkadot/keyring" "^7.2.1"
+    "@polkadot/rpc-core" "5.5.1"
+    "@polkadot/rpc-provider" "5.5.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/types-known" "5.5.1"
+    "@polkadot/util" "^7.2.1"
+    "@polkadot/util-crypto" "^7.2.1"
     eventemitter3 "^4.0.7"
-    rxjs "^7.2.0"
+    rxjs "^7.3.0"
 
-"@polkadot/dev@0.62.43":
-  version "0.62.43"
-  resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.62.43.tgz#567591bf3c38dded4b4c1f3ec8bf3d3198a23b6d"
-  integrity sha512-ZSgYUbC6A+WtRSY5nq7yeGYW+wv3g8cds2zndL4GeClIdVHksgEW6+ch3Hx6LMkE3y4q9Kjvs50oHeemBDut4Q==
+"@polkadot/dev@0.62.60":
+  version "0.62.60"
+  resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.62.60.tgz#450007c189a8433d8627bcc1fc01d2ffb1becfc3"
+  integrity sha512-VHZ4d/hhRSNFe0RXp3L/ZcAk1t2JQ1/lsznONAz4I9SZ2pn5kAQrWRF6eukgfQscrlqCH5njDAxwgXe6ODNVRw==
   dependencies:
-    "@babel/cli" "^7.14.5"
-    "@babel/core" "^7.14.6"
+    "@babel/cli" "^7.14.8"
+    "@babel/core" "^7.15.0"
     "@babel/plugin-proposal-class-properties" "^7.14.5"
     "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5"
     "@babel/plugin-proposal-numeric-separator" "^7.14.5"
@@ -1618,28 +1747,34 @@
     "@babel/plugin-syntax-import-meta" "^7.10.4"
     "@babel/plugin-syntax-top-level-await" "^7.14.5"
     "@babel/plugin-transform-regenerator" "^7.14.5"
-    "@babel/plugin-transform-runtime" "^7.14.5"
-    "@babel/preset-env" "^7.14.7"
+    "@babel/plugin-transform-runtime" "^7.15.0"
+    "@babel/preset-env" "^7.15.0"
     "@babel/preset-react" "^7.14.5"
-    "@babel/preset-typescript" "^7.14.5"
-    "@babel/register" "^7.14.5"
-    "@babel/runtime" "^7.14.6"
+    "@babel/preset-typescript" "^7.15.0"
+    "@babel/register" "^7.15.3"
+    "@babel/runtime" "^7.15.3"
+    "@rollup/plugin-alias" "^3.1.5"
+    "@rollup/plugin-commonjs" "^19.0.2"
+    "@rollup/plugin-inject" "^4.0.2"
+    "@rollup/plugin-json" "^4.1.0"
+    "@rollup/plugin-node-resolve" "^13.0.4"
     "@rushstack/eslint-patch" "^1.0.6"
-    "@typescript-eslint/eslint-plugin" "4.28.0"
-    "@typescript-eslint/parser" "4.28.0"
+    "@typescript-eslint/eslint-plugin" "4.29.2"
+    "@typescript-eslint/parser" "4.29.2"
     "@vue/component-compiler-utils" "^3.2.2"
-    babel-jest "^27.0.5"
+    babel-jest "^27.0.6"
     babel-plugin-module-extension-resolver "^1.0.0-rc.2"
     babel-plugin-module-resolver "^4.1.0"
-    babel-plugin-styled-components "^1.12.0"
-    browserslist "^4.16.6"
-    chalk "^4.1.1"
-    coveralls "^3.1.0"
-    eslint "^7.29.0"
+    babel-plugin-styled-components "^1.13.2"
+    browserslist "^4.16.7"
+    chalk "^4.1.2"
+    coveralls "^3.1.1"
+    eslint "^7.32.0"
     eslint-config-standard "^16.0.3"
-    eslint-import-resolver-node "^0.3.4"
+    eslint-import-resolver-node "^0.3.6"
     eslint-plugin-header "^3.1.1"
-    eslint-plugin-import "^2.23.4"
+    eslint-plugin-import "^2.24.0"
+    eslint-plugin-import-newlines "^1.1.4"
     eslint-plugin-node "^11.1.0"
     eslint-plugin-promise "^5.1.0"
     eslint-plugin-react "^7.24.0"
@@ -1651,118 +1786,129 @@
     gh-release "^6.0.0"
     glob "^7.1.7"
     glob2base "^0.0.12"
-    jest "^27.0.5"
-    jest-cli "^27.0.5"
-    jest-config "^27.0.5"
-    jest-haste-map "^27.0.5"
-    jest-resolve "^27.0.5"
+    jest "^27.0.6"
+    jest-cli "^27.0.6"
+    jest-config "^27.0.6"
+    jest-haste-map "^27.0.6"
+    jest-resolve "^27.0.6"
     madge "^4.0.2"
     minimatch "^3.0.4"
     mkdirp "^1.0.4"
-    prettier "^2.3.1"
+    prettier "^2.3.2"
     rimraf "^3.0.2"
-    typescript "^4.3.4"
-    yargs "^17.0.1"
+    rollup "^2.56.2"
+    typescript "^4.3.5"
+    yargs "^17.1.1"
 
-"@polkadot/keyring@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-7.0.1.tgz#666e903661b98279dc16d512be69f5ace4b58d8d"
-  integrity sha512-eSvG8Q4gUTRDFWj2lqTY/9NekGP8dtp+W6WmouKh0DDwHRawaVeDaq6UJYQv6XoBG1i+ZGPvErRQeGMPOn/mUQ==
+"@polkadot/keyring@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-7.2.1.tgz#5ed8e6c0edc61e3dd99ee647a227b9e3d955e8e6"
+  integrity sha512-WmiTsHKELX16uZWLvebDBckZIAXeJFfbcOM6m/VbMOjSV5C6xIKqiV3232Mn8ZuPKgsOf25Q78/IwJW1Dq53Qg==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/util" "7.0.1"
-    "@polkadot/util-crypto" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/util" "7.2.1"
+    "@polkadot/util-crypto" "7.2.1"
 
-"@polkadot/networks@7.0.1", "@polkadot/networks@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-7.0.1.tgz#e07c4b88e25711433e76d24fce4c7273c25dd38b"
-  integrity sha512-bJSvI7UgEpxmBKS8TMh+I1mfmCMwhClGdSs29kwU+K61IjBTKTt3yQJ/SflYIQV7QftGbz3oMfSkGbQbRHZqvQ==
+"@polkadot/networks@7.2.1", "@polkadot/networks@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-7.2.1.tgz#20c8d81fba4b48162bf360759d8d54c55d30128b"
+  integrity sha512-YX8oQ7QQ2oq3YowwOiv/C82l849V0ZEzpR26YrPgKSXbYFbasho3Akf0zalndZJZV1Bb8EiOkzGoJ3ffogSPxA==
   dependencies:
-    "@babel/runtime" "^7.14.6"
+    "@babel/runtime" "^7.15.3"
 
-"@polkadot/rpc-core@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-5.0.1.tgz#8460287532fe61c31505564df53e92ef6feba875"
-  integrity sha512-JMNOVQijjyJZNu9B8CJwIrQzGYzAp03uCBSbqYfzWBFnYVLKh7JmvOlkLnODM8uUYq0gVN4BaDUSPc39GpELAQ==
+"@polkadot/rpc-core@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-5.5.1.tgz#4ce0646becabe7736dfb81eb902e5933158646c8"
+  integrity sha512-hP7a55iSpgZVqxAIpK+v63eV/nD14Tm7C1rUmfKIS6gGJFJf+sQbTmp6d7+fuKxvYfFqBrFLU8IraOhLOQ5W3Q==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/rpc-provider" "5.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
-    rxjs "^7.2.0"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/rpc-provider" "5.5.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/util" "^7.2.1"
+    rxjs "^7.3.0"
 
-"@polkadot/rpc-provider@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-5.0.1.tgz#ef022a123eb9073634b59c6e0f6e1705e96066a5"
-  integrity sha512-t+VKhMtQfQVgkZDqYnP/44KlBDmcCVo1/MvJ+DoNd7RUWUIBJt3v71G5gDSNeGMTyvxn0KK0qL4j+Nqr6c4FUQ==
+"@polkadot/rpc-provider@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-5.5.1.tgz#633f4a48605623092fb9017433f2b3cd70cd96bc"
+  integrity sha512-wOCKeeyUa7Dw3nxKkQntnfOO471icdzqT2V7bwloBOo+G2MX8nHImO0mW3QMfJygn4qoARF1PBo1PLbDUEDgog==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
-    "@polkadot/util-crypto" "^7.0.1"
-    "@polkadot/x-fetch" "^7.0.1"
-    "@polkadot/x-global" "^7.0.1"
-    "@polkadot/x-ws" "^7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/util" "^7.2.1"
+    "@polkadot/util-crypto" "^7.2.1"
+    "@polkadot/x-fetch" "^7.2.1"
+    "@polkadot/x-global" "^7.2.1"
+    "@polkadot/x-ws" "^7.2.1"
     eventemitter3 "^4.0.7"
 
-"@polkadot/ts@0.3.89":
-  version "0.3.89"
-  resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.3.89.tgz#c7a704ea284d04fcf4d581f5df156d5945480033"
-  integrity sha512-GC0H8wmVKebkieN2MHScjDDonzigIzkjl1Q4V1OhoRcfQbeZZ7vijeiVwP8Hw3wIw4GLKxxXeDrkKPWl/bcaHw==
+"@polkadot/ts@0.4.4":
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.4.4.tgz#e86aa47c2bcbc70ac8385b31014c81927c4b0a88"
+  integrity sha512-lzB8lg8GfdJlA7RdeoOJVFopecN4i++JndbUs6jW7AgRz+joeXQIIRomVgCNE52nW1uWpXMELnlvEP812v7sVw==
   dependencies:
-    "@types/chrome" "^0.0.144"
+    "@types/chrome" "^0.0.145"
 
-"@polkadot/typegen@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-5.0.1.tgz#718b517f4f1578441911096603577bd0a2a968e0"
-  integrity sha512-iFLJoWgIkn+J6MDw3AUWveP9qxVn1C+VeLJbpZ21St5WyeE148Tml0BmYnKLSXlaPMhZEwB+/IV3jpQ35dH4bw==
+"@polkadot/typegen@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-5.5.1.tgz#b31010716a142290d12f48ead6166851599055d0"
+  integrity sha512-ua55CVqT3+Y5fX9stpYUO+UhiJJ1RDTZ6vM2/Lndmsuda4lHQnUDrCnMmxKhM5OcyIlJlY5mF9dyO0kl5mTm+w==
   dependencies:
-    "@babel/core" "^7.14.6"
-    "@babel/register" "^7.14.5"
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/api" "5.0.1"
-    "@polkadot/rpc-provider" "5.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
+    "@babel/core" "^7.15.0"
+    "@babel/register" "^7.15.3"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/api" "5.5.1"
+    "@polkadot/rpc-provider" "5.5.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/types-support" "5.5.1"
+    "@polkadot/util" "^7.2.1"
     handlebars "^4.7.7"
     websocket "^1.0.34"
-    yargs "^17.0.1"
+    yargs "^17.1.0"
 
-"@polkadot/types-known@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-5.0.1.tgz#21feb327fc4323733bf027c8d874a2aa3014b21f"
-  integrity sha512-AIhPlN4r14ZW4wdwHZD2nIe1DE61ZO9PsyrCyAU3ysl6Cw6TI+txDCN3aS/8XYuC7wDLEgLB9vJv2sVWdCzqJg==
+"@polkadot/types-known@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-5.5.1.tgz#b00b0d45cbd07b4e0c3199f8ba00d10a1bd3f63d"
+  integrity sha512-bxBRmZ0a3lwEyWkWOKqmDJfpNKh3cp9xo6IidrQU2S5OPMjFFercB+HwJjkNE1cMtShwBYTvDheUImNkdm+FXA==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/networks" "^7.0.1"
-    "@polkadot/types" "5.0.1"
-    "@polkadot/util" "^7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/networks" "^7.2.1"
+    "@polkadot/types" "5.5.1"
+    "@polkadot/util" "^7.2.1"
 
-"@polkadot/types@5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-5.0.1.tgz#2a4e23e452f999eeae175b595470df0e426a930d"
-  integrity sha512-aN6JKeF7ZYi5irYAaUoDqth6qlOlB15C5vhlDOojEorYLfRs/R+GCrO+lPSs+bKmSxh7BSRh500ikI/xD4nx5A==
+"@polkadot/types-support@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-5.5.1.tgz#15556c2f31e79f0a6a821c7723f702757cb89462"
+  integrity sha512-57i1SdK8B+miGTAlDNdvbBuN6FguTnwzv2UPE2Zv3iQznTSZBkQZN16tIK/yMkQfhtO4ZzPcAnnSPZMncqh/Mg==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/util" "^7.0.1"
-    "@polkadot/util-crypto" "^7.0.1"
-    rxjs "^7.2.0"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/util" "^7.2.1"
+
+"@polkadot/types@5.5.1":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-5.5.1.tgz#057e8f0fc2369c0741c0f9b0224418e8f25a6938"
+  integrity sha512-+Cm7Y6D/98WqL8ofONyZrVvE2CxzK3/z18bATIQIWhG2w9ir9PdWaFMZ3fLCRw2Ggaq88AknguK6kXeEPcKPrA==
+  dependencies:
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/util" "^7.2.1"
+    "@polkadot/util-crypto" "^7.2.1"
+    rxjs "^7.3.0"
 
-"@polkadot/util-crypto@7.0.1", "@polkadot/util-crypto@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-7.0.1.tgz#03109dc11323dad174fb2214d395855495def16a"
-  integrity sha512-dbvdsICoyOVw/K45RmHOP7wXE/7vj+NzEKGcKbiDt39nglHm6g2BTJ947PwwyNusTTAx82Q2iJ9vIZ1Kl0xG+g==
+"@polkadot/util-crypto@7.2.1", "@polkadot/util-crypto@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-7.2.1.tgz#7f1bbf031dac75090699083fc9e825c22e5d5f61"
+  integrity sha512-X3iGba/1JTL/0MNzMNEIlO9DNyKlwFV839jfGLDKhPbCuDmWp0NdQjF3mBmbvNwkXvn07WmhE7g3q9n5iTzqvQ==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/networks" "7.0.1"
-    "@polkadot/util" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/networks" "7.2.1"
+    "@polkadot/util" "7.2.1"
     "@polkadot/wasm-crypto" "^4.1.2"
-    "@polkadot/x-randomvalues" "7.0.1"
+    "@polkadot/x-randomvalues" "7.2.1"
     base-x "^3.0.8"
     base64-js "^1.5.1"
     blakejs "^1.1.1"
     bn.js "^4.11.9"
     create-hash "^1.2.0"
+    ed2curve "^0.3.0"
     elliptic "^6.5.4"
     hash.js "^1.1.7"
     js-sha3 "^0.8.0"
@@ -1770,14 +1916,14 @@
     tweetnacl "^1.0.3"
     xxhashjs "^0.2.2"
 
-"@polkadot/util@7.0.1", "@polkadot/util@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-7.0.1.tgz#79afd40473016876f51d65ebb9900a20108fe0a4"
-  integrity sha512-EtQlZL6ok0Ep+zRz2QHMUoJo/b3kFHVN2qqyD2+9sdqg0FGLmkzNFM+K6dasCMLXieJ1l0HoFsQppSo/leUeaA==
+"@polkadot/util@7.2.1", "@polkadot/util@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-7.2.1.tgz#abcad49f884534ff042c37480f63b9750c69341d"
+  integrity sha512-GilFg3i5dmu0H6dHEyh5bUw3yywmnFpEHfxFmKghL1ABDEr4qD0d/XAJ9UrzLFCBKbdTZsR0MDjgjVI2N84J1A==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-textdecoder" "7.0.1"
-    "@polkadot/x-textencoder" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-textdecoder" "7.2.1"
+    "@polkadot/x-textencoder" "7.2.1"
     "@types/bn.js" "^4.11.6"
     bn.js "^4.11.9"
     camelcase "^5.3.1"
@@ -1806,57 +1952,114 @@
     "@polkadot/wasm-crypto-asmjs" "^4.1.2"
     "@polkadot/wasm-crypto-wasm" "^4.1.2"
 
-"@polkadot/x-fetch@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-7.0.1.tgz#2db6fa19f4f4d9b2f4cf50ba78bf3aa947d7b982"
-  integrity sha512-9R38FjtlJcvdpEA7tVGmTmH4aiBCTABuLJdVSn3cYkgWfxDHeFMqjdFzTJ6Asa5cY0Ds3ZKsh9uccTQBQzV/HQ==
+"@polkadot/x-fetch@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-7.2.1.tgz#c9bee0316d31cd150b2cb6646ccdb77c6dc3d42d"
+  integrity sha512-osdZNPfrB50d7tfjVs4QRjfsb6xqC09JEeYzbUl24hUXPwtkQE8/379jayu1usPe9/JI2wKYGscdf/nRl4pBkA==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-global" "7.0.1"
-    "@types/node-fetch" "^2.5.11"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-global" "7.2.1"
+    "@types/node-fetch" "^2.5.12"
     node-fetch "^2.6.1"
 
-"@polkadot/x-global@7.0.1", "@polkadot/x-global@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-7.0.1.tgz#44fb248d3aaea557753318327149772969e96bff"
-  integrity sha512-gVVACSdRhHYRJejLEAL0mM9BZfY8N50VT2+15A7ALD1tVqwS4tz3P9vRW3Go7ZjfyAc83aEmh0PiQ8Nm1R+2Cg==
+"@polkadot/x-global@7.2.1", "@polkadot/x-global@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-7.2.1.tgz#32207936b7f939a21da608f82ca20535f9148cda"
+  integrity sha512-VNW+76TxEPqvBy3XMNV05mJRPRGZcYh3k5HjW4+asYeFunMahH4zjmCulhtD9SRI/TqdfHTiqDOqKNKe2xJcVg==
   dependencies:
-    "@babel/runtime" "^7.14.6"
+    "@babel/runtime" "^7.15.3"
 
-"@polkadot/x-randomvalues@7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-7.0.1.tgz#32036ae5d48645a062f6a1c3ebbf227236c806b8"
-  integrity sha512-UNoIFaz1xJPozruT+lo8BTeT8A3NM3PgWuru7Vs8OsIz0Phkg7lUWlpHu9PZHyQCyKlUryvkOA692IlVlNYy2Q==
+"@polkadot/x-randomvalues@7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-7.2.1.tgz#708b7a54bd90ec091ab54e125d8b52e0853ea86b"
+  integrity sha512-B4sjwX+gFweZ1YM1Cg/S9hAEx9E/gV/vqLW89PJB6+hyvsPS9eiVvfVpaOsohc7AgmuINm/bSQbNZvtC+BbbKw==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-global" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-global" "7.2.1"
 
-"@polkadot/x-textdecoder@7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-7.0.1.tgz#bb9bba94b2eb1612dd35c299f43ab74515db74d9"
-  integrity sha512-CFRnpI0cp1h2N1+ec551BLVLwV6OHG6Gj62EYcIOXR+o/SX/6MXm3Qcehm2YvfTKqktyIUSWmTwbWjGjuqPrpA==
+"@polkadot/x-textdecoder@7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-7.2.1.tgz#c52074dba9943a12583f3f8672a49399f10e00f3"
+  integrity sha512-yXSZ0P/D/8HT8gbkdTjw/1AKZIVbX3+mIfiDiN3VqUBzruV7ak5hA+D01I0woBGDqxWISoLQFtGrxPAQ8pwAcg==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-global" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-global" "7.2.1"
 
-"@polkadot/x-textencoder@7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-7.0.1.tgz#181d403c5dc1d94fd1e2147fd1c5c528d30d8805"
-  integrity sha512-m+QL1HNiu5GMz6cfr/udSA6fUTv3RyIybJb7v43EQCxqlj/L0J3cUHapFd6tqH9PElD6jPkH1pXcgYN8e7dWTQ==
+"@polkadot/x-textencoder@7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-7.2.1.tgz#2326b3b7f9a5e445d7e560c438effbe800e2b1f6"
+  integrity sha512-1aqfxmfKSOWeOxmGBmk+RYrpqGtWywS6t0y/R3FI+k+s8NfIfGdcjMcupKq7khPh92PvVGkur+CnM/y6chn4XA==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-global" "7.0.1"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-global" "7.2.1"
 
-"@polkadot/x-ws@^7.0.1":
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-7.0.1.tgz#8c22a61c0dd9b82865c7631e22ac147c2b73b118"
-  integrity sha512-VUn/6sCJUpvW9WhUK+DKo1uDrw4yO84twRcy5JSzvSiBTaSplhU9Q4qGFl2Atr3WIzAYYx1jQSm/j6AhPRji1w==
+"@polkadot/x-ws@^7.2.1":
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-7.2.1.tgz#5971ab630911cdecd0a46db6fb899e9086954e58"
+  integrity sha512-sYnOF0qNdMuGFiRGWAtpkQQYIP44JFzGywap0CskhNEyCc+zDBi4l/ta3qHjeGta+h9rdVjDeYk2J86EsKlkSw==
   dependencies:
-    "@babel/runtime" "^7.14.6"
-    "@polkadot/x-global" "7.0.1"
-    "@types/websocket" "^1.0.3"
+    "@babel/runtime" "^7.15.3"
+    "@polkadot/x-global" "7.2.1"
+    "@types/websocket" "^1.0.4"
     websocket "^1.0.34"
 
+"@rollup/plugin-alias@^3.1.5":
+  version "3.1.5"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-3.1.5.tgz#73356a3a1eab2e1e2fd952f9f53cd89fc740d952"
+  integrity sha512-yzUaSvCC/LJPbl9rnzX3HN7vy0tq7EzHoEiQl1ofh4n5r2Rd5bj/+zcJgaGA76xbw95/JjWQyvHg9rOJp2y0oQ==
+  dependencies:
+    slash "^3.0.0"
+
+"@rollup/plugin-commonjs@^19.0.2":
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.2.tgz#1ccc3d63878d1bc9846f8969f09dd3b3e4ecc244"
+  integrity sha512-gBjarfqlC7qs0AutpRW/hrFNm+cd2/QKxhwyFa+srbg1oX7rDsEU3l+W7LAUhsAp9mPJMAkXDhLbQaVwEaE8bA==
+  dependencies:
+    "@rollup/pluginutils" "^3.1.0"
+    commondir "^1.0.1"
+    estree-walker "^2.0.1"
+    glob "^7.1.6"
+    is-reference "^1.2.1"
+    magic-string "^0.25.7"
+    resolve "^1.17.0"
+
+"@rollup/plugin-inject@^4.0.2":
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.2.tgz#55b21bb244a07675f7fdde577db929c82fc17395"
+  integrity sha512-TSLMA8waJ7Dmgmoc8JfPnwUwVZgLjjIAM6MqeIFqPO2ODK36JqE0Cf2F54UTgCUuW8da93Mvoj75a6KAVWgylw==
+  dependencies:
+    "@rollup/pluginutils" "^3.0.4"
+    estree-walker "^1.0.1"
+    magic-string "^0.25.5"
+
+"@rollup/plugin-json@^4.1.0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
+  integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==
+  dependencies:
+    "@rollup/pluginutils" "^3.0.8"
+
+"@rollup/plugin-node-resolve@^13.0.4":
+  version "13.0.4"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.4.tgz#b10222f4145a019740acb7738402130d848660c0"
+  integrity sha512-eYq4TFy40O8hjeDs+sIxEH/jc9lyuI2k9DM557WN6rO5OpnC2qXMBNj4IKH1oHrnAazL49C5p0tgP0/VpqJ+/w==
+  dependencies:
+    "@rollup/pluginutils" "^3.1.0"
+    "@types/resolve" "1.17.1"
+    builtin-modules "^3.1.0"
+    deepmerge "^4.2.2"
+    is-module "^1.0.0"
+    resolve "^1.19.0"
+
+"@rollup/pluginutils@^3.0.4", "@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
+  integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
+  dependencies:
+    "@types/estree" "0.0.39"
+    estree-walker "^1.0.1"
+    picomatch "^2.2.2"
+
 "@rushstack/eslint-patch@^1.0.6":
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz#023d72a5c4531b4ce204528971700a78a85a0c50"
@@ -1945,14 +2148,24 @@
   resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.18.tgz#0c8e298dbff8205e2266606c1ea5fbdba29b46e4"
   integrity sha512-rS27+EkB/RE1Iz3u0XtVL5q36MGDWbgYe7zWiodyKNUnthxY0rukK5V36eiUCtCisB7NN8zKYH6DO2M37qxFEQ==
 
-"@types/chrome@^0.0.144":
-  version "0.0.144"
-  resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.144.tgz#7dd9188e355aa17e3ad397f50b5cd3ad12caf788"
-  integrity sha512-BgoiO7/KP9hRNrCR2Wq+aKWT5Dh9bTofuWaRtcqPcj8YKhZojQgb6sSdIqvds2C+eO63BwaR9KHVMYYgZdGGBg==
+"@types/chrome@^0.0.145":
+  version "0.0.145"
+  resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.145.tgz#6c53ae0af5f25350b07bfd24cf459b5fe65cd9b8"
+  integrity sha512-vLvTMmfc8mvwOZzkmn2UwlWSNu0t0txBkyuIv8NgihRkvFCe6XJX65YZAgAP/RdBit3enhU2GTxCr+prn4uZmA==
   dependencies:
     "@types/filesystem" "*"
     "@types/har-format" "*"
 
+"@types/estree@*":
+  version "0.0.50"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
+  integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
+
+"@types/estree@0.0.39":
+  version "0.0.39"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
+  integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+
 "@types/filesystem@*":
   version "0.0.30"
   resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.30.tgz#a7373a2edf34d13e298baf7ee1101f738b2efb7e"
@@ -2011,10 +2224,10 @@
   resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0"
   integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==
 
-"@types/node-fetch@^2.5.11":
-  version "2.5.11"
-  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.11.tgz#ce22a2e65fc8999f4dbdb7ddbbcf187d755169e4"
-  integrity sha512-2upCKaqVZETDRb8A2VTaRymqFBEgH8u6yr96b/u3+1uQEPDRo3mJLEiPk7vdXBHRtjwkjqzFYMJXrt0Z9QsYjQ==
+"@types/node-fetch@^2.5.12":
+  version "2.5.12"
+  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66"
+  integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==
   dependencies:
     "@types/node" "*"
     form-data "^3.0.0"
@@ -2046,6 +2259,13 @@
   resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.0.tgz#2e8332cc7363f887d32ec5496b207d26ba8052bb"
   integrity sha512-hkc1DATxFLQo4VxPDpMH1gCkPpBbpOoJ/4nhuXw4n63/0R6bCpQECj4+K226UJ4JO/eJQz+1mC2I7JsWanAdQw==
 
+"@types/resolve@1.17.1":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
+  integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
+  dependencies:
+    "@types/node" "*"
+
 "@types/secp256k1@^4.0.1":
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.2.tgz#20c29a87149d980f64464e56539bf4810fdb5d1d"
@@ -2058,10 +2278,10 @@
   resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
   integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
 
-"@types/websocket@^1.0.3":
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.3.tgz#49e09f939afd0ccdee4f7108d4712ec9feb0f153"
-  integrity sha512-ZdoTSwmDsKR7l1I8fpfQtmTI/hUwlOvE3q0iyJsp4tXU0MkdrYowimDzwxjhQvxU4qjhHLd3a6ig0OXRbLgIdw==
+"@types/websocket@^1.0.4":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8"
+  integrity sha512-qn1LkcFEKK8RPp459jkjzsfpbsx36BBt3oC3pITYtkoBw/aVX+EZFa5j3ThCRTNpLFvIMr5dSTD4RaMdilIOpA==
   dependencies:
     "@types/node" "*"
 
@@ -2077,13 +2297,13 @@
   dependencies:
     "@types/yargs-parser" "*"
 
-"@typescript-eslint/eslint-plugin@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz#1a66f03b264844387beb7dc85e1f1d403bd1803f"
-  integrity sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==
+"@typescript-eslint/eslint-plugin@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d"
+  integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg==
   dependencies:
-    "@typescript-eslint/experimental-utils" "4.28.0"
-    "@typescript-eslint/scope-manager" "4.28.0"
+    "@typescript-eslint/experimental-utils" "4.29.2"
+    "@typescript-eslint/scope-manager" "4.29.2"
     debug "^4.3.1"
     functional-red-black-tree "^1.0.1"
     regexpp "^3.1.0"
@@ -2103,18 +2323,6 @@
     semver "^7.3.5"
     tsutils "^3.21.0"
 
-"@typescript-eslint/experimental-utils@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz#13167ed991320684bdc23588135ae62115b30ee0"
-  integrity sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==
-  dependencies:
-    "@types/json-schema" "^7.0.7"
-    "@typescript-eslint/scope-manager" "4.28.0"
-    "@typescript-eslint/types" "4.28.0"
-    "@typescript-eslint/typescript-estree" "4.28.0"
-    eslint-scope "^5.1.1"
-    eslint-utils "^3.0.0"
-
 "@typescript-eslint/experimental-utils@4.28.5":
   version "4.28.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.5.tgz#66c28bef115b417cf9d80812a713e0e46bb42a64"
@@ -2127,14 +2335,26 @@
     eslint-scope "^5.1.1"
     eslint-utils "^3.0.0"
 
-"@typescript-eslint/parser@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa"
-  integrity sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==
+"@typescript-eslint/experimental-utils@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7"
+  integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A==
+  dependencies:
+    "@types/json-schema" "^7.0.7"
+    "@typescript-eslint/scope-manager" "4.29.2"
+    "@typescript-eslint/types" "4.29.2"
+    "@typescript-eslint/typescript-estree" "4.29.2"
+    eslint-scope "^5.1.1"
+    eslint-utils "^3.0.0"
+
+"@typescript-eslint/parser@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.2.tgz#1c7744f4c27aeb74610c955d3dce9250e95c370a"
+  integrity sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g==
   dependencies:
-    "@typescript-eslint/scope-manager" "4.28.0"
-    "@typescript-eslint/types" "4.28.0"
-    "@typescript-eslint/typescript-estree" "4.28.0"
+    "@typescript-eslint/scope-manager" "4.29.2"
+    "@typescript-eslint/types" "4.29.2"
+    "@typescript-eslint/typescript-estree" "4.29.2"
     debug "^4.3.1"
 
 "@typescript-eslint/parser@^4.28.5":
@@ -2147,14 +2367,6 @@
     "@typescript-eslint/typescript-estree" "4.28.5"
     debug "^4.3.1"
 
-"@typescript-eslint/scope-manager@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz#6a3009d2ab64a30fc8a1e257a1a320067f36a0ce"
-  integrity sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==
-  dependencies:
-    "@typescript-eslint/types" "4.28.0"
-    "@typescript-eslint/visitor-keys" "4.28.0"
-
 "@typescript-eslint/scope-manager@4.28.5":
   version "4.28.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.5.tgz#3a1b70c50c1535ac33322786ea99ebe403d3b923"
@@ -2163,33 +2375,28 @@
     "@typescript-eslint/types" "4.28.5"
     "@typescript-eslint/visitor-keys" "4.28.5"
 
+"@typescript-eslint/scope-manager@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b"
+  integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA==
+  dependencies:
+    "@typescript-eslint/types" "4.29.2"
+    "@typescript-eslint/visitor-keys" "4.29.2"
+
 "@typescript-eslint/types@4.27.0":
   version "4.27.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.27.0.tgz#712b408519ed699baff69086bc59cd2fc13df8d8"
   integrity sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==
 
-"@typescript-eslint/types@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0"
-  integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==
-
 "@typescript-eslint/types@4.28.5":
   version "4.28.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.5.tgz#d33edf8e429f0c0930a7c3d44e9b010354c422e9"
   integrity sha512-MruOu4ZaDOLOhw4f/6iudyks/obuvvZUAHBDSW80Trnc5+ovmViLT2ZMDXhUV66ozcl6z0LJfKs1Usldgi/WCA==
 
-"@typescript-eslint/typescript-estree@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf"
-  integrity sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==
-  dependencies:
-    "@typescript-eslint/types" "4.28.0"
-    "@typescript-eslint/visitor-keys" "4.28.0"
-    debug "^4.3.1"
-    globby "^11.0.3"
-    is-glob "^4.0.1"
-    semver "^7.3.5"
-    tsutils "^3.21.0"
+"@typescript-eslint/types@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd"
+  integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ==
 
 "@typescript-eslint/typescript-estree@4.28.5":
   version "4.28.5"
@@ -2204,6 +2411,19 @@
     semver "^7.3.5"
     tsutils "^3.21.0"
 
+"@typescript-eslint/typescript-estree@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219"
+  integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg==
+  dependencies:
+    "@typescript-eslint/types" "4.29.2"
+    "@typescript-eslint/visitor-keys" "4.29.2"
+    debug "^4.3.1"
+    globby "^11.0.3"
+    is-glob "^4.0.1"
+    semver "^7.3.5"
+    tsutils "^3.21.0"
+
 "@typescript-eslint/typescript-estree@^4.8.2":
   version "4.27.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz#189a7b9f1d0717d5cccdcc17247692dedf7a09da"
@@ -2225,14 +2445,6 @@
     "@typescript-eslint/types" "4.27.0"
     eslint-visitor-keys "^2.0.0"
 
-"@typescript-eslint/visitor-keys@4.28.0":
-  version "4.28.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434"
-  integrity sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==
-  dependencies:
-    "@typescript-eslint/types" "4.28.0"
-    eslint-visitor-keys "^2.0.0"
-
 "@typescript-eslint/visitor-keys@4.28.5":
   version "4.28.5"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.5.tgz#ffee2c602762ed6893405ee7c1144d9cc0a29675"
@@ -2241,6 +2453,14 @@
     "@typescript-eslint/types" "4.28.5"
     eslint-visitor-keys "^2.0.0"
 
+"@typescript-eslint/visitor-keys@4.29.2":
+  version "4.29.2"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df"
+  integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag==
+  dependencies:
+    "@typescript-eslint/types" "4.29.2"
+    eslint-visitor-keys "^2.0.0"
+
 "@ungap/promise-all-settled@1.1.2":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
@@ -2606,16 +2826,16 @@
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
   integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
 
-babel-jest@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.0.5.tgz#cd34c033ada05d1362211e5152391fd7a88080c8"
-  integrity sha512-bTMAbpCX7ldtfbca2llYLeSFsDM257aspyAOpsdrdSrBqoLkWCy4HPYTXtXWaSLgFPjrJGACL65rzzr4RFGadw==
+babel-jest@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.0.6.tgz#e99c6e0577da2655118e3608b68761a5a69bd0d8"
+  integrity sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==
   dependencies:
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/babel__core" "^7.1.14"
     babel-plugin-istanbul "^6.0.0"
-    babel-preset-jest "^27.0.1"
+    babel-preset-jest "^27.0.6"
     chalk "^4.0.0"
     graceful-fs "^4.2.4"
     slash "^3.0.0"
@@ -2638,10 +2858,10 @@
     istanbul-lib-instrument "^4.0.0"
     test-exclude "^6.0.0"
 
-babel-plugin-jest-hoist@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.1.tgz#a6d10e484c93abff0f4e95f437dad26e5736ea11"
-  integrity sha512-sqBF0owAcCDBVEDtxqfYr2F36eSHdx7lAVGyYuOBRnKdD6gzcy0I0XrAYCZgOA3CRrLhmR+Uae9nogPzmAtOfQ==
+babel-plugin-jest-hoist@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz#f7c6b3d764af21cb4a2a1ab6870117dbde15b456"
+  integrity sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==
   dependencies:
     "@babel/template" "^7.3.3"
     "@babel/types" "^7.3.3"
@@ -2688,10 +2908,10 @@
   dependencies:
     "@babel/helper-define-polyfill-provider" "^0.2.2"
 
-babel-plugin-styled-components@^1.12.0:
-  version "1.12.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz#1dec1676512177de6b827211e9eda5a30db4f9b9"
-  integrity sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==
+babel-plugin-styled-components@^1.13.2:
+  version "1.13.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.2.tgz#ebe0e6deff51d7f93fceda1819e9b96aeb88278d"
+  integrity sha512-Vb1R3d4g+MUfPQPVDMCGjm3cDocJEUTR7Xq7QS95JWWeksN1wdFRYpD2kulDgI3Huuaf1CZd+NK4KQmqUFh5dA==
   dependencies:
     "@babel/helper-annotate-as-pure" "^7.0.0"
     "@babel/helper-module-imports" "^7.0.0"
@@ -2721,12 +2941,12 @@
     "@babel/plugin-syntax-optional-chaining" "^7.8.3"
     "@babel/plugin-syntax-top-level-await" "^7.8.3"
 
-babel-preset-jest@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.0.1.tgz#7a50c75d16647c23a2cf5158d5bb9eb206b10e20"
-  integrity sha512-nIBIqCEpuiyhvjQs2mVNwTxQQa2xk70p9Dd/0obQGBf8FBzbnI8QhQKzLsWMN2i6q+5B0OcWDtrboBX5gmOLyA==
+babel-preset-jest@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz#909ef08e9f24a4679768be2f60a3df0856843f9d"
+  integrity sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==
   dependencies:
-    babel-plugin-jest-hoist "^27.0.1"
+    babel-plugin-jest-hoist "^27.0.6"
     babel-preset-current-node-syntax "^1.0.0"
 
 balanced-match@^1.0.0:
@@ -2966,6 +3186,17 @@
     escalade "^3.1.1"
     node-releases "^1.1.71"
 
+browserslist@^4.16.7:
+  version "4.16.7"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.7.tgz#108b0d1ef33c4af1b587c54f390e7041178e4335"
+  integrity sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==
+  dependencies:
+    caniuse-lite "^1.0.30001248"
+    colorette "^1.2.2"
+    electron-to-chromium "^1.3.793"
+    escalade "^3.1.1"
+    node-releases "^1.1.73"
+
 bs58@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
@@ -3024,6 +3255,11 @@
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
   integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
 
+builtin-modules@^3.1.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
+  integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
+
 bytes@3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
@@ -3085,6 +3321,11 @@
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001238.tgz#e6a8b45455c5de601718736d0242feef0ecdda15"
   integrity sha512-bZGam2MxEt7YNsa2VwshqWQMwrYs5tR5WZQRYSuFxsBQunWjBuXhN4cS9nV5FFb1Z9y+DoQcQ0COyQbv6A+CKw==
 
+caniuse-lite@^1.0.30001248:
+  version "1.0.30001251"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85"
+  integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==
+
 caseless@~0.12.0:
   version "0.12.0"
   resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
@@ -3134,6 +3375,14 @@
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
+chalk@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
 changelog-parser@^2.0.0:
   version "2.8.0"
   resolved "https://registry.yarnpkg.com/changelog-parser/-/changelog-parser-2.8.0.tgz#c14293e3e8fab797913c722de965480198650108"
@@ -3472,12 +3721,12 @@
     browserslist "^4.16.6"
     semver "7.0.0"
 
-core-js-compat@^3.15.0:
-  version "3.15.1"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.15.1.tgz#1afe233716d37ee021956ef097594071b2b585a7"
-  integrity sha512-xGhzYMX6y7oEGQGAJmP2TmtBLvR4nZmRGEcFa3ubHOq5YEp51gGN9AovVa0AoujGZIq+Wm6dISiYyGNfdflYww==
+core-js-compat@^3.16.0:
+  version "3.16.1"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.1.tgz#c44b7caa2dcb94b673a98f27eee1c8312f55bc2d"
+  integrity sha512-NHXQXvRbd4nxp9TEmooTJLUf94ySUG6+DSsscBpTftN1lQLQ4LjnWvc7AoIo4UjDsFF3hB8Uh5LLCRRdaiT5MQ==
   dependencies:
-    browserslist "^4.16.6"
+    browserslist "^4.16.7"
     semver "7.0.0"
 
 core-util-is@1.0.2, core-util-is@~1.0.0:
@@ -3493,10 +3742,10 @@
     object-assign "^4"
     vary "^1"
 
-coveralls@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.1.0.tgz#13c754d5e7a2dd8b44fe5269e21ca394fb4d615b"
-  integrity sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==
+coveralls@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.1.1.tgz#f5d4431d8b5ae69c5079c8f8ca00d64ac77cf081"
+  integrity sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==
   dependencies:
     js-yaml "^3.13.1"
     lcov-parse "^1.0.0"
@@ -3883,10 +4132,10 @@
     node-source-walk "^4.2.0"
     typescript "^3.9.7"
 
-diff-sequences@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.1.tgz#9c9801d52ed5f576ff0a20e3022a13ee6e297e7c"
-  integrity sha512-XPLijkfJUh/PIBnfkcSHgvD6tlYixmcMAn3osTk6jt+H0v/mgURto1XUiD9DKuGX5NDoVS6dSlA23gd9FUaCFg==
+diff-sequences@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"
+  integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==
 
 diff@5.0.0:
   version "5.0.0"
@@ -3970,6 +4219,13 @@
     jsbn "~0.1.0"
     safer-buffer "^2.1.0"
 
+ed2curve@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d"
+  integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==
+  dependencies:
+    tweetnacl "1.x.x"
+
 ee-first@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -3980,6 +4236,11 @@
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz#0728587f1b9b970ec9ffad932496429aef750d09"
   integrity sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==
 
+electron-to-chromium@^1.3.793:
+  version "1.3.807"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.807.tgz#c2eb803f4f094869b1a24151184ffbbdbf688b1f"
+  integrity sha512-p8uxxg2a23zRsvQ2uwA/OOI+O4BQxzaR7YKMIGGGQCpYmkFX2CVF5f0/hxLMV7yCr7nnJViCwHLhPfs52rIYCA==
+
 elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4:
   version "6.5.4"
   resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@@ -4151,18 +4412,18 @@
   resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516"
   integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==
 
-eslint-import-resolver-node@^0.3.4:
-  version "0.3.4"
-  resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
-  integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
+eslint-import-resolver-node@^0.3.5, eslint-import-resolver-node@^0.3.6:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
+  integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
   dependencies:
-    debug "^2.6.9"
-    resolve "^1.13.1"
+    debug "^3.2.7"
+    resolve "^1.20.0"
 
-eslint-module-utils@^2.6.1:
-  version "2.6.1"
-  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233"
-  integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==
+eslint-module-utils@^2.6.2:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534"
+  integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==
   dependencies:
     debug "^3.2.7"
     pkg-dir "^2.0.0"
@@ -4180,17 +4441,22 @@
   resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6"
   integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==
 
-eslint-plugin-import@^2.23.4:
-  version "2.23.4"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97"
-  integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==
+eslint-plugin-import-newlines@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.1.4.tgz#d69d03fe512b2f54bc781d1dfc51a4ad99df7a52"
+  integrity sha512-GCIM+524XQOFcEPinEyrvktQHkQq+k+kYCwbRrIioGBVGnk3RGDFWv5BPqBQCDci6SNZCVgIOi3/FmtDetbxvA==
+
+eslint-plugin-import@^2.24.0:
+  version "2.24.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.0.tgz#697ffd263e24da5e84e03b282f5fb62251777177"
+  integrity sha512-Kc6xqT9hiYi2cgybOc0I2vC9OgAYga5o/rAFinam/yF/t5uBqxQbauNPMC6fgb640T/89P0gFoO27FOilJ/Cqg==
   dependencies:
     array-includes "^3.1.3"
     array.prototype.flat "^1.2.4"
     debug "^2.6.9"
     doctrine "^2.1.0"
-    eslint-import-resolver-node "^0.3.4"
-    eslint-module-utils "^2.6.1"
+    eslint-import-resolver-node "^0.3.5"
+    eslint-module-utils "^2.6.2"
     find-up "^2.0.0"
     has "^1.0.3"
     is-core-module "^2.4.0"
@@ -4285,13 +4551,14 @@
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
   integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
 
-eslint@^7.29.0:
-  version "7.29.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.29.0.tgz#ee2a7648f2e729485e4d0bd6383ec1deabc8b3c0"
-  integrity sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==
+eslint@^7.31.0:
+  version "7.31.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca"
+  integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==
   dependencies:
     "@babel/code-frame" "7.12.11"
-    "@eslint/eslintrc" "^0.4.2"
+    "@eslint/eslintrc" "^0.4.3"
+    "@humanwhocodes/config-array" "^0.5.0"
     ajv "^6.10.0"
     chalk "^4.0.0"
     cross-spawn "^7.0.2"
@@ -4330,10 +4597,10 @@
     text-table "^0.2.0"
     v8-compile-cache "^2.0.3"
 
-eslint@^7.31.0:
-  version "7.31.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca"
-  integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==
+eslint@^7.32.0:
+  version "7.32.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
+  integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
   dependencies:
     "@babel/code-frame" "7.12.11"
     "@eslint/eslintrc" "^0.4.3"
@@ -4414,6 +4681,16 @@
   resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
   integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
 
+estree-walker@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
+  integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+
+estree-walker@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
 esutils@^2.0.2:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@@ -4574,17 +4851,17 @@
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
-expect@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/expect/-/expect-27.0.2.tgz#e66ca3a4c9592f1c019fa1d46459a9d2084f3422"
-  integrity sha512-YJFNJe2+P2DqH+ZrXy+ydRQYO87oxRUonZImpDodR1G7qo3NYd3pL+NQ9Keqpez3cehczYwZDBC3A7xk3n7M/w==
+expect@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/expect/-/expect-27.0.6.tgz#a4d74fbe27222c718fff68ef49d78e26a8fd4c05"
+  integrity sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     ansi-styles "^5.0.0"
-    jest-get-type "^27.0.1"
-    jest-matcher-utils "^27.0.2"
-    jest-message-util "^27.0.2"
-    jest-regex-util "^27.0.1"
+    jest-get-type "^27.0.6"
+    jest-matcher-utils "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-regex-util "^27.0.6"
 
 express@^4.14.0:
   version "4.17.1"
@@ -5857,6 +6134,11 @@
   resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
   integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
 
+is-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+  integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
+
 is-negative-zero@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
@@ -5931,6 +6213,13 @@
   resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
   integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
 
+is-reference@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
+  integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
+  dependencies:
+    "@types/estree" "*"
+
 is-regex@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f"
@@ -6088,226 +6377,226 @@
     has-to-string-tag-x "^1.2.0"
     is-object "^1.0.1"
 
-jest-changed-files@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.0.2.tgz#997253042b4a032950fc5f56abf3c5d1f8560801"
-  integrity sha512-eMeb1Pn7w7x3wue5/vF73LPCJ7DKQuC9wQUR5ebP9hDPpk5hzcT/3Hmz3Q5BOFpR3tgbmaWhJcMTVgC8Z1NuMw==
+jest-changed-files@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.0.6.tgz#bed6183fcdea8a285482e3b50a9a7712d49a7a8b"
+  integrity sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     execa "^5.0.0"
     throat "^6.0.1"
 
-jest-circus@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.0.5.tgz#b5e327f1d6857c8485126f8e364aefa4378debaa"
-  integrity sha512-p5rO90o1RTh8LPOG6l0Fc9qgp5YGv+8M5CFixhMh7gGHtGSobD1AxX9cjFZujILgY8t30QZ7WVvxlnuG31r8TA==
+jest-circus@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.0.6.tgz#dd4df17c4697db6a2c232aaad4e9cec666926668"
+  integrity sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==
   dependencies:
-    "@jest/environment" "^27.0.5"
-    "@jest/test-result" "^27.0.2"
-    "@jest/types" "^27.0.2"
+    "@jest/environment" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     chalk "^4.0.0"
     co "^4.6.0"
     dedent "^0.7.0"
-    expect "^27.0.2"
+    expect "^27.0.6"
     is-generator-fn "^2.0.0"
-    jest-each "^27.0.2"
-    jest-matcher-utils "^27.0.2"
-    jest-message-util "^27.0.2"
-    jest-runtime "^27.0.5"
-    jest-snapshot "^27.0.5"
-    jest-util "^27.0.2"
-    pretty-format "^27.0.2"
+    jest-each "^27.0.6"
+    jest-matcher-utils "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-runtime "^27.0.6"
+    jest-snapshot "^27.0.6"
+    jest-util "^27.0.6"
+    pretty-format "^27.0.6"
     slash "^3.0.0"
     stack-utils "^2.0.3"
     throat "^6.0.1"
 
-jest-cli@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.0.5.tgz#f359ba042624cffb96b713010a94bffb7498a37c"
-  integrity sha512-kZqY020QFOFQKVE2knFHirTBElw3/Q0kUbDc3nMfy/x+RQ7zUY89SUuzpHHJoSX1kX7Lq569ncvjNqU3Td/FCA==
+jest-cli@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.0.6.tgz#d021e5f4d86d6a212450d4c7b86cb219f1e6864f"
+  integrity sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==
   dependencies:
-    "@jest/core" "^27.0.5"
-    "@jest/test-result" "^27.0.2"
-    "@jest/types" "^27.0.2"
+    "@jest/core" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/types" "^27.0.6"
     chalk "^4.0.0"
     exit "^0.1.2"
     graceful-fs "^4.2.4"
     import-local "^3.0.2"
-    jest-config "^27.0.5"
-    jest-util "^27.0.2"
-    jest-validate "^27.0.2"
+    jest-config "^27.0.6"
+    jest-util "^27.0.6"
+    jest-validate "^27.0.6"
     prompts "^2.0.1"
     yargs "^16.0.3"
 
-jest-config@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.0.5.tgz#683da3b0d8237675c29c817f6e3aba1481028e19"
-  integrity sha512-zCUIXag7QIXKEVN4kUKbDBDi9Q53dV5o3eNhGqe+5zAbt1vLs4VE3ceWaYrOub0L4Y7E9pGfM84TX/0ARcE+Qw==
+jest-config@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.0.6.tgz#119fb10f149ba63d9c50621baa4f1f179500277f"
+  integrity sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==
   dependencies:
     "@babel/core" "^7.1.0"
-    "@jest/test-sequencer" "^27.0.5"
-    "@jest/types" "^27.0.2"
-    babel-jest "^27.0.5"
+    "@jest/test-sequencer" "^27.0.6"
+    "@jest/types" "^27.0.6"
+    babel-jest "^27.0.6"
     chalk "^4.0.0"
     deepmerge "^4.2.2"
     glob "^7.1.1"
     graceful-fs "^4.2.4"
     is-ci "^3.0.0"
-    jest-circus "^27.0.5"
-    jest-environment-jsdom "^27.0.5"
-    jest-environment-node "^27.0.5"
-    jest-get-type "^27.0.1"
-    jest-jasmine2 "^27.0.5"
-    jest-regex-util "^27.0.1"
-    jest-resolve "^27.0.5"
-    jest-runner "^27.0.5"
-    jest-util "^27.0.2"
-    jest-validate "^27.0.2"
+    jest-circus "^27.0.6"
+    jest-environment-jsdom "^27.0.6"
+    jest-environment-node "^27.0.6"
+    jest-get-type "^27.0.6"
+    jest-jasmine2 "^27.0.6"
+    jest-regex-util "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-runner "^27.0.6"
+    jest-util "^27.0.6"
+    jest-validate "^27.0.6"
     micromatch "^4.0.4"
-    pretty-format "^27.0.2"
+    pretty-format "^27.0.6"
 
-jest-diff@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.0.2.tgz#f315b87cee5dc134cf42c2708ab27375cc3f5a7e"
-  integrity sha512-BFIdRb0LqfV1hBt8crQmw6gGQHVDhM87SpMIZ45FPYKReZYG5er1+5pIn2zKqvrJp6WNox0ylR8571Iwk2Dmgw==
+jest-diff@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.0.6.tgz#4a7a19ee6f04ad70e0e3388f35829394a44c7b5e"
+  integrity sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==
   dependencies:
     chalk "^4.0.0"
-    diff-sequences "^27.0.1"
-    jest-get-type "^27.0.1"
-    pretty-format "^27.0.2"
+    diff-sequences "^27.0.6"
+    jest-get-type "^27.0.6"
+    pretty-format "^27.0.6"
 
-jest-docblock@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.1.tgz#bd9752819b49fa4fab1a50b73eb58c653b962e8b"
-  integrity sha512-TA4+21s3oebURc7VgFV4r7ltdIJ5rtBH1E3Tbovcg7AV+oLfD5DcJ2V2vJ5zFA9sL5CFd/d2D6IpsAeSheEdrA==
+jest-docblock@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3"
+  integrity sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==
   dependencies:
     detect-newline "^3.0.0"
 
-jest-each@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.0.2.tgz#865ddb4367476ced752167926b656fa0dcecd8c7"
-  integrity sha512-OLMBZBZ6JkoXgUenDtseFRWA43wVl2BwmZYIWQws7eS7pqsIvePqj/jJmEnfq91ALk3LNphgwNK/PRFBYi7ITQ==
+jest-each@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.0.6.tgz#cee117071b04060158dc8d9a66dc50ad40ef453b"
+  integrity sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     chalk "^4.0.0"
-    jest-get-type "^27.0.1"
-    jest-util "^27.0.2"
-    pretty-format "^27.0.2"
+    jest-get-type "^27.0.6"
+    jest-util "^27.0.6"
+    pretty-format "^27.0.6"
 
-jest-environment-jsdom@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.0.5.tgz#c36771977cf4490a9216a70473b39161d193c212"
-  integrity sha512-ToWhViIoTl5738oRaajTMgYhdQL73UWPoV4GqHGk2DPhs+olv8OLq5KoQW8Yf+HtRao52XLqPWvl46dPI88PdA==
+jest-environment-jsdom@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz#f66426c4c9950807d0a9f209c590ce544f73291f"
+  integrity sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==
   dependencies:
-    "@jest/environment" "^27.0.5"
-    "@jest/fake-timers" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/environment" "^27.0.6"
+    "@jest/fake-timers" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
-    jest-mock "^27.0.3"
-    jest-util "^27.0.2"
+    jest-mock "^27.0.6"
+    jest-util "^27.0.6"
     jsdom "^16.6.0"
 
-jest-environment-node@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.0.5.tgz#b7238fc2b61ef2fb9563a3b7653a95fa009a6a54"
-  integrity sha512-47qqScV/WMVz5OKF5TWpAeQ1neZKqM3ySwNveEnLyd+yaE/KT6lSMx/0SOx60+ZUcVxPiESYS+Kt2JS9y4PpkQ==
+jest-environment-node@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.0.6.tgz#a6699b7ceb52e8d68138b9808b0c404e505f3e07"
+  integrity sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==
   dependencies:
-    "@jest/environment" "^27.0.5"
-    "@jest/fake-timers" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/environment" "^27.0.6"
+    "@jest/fake-timers" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
-    jest-mock "^27.0.3"
-    jest-util "^27.0.2"
+    jest-mock "^27.0.6"
+    jest-util "^27.0.6"
 
-jest-get-type@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.1.tgz#34951e2b08c8801eb28559d7eb732b04bbcf7815"
-  integrity sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==
+jest-get-type@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe"
+  integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==
 
-jest-haste-map@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.0.5.tgz#2e1e55073b5328410a2c0d74b334e513d71f3470"
-  integrity sha512-3LFryGSHxwPFHzKIs6W0BGA2xr6g1MvzSjR3h3D8K8Uqy4vbRm/grpGHzbPtIbOPLC6wFoViRrNEmd116QWSkw==
+jest-haste-map@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.0.6.tgz#4683a4e68f6ecaa74231679dca237279562c8dc7"
+  integrity sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@types/graceful-fs" "^4.1.2"
     "@types/node" "*"
     anymatch "^3.0.3"
     fb-watchman "^2.0.0"
     graceful-fs "^4.2.4"
-    jest-regex-util "^27.0.1"
-    jest-serializer "^27.0.1"
-    jest-util "^27.0.2"
-    jest-worker "^27.0.2"
+    jest-regex-util "^27.0.6"
+    jest-serializer "^27.0.6"
+    jest-util "^27.0.6"
+    jest-worker "^27.0.6"
     micromatch "^4.0.4"
     walker "^1.0.7"
   optionalDependencies:
     fsevents "^2.3.2"
 
-jest-jasmine2@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.0.5.tgz#8a6eb2a685cdec3af13881145c77553e4e197776"
-  integrity sha512-m3TojR19sFmTn79QoaGy1nOHBcLvtLso6Zh7u+gYxZWGcza4rRPVqwk1hciA5ZOWWZIJOukAcore8JRX992FaA==
+jest-jasmine2@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz#fd509a9ed3d92bd6edb68a779f4738b100655b37"
+  integrity sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==
   dependencies:
     "@babel/traverse" "^7.1.0"
-    "@jest/environment" "^27.0.5"
-    "@jest/source-map" "^27.0.1"
-    "@jest/test-result" "^27.0.2"
-    "@jest/types" "^27.0.2"
+    "@jest/environment" "^27.0.6"
+    "@jest/source-map" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     chalk "^4.0.0"
     co "^4.6.0"
-    expect "^27.0.2"
+    expect "^27.0.6"
     is-generator-fn "^2.0.0"
-    jest-each "^27.0.2"
-    jest-matcher-utils "^27.0.2"
-    jest-message-util "^27.0.2"
-    jest-runtime "^27.0.5"
-    jest-snapshot "^27.0.5"
-    jest-util "^27.0.2"
-    pretty-format "^27.0.2"
+    jest-each "^27.0.6"
+    jest-matcher-utils "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-runtime "^27.0.6"
+    jest-snapshot "^27.0.6"
+    jest-util "^27.0.6"
+    pretty-format "^27.0.6"
     throat "^6.0.1"
 
-jest-leak-detector@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.0.2.tgz#ce19aa9dbcf7a72a9d58907a970427506f624e69"
-  integrity sha512-TZA3DmCOfe8YZFIMD1GxFqXUkQnIoOGQyy4hFCA2mlHtnAaf+FeOMxi0fZmfB41ZL+QbFG6BVaZF5IeFIVy53Q==
+jest-leak-detector@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz#545854275f85450d4ef4b8fe305ca2a26450450f"
+  integrity sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==
   dependencies:
-    jest-get-type "^27.0.1"
-    pretty-format "^27.0.2"
+    jest-get-type "^27.0.6"
+    pretty-format "^27.0.6"
 
-jest-matcher-utils@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.0.2.tgz#f14c060605a95a466cdc759acc546c6f4cbfc4f0"
-  integrity sha512-Qczi5xnTNjkhcIB0Yy75Txt+Ez51xdhOxsukN7awzq2auZQGPHcQrJ623PZj0ECDEMOk2soxWx05EXdXGd1CbA==
+jest-matcher-utils@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz#2a8da1e86c620b39459f4352eaa255f0d43e39a9"
+  integrity sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==
   dependencies:
     chalk "^4.0.0"
-    jest-diff "^27.0.2"
-    jest-get-type "^27.0.1"
-    pretty-format "^27.0.2"
+    jest-diff "^27.0.6"
+    jest-get-type "^27.0.6"
+    pretty-format "^27.0.6"
 
-jest-message-util@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.0.2.tgz#181c9b67dff504d8f4ad15cba10d8b80f272048c"
-  integrity sha512-rTqWUX42ec2LdMkoUPOzrEd1Tcm+R1KfLOmFK+OVNo4MnLsEaxO5zPDb2BbdSmthdM/IfXxOZU60P/WbWF8BTw==
+jest-message-util@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.0.6.tgz#158bcdf4785706492d164a39abca6a14da5ab8b5"
+  integrity sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==
   dependencies:
     "@babel/code-frame" "^7.12.13"
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@types/stack-utils" "^2.0.0"
     chalk "^4.0.0"
     graceful-fs "^4.2.4"
     micromatch "^4.0.4"
-    pretty-format "^27.0.2"
+    pretty-format "^27.0.6"
     slash "^3.0.0"
     stack-utils "^2.0.3"
 
-jest-mock@^27.0.3:
-  version "27.0.3"
-  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.0.3.tgz#5591844f9192b3335c0dca38e8e45ed297d4d23d"
-  integrity sha512-O5FZn5XDzEp+Xg28mUz4ovVcdwBBPfAhW9+zJLO0Efn2qNbYcDaJvSlRiQ6BCZUCVOJjALicuJQI9mRFjv1o9Q==
+jest-mock@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.0.6.tgz#0efdd40851398307ba16778728f6d34d583e3467"
+  integrity sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
 
 jest-pnp-resolver@^1.2.2:
@@ -6315,76 +6604,76 @@
   resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
   integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
 
-jest-regex-util@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.1.tgz#69d4b1bf5b690faa3490113c47486ed85dd45b68"
-  integrity sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==
+jest-regex-util@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5"
+  integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==
 
-jest-resolve-dependencies@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.5.tgz#819ccdddd909c65acddb063aac3a49e4ba1ed569"
-  integrity sha512-xUj2dPoEEd59P+nuih4XwNa4nJ/zRd/g4rMvjHrZPEBWeWRq/aJnnM6mug+B+Nx+ILXGtfWHzQvh7TqNV/WbuA==
+jest-resolve-dependencies@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz#3e619e0ef391c3ecfcf6ef4056207a3d2be3269f"
+  integrity sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==
   dependencies:
-    "@jest/types" "^27.0.2"
-    jest-regex-util "^27.0.1"
-    jest-snapshot "^27.0.5"
+    "@jest/types" "^27.0.6"
+    jest-regex-util "^27.0.6"
+    jest-snapshot "^27.0.6"
 
-jest-resolve@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.0.5.tgz#937535a5b481ad58e7121eaea46d1424a1e0c507"
-  integrity sha512-Md65pngRh8cRuWVdWznXBB5eDt391OJpdBaJMxfjfuXCvOhM3qQBtLMCMTykhuUKiBMmy5BhqCW7AVOKmPrW+Q==
+jest-resolve@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.0.6.tgz#e90f436dd4f8fbf53f58a91c42344864f8e55bff"
+  integrity sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     chalk "^4.0.0"
     escalade "^3.1.1"
     graceful-fs "^4.2.4"
     jest-pnp-resolver "^1.2.2"
-    jest-util "^27.0.2"
-    jest-validate "^27.0.2"
+    jest-util "^27.0.6"
+    jest-validate "^27.0.6"
     resolve "^1.20.0"
     slash "^3.0.0"
 
-jest-runner@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.0.5.tgz#b6fdc587e1a5056339205914294555c554efc08a"
-  integrity sha512-HNhOtrhfKPArcECgBTcWOc+8OSL8GoFoa7RsHGnfZR1C1dFohxy9eLtpYBS+koybAHlJLZzNCx2Y/Ic3iEtJpQ==
+jest-runner@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.0.6.tgz#1325f45055539222bbc7256a6976e993ad2f9520"
+  integrity sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==
   dependencies:
-    "@jest/console" "^27.0.2"
-    "@jest/environment" "^27.0.5"
-    "@jest/test-result" "^27.0.2"
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/console" "^27.0.6"
+    "@jest/environment" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     chalk "^4.0.0"
     emittery "^0.8.1"
     exit "^0.1.2"
     graceful-fs "^4.2.4"
-    jest-docblock "^27.0.1"
-    jest-environment-jsdom "^27.0.5"
-    jest-environment-node "^27.0.5"
-    jest-haste-map "^27.0.5"
-    jest-leak-detector "^27.0.2"
-    jest-message-util "^27.0.2"
-    jest-resolve "^27.0.5"
-    jest-runtime "^27.0.5"
-    jest-util "^27.0.2"
-    jest-worker "^27.0.2"
+    jest-docblock "^27.0.6"
+    jest-environment-jsdom "^27.0.6"
+    jest-environment-node "^27.0.6"
+    jest-haste-map "^27.0.6"
+    jest-leak-detector "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-runtime "^27.0.6"
+    jest-util "^27.0.6"
+    jest-worker "^27.0.6"
     source-map-support "^0.5.6"
     throat "^6.0.1"
 
-jest-runtime@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.0.5.tgz#cd5d1aa9754d30ddf9f13038b3cb7b95b46f552d"
-  integrity sha512-V/w/+VasowPESbmhXn5AsBGPfb35T7jZPGZybYTHxZdP7Gwaa+A0EXE6rx30DshHKA98lVCODbCO8KZpEW3hiQ==
+jest-runtime@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.0.6.tgz#45877cfcd386afdd4f317def551fc369794c27c9"
+  integrity sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==
   dependencies:
-    "@jest/console" "^27.0.2"
-    "@jest/environment" "^27.0.5"
-    "@jest/fake-timers" "^27.0.5"
-    "@jest/globals" "^27.0.5"
-    "@jest/source-map" "^27.0.1"
-    "@jest/test-result" "^27.0.2"
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/console" "^27.0.6"
+    "@jest/environment" "^27.0.6"
+    "@jest/fake-timers" "^27.0.6"
+    "@jest/globals" "^27.0.6"
+    "@jest/source-map" "^27.0.6"
+    "@jest/test-result" "^27.0.6"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/yargs" "^16.0.0"
     chalk "^4.0.0"
     cjs-module-lexer "^1.0.0"
@@ -6392,30 +6681,30 @@
     exit "^0.1.2"
     glob "^7.1.3"
     graceful-fs "^4.2.4"
-    jest-haste-map "^27.0.5"
-    jest-message-util "^27.0.2"
-    jest-mock "^27.0.3"
-    jest-regex-util "^27.0.1"
-    jest-resolve "^27.0.5"
-    jest-snapshot "^27.0.5"
-    jest-util "^27.0.2"
-    jest-validate "^27.0.2"
+    jest-haste-map "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-mock "^27.0.6"
+    jest-regex-util "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-snapshot "^27.0.6"
+    jest-util "^27.0.6"
+    jest-validate "^27.0.6"
     slash "^3.0.0"
     strip-bom "^4.0.0"
     yargs "^16.0.3"
 
-jest-serializer@^27.0.1:
-  version "27.0.1"
-  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.0.1.tgz#2464d04dcc33fb71dc80b7c82e3c5e8a08cb1020"
-  integrity sha512-svy//5IH6bfQvAbkAEg1s7xhhgHTtXu0li0I2fdKHDsLP2P2MOiscPQIENQep8oU2g2B3jqLyxKKzotZOz4CwQ==
+jest-serializer@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1"
+  integrity sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==
   dependencies:
     "@types/node" "*"
     graceful-fs "^4.2.4"
 
-jest-snapshot@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.0.5.tgz#6e3b9e8e193685372baff771ba34af631fe4d4d5"
-  integrity sha512-H1yFYdgnL1vXvDqMrnDStH6yHFdMEuzYQYc71SnC/IJnuuhW6J16w8GWG1P+qGd3Ag3sQHjbRr0TcwEo/vGS+g==
+jest-snapshot@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.0.6.tgz#f4e6b208bd2e92e888344d78f0f650bcff05a4bf"
+  integrity sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==
   dependencies:
     "@babel/core" "^7.7.2"
     "@babel/generator" "^7.7.2"
@@ -6423,79 +6712,79 @@
     "@babel/plugin-syntax-typescript" "^7.7.2"
     "@babel/traverse" "^7.7.2"
     "@babel/types" "^7.0.0"
-    "@jest/transform" "^27.0.5"
-    "@jest/types" "^27.0.2"
+    "@jest/transform" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/babel__traverse" "^7.0.4"
     "@types/prettier" "^2.1.5"
     babel-preset-current-node-syntax "^1.0.0"
     chalk "^4.0.0"
-    expect "^27.0.2"
+    expect "^27.0.6"
     graceful-fs "^4.2.4"
-    jest-diff "^27.0.2"
-    jest-get-type "^27.0.1"
-    jest-haste-map "^27.0.5"
-    jest-matcher-utils "^27.0.2"
-    jest-message-util "^27.0.2"
-    jest-resolve "^27.0.5"
-    jest-util "^27.0.2"
+    jest-diff "^27.0.6"
+    jest-get-type "^27.0.6"
+    jest-haste-map "^27.0.6"
+    jest-matcher-utils "^27.0.6"
+    jest-message-util "^27.0.6"
+    jest-resolve "^27.0.6"
+    jest-util "^27.0.6"
     natural-compare "^1.4.0"
-    pretty-format "^27.0.2"
+    pretty-format "^27.0.6"
     semver "^7.3.2"
 
-jest-util@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.0.2.tgz#fc2c7ace3c75ae561cf1e5fdb643bf685a5be7c7"
-  integrity sha512-1d9uH3a00OFGGWSibpNYr+jojZ6AckOMCXV2Z4K3YXDnzpkAaXQyIpY14FOJPiUmil7CD+A6Qs+lnnh6ctRbIA==
+jest-util@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.0.6.tgz#e8e04eec159de2f4d5f57f795df9cdc091e50297"
+  integrity sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     chalk "^4.0.0"
     graceful-fs "^4.2.4"
     is-ci "^3.0.0"
     picomatch "^2.2.3"
 
-jest-validate@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.0.2.tgz#7fe2c100089449cd5cbb47a5b0b6cb7cda5beee5"
-  integrity sha512-UgBF6/oVu1ofd1XbaSotXKihi8nZhg0Prm8twQ9uCuAfo59vlxCXMPI/RKmrZEVgi3Nd9dS0I8A0wzWU48pOvg==
+jest-validate@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.0.6.tgz#930a527c7a951927df269f43b2dc23262457e2a6"
+  integrity sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     camelcase "^6.2.0"
     chalk "^4.0.0"
-    jest-get-type "^27.0.1"
+    jest-get-type "^27.0.6"
     leven "^3.1.0"
-    pretty-format "^27.0.2"
+    pretty-format "^27.0.6"
 
-jest-watcher@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.0.2.tgz#dab5f9443e2d7f52597186480731a8c6335c5deb"
-  integrity sha512-8nuf0PGuTxWj/Ytfw5fyvNn/R80iXY8QhIT0ofyImUvdnoaBdT6kob0GmhXR+wO+ALYVnh8bQxN4Tjfez0JgkA==
+jest-watcher@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.0.6.tgz#89526f7f9edf1eac4e4be989bcb6dec6b8878d9c"
+  integrity sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==
   dependencies:
-    "@jest/test-result" "^27.0.2"
-    "@jest/types" "^27.0.2"
+    "@jest/test-result" "^27.0.6"
+    "@jest/types" "^27.0.6"
     "@types/node" "*"
     ansi-escapes "^4.2.1"
     chalk "^4.0.0"
-    jest-util "^27.0.2"
+    jest-util "^27.0.6"
     string-length "^4.0.1"
 
-jest-worker@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.2.tgz#4ebeb56cef48b3e7514552f80d0d80c0129f0b05"
-  integrity sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==
+jest-worker@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed"
+  integrity sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==
   dependencies:
     "@types/node" "*"
     merge-stream "^2.0.0"
     supports-color "^8.0.0"
 
-jest@^27.0.5:
-  version "27.0.5"
-  resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.5.tgz#141825e105514a834cc8d6e44670509e8d74c5f2"
-  integrity sha512-4NlVMS29gE+JOZvgmSAsz3eOjkSsHqjTajlIsah/4MVSmKvf3zFP/TvgcLoWe2UVHiE9KF741sReqhF0p4mqbQ==
+jest@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.6.tgz#10517b2a628f0409087fbf473db44777d7a04505"
+  integrity sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==
   dependencies:
-    "@jest/core" "^27.0.5"
+    "@jest/core" "^27.0.6"
     import-local "^3.0.2"
-    jest-cli "^27.0.5"
+    jest-cli "^27.0.6"
 
 js-sha3@0.5.7, js-sha3@^0.5.7:
   version "0.5.7"
@@ -6931,6 +7220,13 @@
     typescript "^3.9.5"
     walkdir "^0.4.1"
 
+magic-string@^0.25.5, magic-string@^0.25.7:
+  version "0.25.7"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
+  integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
+  dependencies:
+    sourcemap-codec "^1.4.4"
+
 make-dir@^2.0.0, make-dir@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@@ -7366,6 +7662,11 @@
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20"
   integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==
 
+node-releases@^1.1.73:
+  version "1.1.74"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e"
+  integrity sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==
+
 node-source-walk@^4.0.0, node-source-walk@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-4.2.0.tgz#c2efe731ea8ba9c03c562aa0a9d984e54f27bc2c"
@@ -7812,7 +8113,7 @@
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
   integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
 
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
   integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
@@ -7994,17 +8295,17 @@
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
   integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
 
-prettier@^2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
-  integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==
+prettier@^2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
+  integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==
 
-pretty-format@^27.0.2:
-  version "27.0.2"
-  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.2.tgz#9283ff8c4f581b186b2d4da461617143dca478a4"
-  integrity sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==
+pretty-format@^27.0.6:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.6.tgz#ab770c47b2c6f893a21aefc57b75da63ef49a11f"
+  integrity sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==
   dependencies:
-    "@jest/types" "^27.0.2"
+    "@jest/types" "^27.0.6"
     ansi-regex "^5.0.0"
     ansi-styles "^5.0.0"
     react-is "^17.0.1"
@@ -8454,7 +8755,7 @@
   resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2:
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2:
   version "1.20.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
   integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -8524,6 +8825,13 @@
   dependencies:
     bn.js "^4.11.1"
 
+rollup@^2.56.2:
+  version "2.56.2"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.2.tgz#a045ff3f6af53ee009b5f5016ca3da0329e5470f"
+  integrity sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==
+  optionalDependencies:
+    fsevents "~2.3.2"
+
 run-async@^2.4.0:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@@ -8543,10 +8851,10 @@
   dependencies:
     tslib "^1.9.0"
 
-rxjs@^7.2.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.2.0.tgz#5cd12409639e9514a71c9f5f9192b2c4ae94de31"
-  integrity sha512-aX8w9OpKrQmiPKfT1bqETtUr9JygIz6GZ+gql8v7CijClsP0laoFUdKzxFAoWuRdSlOdU2+crss+cMf+cqMTnw==
+rxjs@^7.3.0:
+  version "7.3.0"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.3.0.tgz#39fe4f3461dc1e50be1475b2b85a0a88c1e938c6"
+  integrity sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw==
   dependencies:
     tslib "~2.1.0"
 
@@ -8894,6 +9202,11 @@
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
   integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
 
+sourcemap-codec@^1.4.4:
+  version "1.4.8"
+  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
 spdx-correct@^3.0.0:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
@@ -9453,16 +9766,16 @@
   dependencies:
     safe-buffer "^5.0.1"
 
+tweetnacl@1.x.x, tweetnacl@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
+  integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
+
 tweetnacl@^0.14.3, tweetnacl@~0.14.0:
   version "0.14.5"
   resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
   integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
 
-tweetnacl@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
-  integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
-
 type-check@^0.4.0, type-check@~0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -9527,11 +9840,16 @@
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
   integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
 
-typescript@^4.2.4, typescript@^4.3.4:
+typescript@^4.2.4:
   version "4.3.4"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.4.tgz#3f85b986945bcf31071decdd96cf8bfa65f9dcbc"
   integrity sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==
 
+typescript@^4.3.5:
+  version "4.3.5"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
+  integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
+
 uglify-js@^3.1.4:
   version "3.13.9"
   resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.9.tgz#4d8d21dcd497f29cfd8e9378b9df123ad025999b"
@@ -10339,7 +10657,7 @@
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
-yargs@^17.0.0, yargs@^17.0.1:
+yargs@^17.0.0:
   version "17.0.1"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb"
   integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==
@@ -10352,6 +10670,19 @@
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
+yargs@^17.1.0, yargs@^17.1.1:
+  version "17.1.1"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba"
+  integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==
+  dependencies:
+    cliui "^7.0.2"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
+    require-directory "^2.1.1"
+    string-width "^4.2.0"
+    y18n "^5.0.5"
+    yargs-parser "^20.2.2"
+
 yn@3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"