diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
new file mode 100644
index 00000000..ce671674
--- /dev/null
+++ b/.github/workflows/e2e.yml
@@ -0,0 +1,79 @@
+name: End-to-end test
+on:
+ push:
+ branches:
+ - master
+ paths-ignore:
+ - '**.md'
+ pull_request:
+ branches:
+ - master
+ paths-ignore:
+ - '**.md'
+
+jobs:
+ build_code:
+ name: End to end test
+ runs-on: ubuntu-latest
+ timeout-minutes: 120
+ strategy:
+ matrix:
+ node-version: [16.x]
+ env:
+ MANTA_SDK_BRANCH: "main"
+
+ steps:
+ - name: Cancel previous runs
+ uses: styfle/cancel-workflow-action@0.9.1
+ with:
+ access_token: ${{ github.token }}
+ - uses: actions/checkout@v1
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Build manta-signer test server
+ run: cargo build --example test_server --release --features=unsafe-disable-cors
+ - name: Build manta-js
+ run: |
+ cd js
+ yarn install --immutable | grep -v 'YN0013'
+ yarn build
+
+ - name: Enable test scripts
+ run: |
+ chmod +x "${GITHUB_WORKSPACE}/.github/workflows/e2e/get_latest_sdk_version.sh"
+ chmod +x "${GITHUB_WORKSPACE}/.github/workflows/e2e/move_proving_keys.sh"
+ chmod +x "${GITHUB_WORKSPACE}/.github/workflows/e2e/get_node.sh"
+ chmod +x "${GITHUB_WORKSPACE}/.github/workflows/e2e/run_test.sh"
+
+ - name: Get latest Manta sdk version
+ run: |
+ LATEST_SDK_VERSION=`"${GITHUB_WORKSPACE}/.github/workflows/e2e/get_latest_sdk_version.sh" ${{ env.MANTA_SDK_BRANCH }}`
+ echo $LATEST_SDK_VERSION
+ echo "LATEST_SDK_VERSION=$LATEST_SDK_VERSION" >> $GITHUB_ENV
+ - name: Load proving keys from cache
+ id: load-cache-proving-keys
+ uses: actions/cache@v2
+ env:
+ cache-name: proving-keys
+ with:
+ path: ~/.local/share/manta-signer
+ key: ${{ env.cache-name }}-${{ env.LATEST_SDK_VERSION }}
+ - name: Get proving keys
+ if: steps.load-cache-proving-keys.outputs.cache-hit != 'true'
+ uses: actions/checkout@v2
+ with:
+ repository: Manta-Network/sdk
+ path: sdk
+ fetch-depth: 1
+ lfs: true
+ - name: Move proving keys
+ if: steps.load-cache-proving-keys.outputs.cache-hit != 'true'
+ run: "${GITHUB_WORKSPACE}/.github/workflows/e2e/move_proving_keys.sh"
+
+ - name: Get Dolphin node
+ run: "${GITHUB_WORKSPACE}/.github/workflows/e2e/get_node.sh"
+
+ - name: Run test
+ run: "${GITHUB_WORKSPACE}/.github/workflows/e2e/run_test.sh"
diff --git a/.github/workflows/e2e/get_latest_sdk_version.sh b/.github/workflows/e2e/get_latest_sdk_version.sh
new file mode 100644
index 00000000..5ff80b12
--- /dev/null
+++ b/.github/workflows/e2e/get_latest_sdk_version.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+BRANCH=$1
+
+git ls-remote https://github.com/manta-network/sdk.git $BRANCH | awk '{ print $1}'
diff --git a/.github/workflows/e2e/get_node.sh b/.github/workflows/e2e/get_node.sh
new file mode 100644
index 00000000..055fa74e
--- /dev/null
+++ b/.github/workflows/e2e/get_node.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+cd ~
+mkdir Manta
+cd Manta
+curl https://manta-ops.s3.amazonaws.com/Dolphin-v0.2.1-841eb2f-x86_64-linux-gnu/manta --output manta
+chmod +x manta
diff --git a/.github/workflows/e2e/move_proving_keys.sh b/.github/workflows/e2e/move_proving_keys.sh
new file mode 100644
index 00000000..8e720787
--- /dev/null
+++ b/.github/workflows/e2e/move_proving_keys.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+mkdir ~/.local
+mkdir ~/.local/share
+mkdir ~/.local/share/manta-signer
+cp ./sdk/zkp/reclaim_pk.bin ~/.local/share/manta-signer
+cp ./sdk/zkp/transfer_pk.bin ~/.local/share/manta-signer
diff --git a/.github/workflows/e2e/run_test.sh b/.github/workflows/e2e/run_test.sh
new file mode 100644
index 00000000..25baa154
--- /dev/null
+++ b/.github/workflows/e2e/run_test.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Create 10-round simulation instructions and save output
+cd js/e2e/simulation
+cargo run 10 | tail -n +2 > out.json
+cat out.json
+
+# Run 3 headless copies of signer
+cd ../../..
+cargo run --example test_server --release --features=unsafe-disable-cors -- http://127.0.0.1:29988 &
+cargo run --example test_server --release --features=unsafe-disable-cors -- http://127.0.0.1:29989 &
+cargo run --example test_server --release --features=unsafe-disable-cors -- http://127.0.0.1:29990 &
+
+# Run node
+~/Manta/manta --chain dev --ws-port 9944 --port 30333 --alice \
+--tmp --rpc-cors all --unsafe-ws-external --unsafe-rpc-external \
+--rpc-methods=Unsafe &
+
+# Run test
+cd js
+yarn test
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f4583219..138f638b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,8 +1,8 @@
-name: Build and upload binaries
+name: Build and upload release binaries
on:
pull_request:
- branches:
+ branches:
- master
release:
types: [published]
@@ -52,22 +52,22 @@ jobs:
cache-name: cache-cargo
with:
path: ~/.cargo
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./ui/src-tauri/Cargo.lock') }}
+ key: ${{ matrix.os }}-build-${{ env.cache-name }}-${{ hashFiles('./ui/src-tauri/Cargo.lock') }}
restore-keys: |
- ${{ runner.os }}-build-${{ env.cache-name }}-
- ${{ runner.os }}-build-
- ${{ runner.os }}-
+ ${{ matrix.os }}-build-${{ env.cache-name }}-
+ ${{ matrix.os }}-build-
+ ${{ matrix.os }}-
- name: Cache target dir
uses: actions/cache@v2
env:
cache-name: cache-target
with:
path: ui/src-tauri/target
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./ui/src-tauri/Cargo.lock') }}
+ key: ${{ matrix.os }}-build-${{ env.cache-name }}-${{ hashFiles('./ui/src-tauri/Cargo.lock') }}
restore-keys: |
- ${{ runner.os }}-build-${{ env.cache-name }}-
- ${{ runner.os }}-build-
- ${{ runner.os }}-
+ ${{ matrix.os }}-build-${{ env.cache-name }}-
+ ${{ matrix.os }}-build-
+ ${{ matrix.os }}-
- name: Fetch Proving Keys
uses: actions/checkout@v2
with:
@@ -118,7 +118,7 @@ jobs:
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: "ui/src-tauri/target/release/bundle/msi/manta-signer_${{ needs.setup.outputs.release_version }}_x64.msi"
- asset_name: "manta-signer-${{ matrix.os }}_${{ needs.setup.outputs.release_version }}_x64.msi"
+ asset_name: "manta-signer-${{ matrix.os }}_${{ needs.setup.outputs.release_version }}_x64.msi"
asset_content_type: application/binary
if: matrix.os_type == 'windows' && github.event_name == 'release' && github.event.action == 'published'
- name: Upload Mac Image
@@ -128,6 +128,6 @@ jobs:
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: "ui/src-tauri/target/release/bundle/dmg/manta-signer_${{ needs.setup.outputs.release_version }}_x64.dmg"
- asset_name: "manta-signer-${{ matrix.os }}_${{ needs.setup.outputs.release_version }}_x64.dmg"
+ asset_name: "manta-signer-${{ matrix.os }}_${{ needs.setup.outputs.release_version }}_x64.dmg"
asset_content_type: application/binary
if: matrix.os_type == 'macos' && github.event_name == 'release' && github.event.action == 'published'
diff --git a/README.md b/README.md
index 081c42ea..c2606046 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
manta-signer
============
-`manta-signer` is manta's native client that **turbo charges** zero-knowledge-proof generation.
+`manta-signer` is manta's native client that **turbo charges** zero-knowledge-proof generation.
@@ -11,5 +11,6 @@ Disclaimer: `manta-signer` is experimental software, use it at your own risk.
```
-src: manta-signer zkp generation
-ui: manta-signer desktop UI
+-js: external Javascript libraries that interact with manta-signer
```
diff --git a/js/.env b/js/.env
new file mode 100644
index 00000000..2accbba8
--- /dev/null
+++ b/js/.env
@@ -0,0 +1 @@
+ESLINT_NO_DEV_ERRORS=true
diff --git a/js/.eslintrc.yml b/js/.eslintrc.yml
new file mode 100644
index 00000000..c90321df
--- /dev/null
+++ b/js/.eslintrc.yml
@@ -0,0 +1,30 @@
+env:
+ commonjs: true
+ es2021: true
+extends:
+ - standard
+parser: '@typescript-eslint/parser'
+parserOptions:
+ ecmaVersion: 12
+plugins:
+ - '@typescript-eslint'
+ignorePatterns: ['types.d.ts']
+rules:
+ {
+ 'indent': ['error', 2],
+ 'linebreak-style': ['error', 'unix'],
+ 'quotes': ['error', 'single'],
+ 'semi': ['error', 'always'],
+ 'space-before-function-paren': ['error', 'never'],
+ 'comma-dangle':
+ [
+ 'error',
+ {
+ 'arrays': 'never',
+ 'objects': 'never',
+ 'imports': 'never',
+ 'exports': 'never',
+ 'functions': 'never'
+ }
+ ]
+ }
diff --git a/js/.prettierrc b/js/.prettierrc
new file mode 100644
index 00000000..c517dd97
--- /dev/null
+++ b/js/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "none"
+}
\ No newline at end of file
diff --git a/js/.yarnrc.yml b/js/.yarnrc.yml
new file mode 100644
index 00000000..de80f2ba
--- /dev/null
+++ b/js/.yarnrc.yml
@@ -0,0 +1,2 @@
+nodeLinker: node-modules
+nmHoistingLimits: workspaces
diff --git a/js/README.md b/js/README.md
new file mode 100644
index 00000000..4b7b9849
--- /dev/null
+++ b/js/README.md
@@ -0,0 +1,63 @@
+# Signer JS Libraries
+
+This workspace includes the following packages:
+
+| name | path | description | status |
+|------------------|---------------------|-----------------------------------------|---------------|
+| dophin-api | `./dolphin-api` | api for dolphin nodes. | experimental |
+| workflows | `./workflows` | logical workflows with extrinsics. | experimental |
+| e2e | `./e2e` | end-to-end test suites. | experimental |
+| singer-interface | `/signer-interface` | typescript interface for manta-signer. | experimental |
+| coin-selection | `/coin-selection` | simple coin selection logic | experimental |
+
+
+## Build
+Tested environment:
+* node: `v16.x`
+* yarn: `1.22.x`
+
+```yarn install && yarn build```
+
+## Test Setup
+
+1. Make sure you have a node running that you want to connect to.
+
+```bash
+ git clone -b dolphin git@github.com:Manta-Network/Manta.git
+ cd Manta
+ cargo build --release
+ ./target/release/manta --dev --tmp --alice --unsafe-ws-external
+```
+
+Which will be live at `ws://127.0.0.1:9944`.
+
+2. [Run manta-signer test server](https://github.com/Manta-Network/manta-signer/tree/master/examples)
+
+
+## Tests
+You can run the entire testsuite with
+
+```yarn run e2e test```
+
+
+### Create a new test
+The test suite is set up using [mocha](https://mochajs.org/) as the test runner and [chai](https://www.chaijs.com/) for the assertion library.
+Both projects have good documentation on how to use them.
+
+Add a new test by adding a `describe()` call in `e2e/test/test.ts`.
+
+
+## Workflows
+To create a new workflow to be uses in `dev-cli` or `e2e` tests,
+start by choosing a name for your workflow. Then create a copy of
+`/manta-workflows/src/workflows/init_asset_workflow.ts` with the new name, and
+replace all instances of `initAssetWorkflow` in the file with the new name.
+
+Both repositories already have `manta-workflows` as a dependency, so to use a
+workflow recompile the project:
+
+```yarn run workflows build```
+
+And then import your workflow like
+
+``` import { initAssetWorkflow } from 'manta-workflows';```
diff --git a/js/coin-selection/README.md b/js/coin-selection/README.md
new file mode 100644
index 00000000..cec60d8c
--- /dev/null
+++ b/js/coin-selection/README.md
@@ -0,0 +1,3 @@
+# Manta Coin Selection
+
+Coin selection logic for Manta / Calamari Network, for now extremely basic
diff --git a/js/coin-selection/package.json b/js/coin-selection/package.json
new file mode 100644
index 00000000..6a18a192
--- /dev/null
+++ b/js/coin-selection/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "coin-selection",
+ "version": "0.1.1",
+ "main": "dist/index.js",
+ "description": "Coin selection logic for Manta and Calamari Netowrk",
+ "license": "GPL-3.0-only",
+ "scripts": {
+ "build": "rm -rf coin-selection/dist ; tsc"
+ },
+ "dependencies": {
+ "bn.js": "^5.2.0"
+ },
+ "devDependencies": {
+ "typescript": "^4.4.4"
+ }
+}
\ No newline at end of file
diff --git a/js/coin-selection/src/coinSelection.ts b/js/coin-selection/src/coinSelection.ts
new file mode 100644
index 00000000..57cd6b69
--- /dev/null
+++ b/js/coin-selection/src/coinSelection.ts
@@ -0,0 +1,32 @@
+// @ts-nocheck
+export class CoinSelection {
+ constructor(coins, totalValueAtomicUnits, targetValueAtomicUnits, assetId) {
+ this.coins = coins;
+ this.totalValueAtomicUnits = totalValueAtomicUnits;
+ this.targetValueAtomicUnits = targetValueAtomicUnits;
+ this.assetId = assetId;
+ this.changeValueAtomicUnits = totalValueAtomicUnits.sub(
+ targetValueAtomicUnits
+ );
+ }
+
+ numberOfZeroCoinsRequired() {
+ return Math.max(0, 2 - this.coins.length);
+ }
+
+ last() {
+ const last = this.coins[this.coins.length - 1];
+ if (!last) {
+ throw new Error('Coin selection does not contain any coins');
+ }
+ return last;
+ }
+
+ secondLast() {
+ const secondLast = this.coins[this.coins.length - 2];
+ if (!secondLast) {
+ throw new Error('Coin selection contains fewer than two coins');
+ }
+ return secondLast;
+ }
+}
diff --git a/js/coin-selection/src/index.ts b/js/coin-selection/src/index.ts
new file mode 100644
index 00000000..88533219
--- /dev/null
+++ b/js/coin-selection/src/index.ts
@@ -0,0 +1,4 @@
+import { CoinSelection } from './coinSelection.js';
+import { selectCoins } from './selectCoins.js';
+
+export { CoinSelection, selectCoins };
diff --git a/js/coin-selection/src/selectCoins.ts b/js/coin-selection/src/selectCoins.ts
new file mode 100644
index 00000000..fd4fadeb
--- /dev/null
+++ b/js/coin-selection/src/selectCoins.ts
@@ -0,0 +1,41 @@
+// @ts-nocheck
+import * as BN from 'bn.js';
+import { CoinSelection } from './coinSelection.js';
+
+/**
+ * Add eligible assets to our coin selection until we reach target amount
+ * If less than two coins selected, add more if possible, to avoid necessity of
+ * minting coins with zero value.
+ */
+export const selectCoins = (
+ targetValueAtomicUnits,
+ spendableAssets,
+ assetId
+) => {
+ let totalValueAtomicUnits = new BN(0);
+ const selectedCoins = [];
+ spendableAssets
+ .filter((asset) => asset.assetId === assetId)
+ .forEach((asset) => {
+ if (
+ totalValueAtomicUnits.lt(targetValueAtomicUnits) ||
+ selectedCoins.length < 2
+ ) {
+ totalValueAtomicUnits = totalValueAtomicUnits.add(
+ asset.valueAtomicUnits
+ );
+ selectedCoins.push(asset);
+ }
+ });
+
+ if (totalValueAtomicUnits.lt(targetValueAtomicUnits)) {
+ throw new Error('Coin selection; insufficient funds');
+ }
+
+ return new CoinSelection(
+ selectedCoins,
+ totalValueAtomicUnits,
+ targetValueAtomicUnits,
+ assetId
+ );
+};
diff --git a/js/coin-selection/tsconfig.json b/js/coin-selection/tsconfig.json
new file mode 100644
index 00000000..ce91a36f
--- /dev/null
+++ b/js/coin-selection/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "target": "ES6",
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "skipLibCheck": true,
+ "esModuleInterop": false
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules"]
+}
diff --git a/js/coin-selection/yarn.lock b/js/coin-selection/yarn.lock
new file mode 100644
index 00000000..662189c4
--- /dev/null
+++ b/js/coin-selection/yarn.lock
@@ -0,0 +1,8 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+bn.js@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
+ integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
diff --git a/js/dolphin-api/README.md b/js/dolphin-api/README.md
new file mode 100644
index 00000000..3a2369b3
--- /dev/null
+++ b/js/dolphin-api/README.md
@@ -0,0 +1,9 @@
+Dolphin-API
+============
+
+Type definition for dolphin testnet.
+
+## Output type defintions
+```bash
+npx ts-node ./src/output.ts
+```
diff --git a/js/dolphin-api/package.json b/js/dolphin-api/package.json
new file mode 100644
index 00000000..c1706c01
--- /dev/null
+++ b/js/dolphin-api/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "dolphin-api",
+ "version": "0.2.0",
+ "description": "api for manta/calamari/dolphin",
+ "main": "./dist/index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "build": "rm -rf dolphin-api/dist; tsc"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "typescript": "^4.4.4"
+ }
+}
\ No newline at end of file
diff --git a/js/dolphin-api/src/index.ts b/js/dolphin-api/src/index.ts
new file mode 100644
index 00000000..429b44e7
--- /dev/null
+++ b/js/dolphin-api/src/index.ts
@@ -0,0 +1 @@
+export { DolphinTypes } from './types';
diff --git a/js/dolphin-api/src/output.ts b/js/dolphin-api/src/output.ts
new file mode 100644
index 00000000..97ce96d3
--- /dev/null
+++ b/js/dolphin-api/src/output.ts
@@ -0,0 +1,7 @@
+import { DolphinTypes } from '.';
+var fs = require('fs');
+var json = JSON.stringify(DolphinTypes, null, 2);
+fs.writeFile('types.json', json, 'utf8', function(err) {
+ if (err) throw err;
+ console.log('complete');
+ });
\ No newline at end of file
diff --git a/js/dolphin-api/src/types.ts b/js/dolphin-api/src/types.ts
new file mode 100644
index 00000000..f99e70e3
--- /dev/null
+++ b/js/dolphin-api/src/types.ts
@@ -0,0 +1,123 @@
+export const DolphinTypes = {
+ CurrencyId: {
+ _enum: [
+ "DOL"
+ ]
+ },
+ Address: 'MultiAddress',
+ LookupSource: 'MultiAddress',
+ AssetBalance: 'u128',
+ AssetId: 'u32',
+ MantaRandomValue: '[u8; 32]',
+ MantaSecretKey: '[u8; 32]',
+ MantaPublicKey: '[u8; 32]',
+ UTXO: '[u8; 32]',
+ MantaEciesCiphertext: {
+ encrypted_msg: '[u8; 36]',
+ ephemeral_pk: '[u8; 32]'
+ },
+ MantaAssetShieldedAddress: {
+ k: 'MantaRandomValue',
+ s: 'MantaRandomValue',
+ ecpk: 'MantaSecretKey'
+ },
+ SenderData: {
+ void_number: 'MantaRandomValue',
+ root: 'MantaRandomValue',
+ shard_index: 'u8'
+ },
+ ReceiverData: {
+ cm: 'MantaRandomValue',
+ encrypted_note: 'MantaEciesCiphertext'
+ },
+ MintData: {
+ asset_id: 'AssetId',
+ value: 'AssetBalance',
+ cm: 'MantaRandomValue',
+ k: 'MantaRandomValue',
+ s: 'MantaRandomValue',
+ encrypted_note: 'MantaEciesCiphertext'
+ },
+ PrivateTransferData: {
+ sender_0: 'SenderData',
+ sender_1: 'SenderData',
+ receiver_0: 'ReceiverData',
+ receiver_1: 'ReceiverData',
+ proof: '[u8; 192]'
+ },
+ ReclaimData: {
+ asset_id: 'AssetId',
+ sender_0: 'SenderData',
+ sender_1: 'SenderData',
+ receiver: 'ReceiverData',
+ reclaim_value: 'AssetBalance',
+ proof: '[u8; 192]'
+ },
+ DeriveShieldedAddressParams: {
+ keypath: 'String'
+ },
+ GenerateAssetParams: {
+ asset_id: 'AssetId',
+ value: 'AssetBalance',
+ keypath: 'String'
+ },
+ GeneratePrivateTransferParams: {
+ sender_asset_1_value: 'AssetBalance',
+ sender_asset_2_value: 'AssetBalance',
+ sender_asset_1_keypath: 'String',
+ sender_asset_2_keypath: 'String',
+ sender_asset_1_shard: 'Vec<[u8; 32]>',
+ sender_asset_2_shard: 'Vec<[u8; 32]>',
+ change_output_keypath: 'String',
+ non_change_output_keypath: 'Option',
+ non_change_output_value: 'AssetBalance',
+ change_output_value: 'AssetBalance'
+ },
+ GeneratePrivateTransferBatchParams: {
+ asset_id: 'AssetId',
+ receiving_address: 'MantaAssetShieldedAddress',
+ private_transfer_params_list: 'Vec'
+ },
+ PrivateTransferBatch: {
+ private_transfer_data_list: 'Vec'
+ },
+ GenerateReclaimParams: {
+ asset_id: 'AssetId',
+ input_asset_1_value: 'AssetBalance',
+ input_asset_2_value: 'AssetBalance',
+ input_asset_1_keypath: 'String',
+ input_asset_2_keypath: 'String',
+ input_asset_1_shard: 'Vec<[u8; 32]>',
+ input_asset_2_shard: 'Vec<[u8; 32]>',
+ change_keypath: 'String',
+ reclaim_value: 'AssetBalance'
+ },
+ GenerateReclaimBatchParams: {
+ private_transfer_params_list: 'Vec',
+ reclaim_params: 'GenerateReclaimParams'
+ },
+ ReclaimBatch: {
+ private_transfer_data_list: 'Vec',
+ reclaim_data: 'ReclaimData'
+ },
+ RecoverAccountParams: {
+ void_numbers: 'Vec',
+ utxos: 'Vec',
+ encrypted_notes: 'Vec'
+ },
+ MantaSignerInputAsset: {
+ keypath: 'String',
+ asset_id: 'AssetId',
+ value: 'AssetBalance',
+ utxo: 'UTXO',
+ shard_index: 'u8',
+ void_number: 'MantaRandomValue'
+ },
+ RecoveredAccount: {
+ assets: 'Vec'
+ },
+ ShardMetaData: {
+ current_index: 'u64',
+ current_auth_path: '[u8; 584]'
+ }
+};
diff --git a/js/dolphin-api/tsconfig.json b/js/dolphin-api/tsconfig.json
new file mode 100644
index 00000000..1e3c2e10
--- /dev/null
+++ b/js/dolphin-api/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "target": "ES6",
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "skipLibCheck": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules"]
+}
diff --git a/js/e2e/README.md b/js/e2e/README.md
new file mode 100644
index 00000000..7db8ec60
--- /dev/null
+++ b/js/e2e/README.md
@@ -0,0 +1,18 @@
+# Manta client end to end test
+
+Test randomly simulating
+
+### How to run
+
+0. Setup the simulation file `cd simulation && cargo run -- -o out.json 10`
+1. Run a local Manta node
+2. Run four instances of [`manta-signer`](https://github.com/Manta-Network/manta-signer) test server on localhost ports 29987-29990. It might be convenient to add aliases to your bash profile:
+
+```bash
+alias alice_signer="cd /path/to/manta-signer/examples && cargo run --example test_server --release -- http://127.0.0.1:29987"
+alias bob_signer="cd /path/to/manta-signer/examples && cargo run --example test_server --release -- http://127.0.0.1:29988"
+alias charlie_signer="cd /path/to/manta-signer/examples && cargo run --example test_server --release -- http://127.0.0.1:29989"
+alias dave_signer="cd /path/to/manta-signer/examples && cargo run --example test_server --release -- http://127.0.0.1:29990"
+```
+
+3. From the root of `manta-js`, run `yarn install && yarn build && yarn test`
diff --git a/js/e2e/package.json b/js/e2e/package.json
new file mode 100644
index 00000000..ed884c03
--- /dev/null
+++ b/js/e2e/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "e2e",
+ "version": "0.2.0",
+ "description": "A library of e2e tests for manta",
+ "repository": "git@github.com:Manta-Network/manta-js",
+ "author": "Gabriela Brown ",
+ "scripts": {
+ "build": "tsc --build",
+ "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register './test/*.ts'"
+ },
+ "license": "GPL-3.0-only",
+ "dependencies": {
+ "workflows": "0.2.0",
+ "@types/chai": "^4.2.21",
+ "@types/mocha": "^9.0.0",
+ "chai": "^4.3.4",
+ "mocha": "^9.1.1",
+ "dolphin-api": "0.2.0",
+ "signer-interface": "^0.2.0"
+ }
+}
\ No newline at end of file
diff --git a/js/e2e/simulation/.gitignore b/js/e2e/simulation/.gitignore
new file mode 100644
index 00000000..54466f5b
--- /dev/null
+++ b/js/e2e/simulation/.gitignore
@@ -0,0 +1,2 @@
+/target
+
diff --git a/js/e2e/simulation/.rustfmt.toml b/js/e2e/simulation/.rustfmt.toml
new file mode 100644
index 00000000..e69de29b
diff --git a/js/e2e/simulation/Cargo.toml b/js/e2e/simulation/Cargo.toml
new file mode 100644
index 00000000..e25f824f
--- /dev/null
+++ b/js/e2e/simulation/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "manta-simulation"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+clap = "2.33.3"
+indexmap = { version = "1.7.0", features = ["serde"] }
+rand = "0.8.4"
+serde = { version = "1.0.130", features = ["derive"] }
+serde_json = "1.0.68"
+statrs = "0.15.0"
+
diff --git a/js/e2e/simulation/README.md b/js/e2e/simulation/README.md
new file mode 100644
index 00000000..d61f73de
--- /dev/null
+++ b/js/e2e/simulation/README.md
@@ -0,0 +1,13 @@
+# manta-simulation
+
+This is a temporary simulation suite for possible transactions on the Manta Network. This should only be used for internal testing at the moment. Eventually, this should be part of a larger, more comprehensive, end-to-end testing solution.
+
+## Running the Simulation
+
+To run the simulation, use `cargo run -- `. For the list of options use `cargo run -- --help`.
+
+## Configuration
+
+See the `Config` struct in `src/main.rs` for documetation on configuration options for the simulator and see `default-config.json` for the default configuration. The default configuration is automatically used by `cargo run` if the `--config` option is not passed.
+
+For more documentation run `cargo doc --open`.
diff --git a/js/e2e/simulation/default-config.json b/js/e2e/simulation/default-config.json
new file mode 100644
index 00000000..1bc7cd02
--- /dev/null
+++ b/js/e2e/simulation/default-config.json
@@ -0,0 +1,41 @@
+{
+ "starting_account_count": 3,
+ "new_account_sampling_cycle": 0,
+ "account_count_growth_rate": 1.0,
+ "maximum_account_count": 0,
+ "allowed_asset_sampling": {
+ "0": 10000,
+ "1": 1000,
+ "2": 100,
+ "3": 10,
+ "4": 1
+ },
+ "action_sampling_ranges": {
+ "none": {
+ "start": 1.0,
+ "end": 100.0
+ },
+ "public_deposit": {
+ "start": 1.0,
+ "end": 25.0
+ },
+ "public_withdraw": {
+ "start": 1.0,
+ "end": 25.0
+ },
+ "mint": {
+ "start": 50.0,
+ "end": 100.0
+ },
+ "private_transfer": {
+ "start": 50.0,
+ "end": 100.0
+ },
+ "reclaim": {
+ "start": 50.0,
+ "end": 100.0
+ }
+ },
+ "maximum_updates_per_step": 2048,
+ "maximum_total_updates": 262144
+}
\ No newline at end of file
diff --git a/js/e2e/simulation/src/main.rs b/js/e2e/simulation/src/main.rs
new file mode 100644
index 00000000..d2a4f791
--- /dev/null
+++ b/js/e2e/simulation/src/main.rs
@@ -0,0 +1,707 @@
+//! Manta Simulation
+
+use clap::{App, Arg};
+use core::cmp::min;
+use core::ops::Range;
+use indexmap::IndexMap;
+use rand::{distributions::Distribution, seq::SliceRandom, thread_rng, Rng, RngCore};
+use serde::{Deserialize, Serialize};
+use statrs::{
+ distribution::{Categorical, Discrete, Poisson},
+ StatsError,
+};
+use std::collections::HashMap;
+use std::fs;
+
+/// Flushes the STDOUT buffer.
+#[inline]
+fn flush_stdout() {
+ use std::io::Write;
+ let _ = std::io::stdout().flush();
+}
+
+/// Choose `count`-many elements from `vec` randomly and drop the remaining ones.
+#[inline]
+fn choose_multiple(vec: &mut Vec, count: usize, rng: &mut R)
+where
+ R: RngCore + ?Sized,
+{
+ let drop_count = vec.partial_shuffle(rng, count).1.len();
+ vec.drain(0..drop_count);
+}
+
+/// Asset Id
+pub type AssetId = u32;
+
+/// Asset Value
+pub type AssetValue = u128;
+
+/// Asset
+#[derive(Clone, Copy, Debug, Default, Deserialize, Hash, Eq, PartialEq, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct Asset {
+ /// Asset Id
+ pub id: AssetId,
+
+ /// Asset Value
+ pub value: AssetValue,
+}
+
+impl Asset {
+ /// Builds a new [`Asset`] from the given `id` and `value`.
+ #[inline]
+ pub fn new(id: AssetId, value: AssetValue) -> Self {
+ Self { id, value }
+ }
+}
+
+/// Balance State
+#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
+#[serde(deny_unknown_fields, transparent)]
+pub struct BalanceState {
+ /// Asset Map
+ map: HashMap,
+}
+
+impl BalanceState {
+ /// Returns the asset balance associated to the assets with the given `id`.
+ #[inline]
+ pub fn balance(&self, id: AssetId) -> AssetValue {
+ self.map.get(&id).copied().unwrap_or_default()
+ }
+
+ /// Returns `true` if `self` contains at least `value` amount of the asset with the given `id`.
+ #[inline]
+ pub fn contains(&self, id: AssetId, value: AssetValue) -> bool {
+ self.balance(id) >= value
+ }
+
+ /// Deposit `asset` into `self`.
+ #[inline]
+ pub fn deposit(&mut self, asset: Asset) {
+ *self.map.entry(asset.id).or_default() += asset.value;
+ }
+
+ /// Withdraw `asset` from `self`, returning `false` if it would overdraw the balance.
+ #[inline]
+ pub fn withdraw(&mut self, asset: Asset) -> bool {
+ if asset.value == 0 {
+ true
+ } else {
+ self.map
+ .get_mut(&asset.id)
+ .map(move |balance| {
+ if let Some(result) = balance.checked_sub(asset.value) {
+ *balance = result;
+ true
+ } else {
+ false
+ }
+ })
+ .unwrap_or(false)
+ }
+ }
+}
+
+/// Action Types
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[serde(deny_unknown_fields, tag = "type")]
+pub enum Action {
+ /// No Action
+ None,
+
+ /// Public Deposit Action
+ PublicDeposit,
+
+ /// Public Withdraw Action
+ PublicWithdraw,
+
+ /// Mint Action
+ Mint,
+
+ /// Private Transfer Action
+ PrivateTransfer,
+
+ /// Reclaim Action
+ Reclaim,
+}
+
+/// Action Distribution Probability Mass Function
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub struct ActionDistributionPMF {
+ /// No Action Weight
+ pub none: T,
+
+ /// Public Deposit Action Weight
+ pub public_deposit: T,
+
+ /// Public Withdraw Action Weight
+ pub public_withdraw: T,
+
+ /// Mint Action Weight
+ pub mint: T,
+
+ /// Private Transfer Action Weight
+ pub private_transfer: T,
+
+ /// Reclaim Action Weight
+ pub reclaim: T,
+}
+
+impl Default for ActionDistributionPMF {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ none: 1.0,
+ public_deposit: 1.0,
+ public_withdraw: 1.0,
+ mint: 1.0,
+ private_transfer: 1.0,
+ reclaim: 1.0,
+ }
+ }
+}
+
+impl From for ActionDistributionPMF {
+ #[inline]
+ fn from(actions: ActionDistribution) -> Self {
+ ActionDistributionPMF {
+ none: actions.distribution.pmf(0),
+ public_deposit: actions.distribution.pmf(1),
+ public_withdraw: actions.distribution.pmf(2),
+ mint: actions.distribution.pmf(3),
+ private_transfer: actions.distribution.pmf(4),
+ reclaim: actions.distribution.pmf(5),
+ }
+ }
+}
+
+/// Action Distribution
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+#[serde(
+ deny_unknown_fields,
+ into = "ActionDistributionPMF",
+ try_from = "ActionDistributionPMF"
+)]
+pub struct ActionDistribution {
+ /// Distribution over Actions
+ distribution: Categorical,
+}
+
+impl Default for ActionDistribution {
+ #[inline]
+ fn default() -> Self {
+ Self::try_from(ActionDistributionPMF::default()).unwrap()
+ }
+}
+
+impl TryFrom for ActionDistribution {
+ type Error = StatsError;
+
+ #[inline]
+ fn try_from(pmf: ActionDistributionPMF) -> Result {
+ Ok(Self {
+ distribution: Categorical::new(&[
+ pmf.none,
+ pmf.public_deposit,
+ pmf.public_withdraw,
+ pmf.mint,
+ pmf.private_transfer,
+ pmf.reclaim,
+ ])?,
+ })
+ }
+}
+
+impl Distribution for ActionDistribution {
+ #[inline]
+ fn sample(&self, rng: &mut R) -> Action
+ where
+ R: RngCore + ?Sized,
+ {
+ match self.distribution.sample(rng) as usize {
+ 0 => Action::None,
+ 1 => Action::PublicDeposit,
+ 2 => Action::PublicWithdraw,
+ 3 => Action::Mint,
+ 4 => Action::PrivateTransfer,
+ 5 => Action::Reclaim,
+ _ => unreachable!(),
+ }
+ }
+}
+
+/// User Account
+#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct Account {
+ /// Public Balances
+ pub public: BalanceState,
+
+ /// Secret Balances
+ pub secret: BalanceState,
+
+ /// Action Distribution
+ pub actions: ActionDistribution,
+}
+
+impl Account {
+ /// Samples a new account sampled using `config` settings and `rng`.
+ #[inline]
+ pub fn sample(config: &Config, rng: &mut R) -> Self
+ where
+ R: RngCore + ?Sized,
+ {
+ let mut public = BalanceState::default();
+ // TODO: Use a better distribution to sample a starting balance.
+ for _ in 0usize..rng.gen_range(0..50) {
+ public.deposit(config.sample_asset(rng));
+ }
+ Self {
+ public,
+ secret: Default::default(),
+ actions: ActionDistribution::try_from(ActionDistributionPMF {
+ none: rng.gen_range(config.action_sampling_ranges.none.clone()),
+ public_deposit: rng.gen_range(config.action_sampling_ranges.public_deposit.clone()),
+ public_withdraw: rng
+ .gen_range(config.action_sampling_ranges.public_withdraw.clone()),
+ mint: rng.gen_range(config.action_sampling_ranges.mint.clone()),
+ private_transfer: rng
+ .gen_range(config.action_sampling_ranges.private_transfer.clone()),
+ reclaim: rng.gen_range(config.action_sampling_ranges.reclaim.clone()),
+ })
+ .unwrap(),
+ }
+ }
+}
+
+/// Simulation Update
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+#[serde(deny_unknown_fields, tag = "type")]
+pub enum Update {
+ /// Create Account
+ CreateAccount { account: Account },
+
+ /// Deposit Public Balance
+ PublicDeposit { account_index: usize, asset: Asset },
+
+ /// Withdraw Public Balance
+ PublicWithdraw { account_index: usize, asset: Asset },
+
+ /// Mint Asset
+ Mint { source_index: usize, asset: Asset },
+
+ /// Private Transfer Asset
+ PrivateTransfer {
+ sender_index: usize,
+ receiver_index: usize,
+ asset: Asset,
+ },
+
+ /// Reclaim Asset
+ Reclaim { sender_index: usize, asset: Asset },
+}
+
+/// Simulation Configuration
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct Config {
+ /// Number of starting accounts
+ pub starting_account_count: u64,
+
+ /// Number of simulation steps before creating new accounts
+ pub new_account_sampling_cycle: u64,
+
+ /// [`Poisson`] growth rate of the number of accounts
+ ///
+ /// This configuration setting is not used if `new_account_sampling_cycle == 0`.
+ pub account_count_growth_rate: f64,
+
+ /// Maximum number of accounts
+ ///
+ /// If this value is less than `starting_account_count`, the maximum count is ignored.
+ pub maximum_account_count: u64,
+
+ /// Which assets are allowed to be sampled and the maximum per sample
+ pub allowed_asset_sampling: IndexMap,
+
+ /// Action Sampling Ranges
+ ///
+ /// This is a distribution over an [`ActionDistribution`] which is used to sample an
+ /// [`ActionDistribution`] for a particular account.
+ pub action_sampling_ranges: ActionDistributionPMF>,
+
+ /// Maximum number of updates allowed per step
+ ///
+ /// If this value is `0`, it has no effect.
+ pub maximum_updates_per_step: u32,
+
+ /// Maximum number of total updates
+ ///
+ /// If this value is `0`, it has no effect.
+ pub maximum_total_updates: u32,
+}
+
+impl Config {
+ /// Returns `true` if `self` has an active account count maximum.
+ #[inline]
+ fn has_maximum_account_count(&self) -> bool {
+ self.maximum_account_count >= self.starting_account_count
+ }
+
+ /// Returns `true` if `accounts` is equal to the account count maximum, if it is active.
+ #[inline]
+ fn maximum_account_count_has_been_reached(&self, accounts: u64) -> bool {
+ self.has_maximum_account_count() && self.maximum_account_count == accounts
+ }
+
+ /// Returns `true` if new accounts should be created for the current `step_counter` and an
+ /// account list with `accounts`-many elements.
+ #[inline]
+ fn should_create_new_accounts(&self, step_counter: u64, accounts: u64) -> bool {
+ self.maximum_account_count != self.starting_account_count
+ && !self.maximum_account_count_has_been_reached(accounts)
+ && self.new_account_sampling_cycle != 0
+ && step_counter % self.new_account_sampling_cycle == 0
+ }
+
+ /// Samples an allowed asset using `rng`.
+ #[inline]
+ fn sample_asset(&self, rng: &mut R) -> Asset
+ where
+ R: RngCore + ?Sized,
+ {
+ let id = self.sample_asset_id(rng);
+ Asset::new(id, self.sample_asset_value(id, rng))
+ }
+
+ /// Samples an allowed asset id using `rng`.
+ #[inline]
+ fn sample_asset_id(&self, rng: &mut R) -> AssetId
+ where
+ R: RngCore + ?Sized,
+ {
+ let mut ids = self.allowed_asset_sampling.keys();
+ *ids.nth(rng.gen_range(0..ids.len())).unwrap()
+ }
+
+ /// Samples an allowed asset value of the given `id` using `rng`.
+ #[inline]
+ fn sample_asset_value(&self, id: AssetId, rng: &mut R) -> AssetValue
+ where
+ R: RngCore + ?Sized,
+ {
+ rng.gen_range(0..=self.allowed_asset_sampling[&id])
+ }
+
+ /// Samples an allowed withdraw from `balances`.
+ #[inline]
+ fn sample_withdraw(&self, balances: &BalanceState, rng: &mut R) -> Asset
+ where
+ R: RngCore + ?Sized,
+ {
+ let mut ids = self.allowed_asset_sampling.keys().collect::>();
+ ids.shuffle(rng);
+ for id in &ids {
+ let balance = balances.balance(**id);
+ if balance != 0 {
+ return Asset::new(
+ **id,
+ rng.gen_range(1..=min(balance, self.allowed_asset_sampling[*id])),
+ );
+ }
+ }
+ Asset::new(*ids[ids.len() - 1], 0)
+ }
+}
+
+/// Simulator
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct Simulator {
+ /// Configuration
+ config: Config,
+
+ /// Step Counter
+ step_counter: u64,
+
+ /// Accounts
+ accounts: Vec,
+}
+
+impl Simulator {
+ /// Builds a new [`Simulator`] from the given `config`, sampling from `rng`.
+ #[inline]
+ pub fn new(config: Config, rng: &mut R) -> Self
+ where
+ R: RngCore + ?Sized,
+ {
+ Self {
+ accounts: (0..config.starting_account_count)
+ .map(|_| Account::sample(&config, rng))
+ .collect(),
+ step_counter: Default::default(),
+ config,
+ }
+ }
+
+ /// Computes one step of the simulation using `rng`.
+ #[inline]
+ pub fn step(&self, rng: &mut R) -> Vec
+ where
+ R: RngCore + ?Sized,
+ {
+ let mut updates = Vec::new();
+ for (i, account) in self.accounts.iter().enumerate() {
+ match account.actions.sample(rng) {
+ Action::None => {}
+ Action::PublicDeposit => {
+ updates.push(Update::PublicDeposit {
+ account_index: i,
+ asset: self.config.sample_asset(rng),
+ });
+ }
+ Action::PublicWithdraw => {
+ updates.push(Update::PublicWithdraw {
+ account_index: i,
+ asset: self.config.sample_withdraw(&account.public, rng),
+ });
+ }
+ Action::Mint => {
+ updates.push(Update::Mint {
+ source_index: i,
+ asset: self.config.sample_withdraw(&account.public, rng),
+ });
+ }
+ Action::PrivateTransfer => {
+ let asset = self.config.sample_withdraw(&account.secret, rng);
+ if asset.value > 0 {
+ updates.push(Update::PrivateTransfer {
+ sender_index: i,
+ receiver_index: rng.gen_range(0..self.accounts.len()),
+ asset
+ });
+ };
+ }
+ Action::Reclaim => {
+ updates.push(Update::Reclaim {
+ sender_index: i,
+ asset: self.config.sample_withdraw(&account.secret, rng),
+ });
+ }
+ }
+ }
+ let accounts_len = self.accounts.len() as u64;
+ if self
+ .config
+ .should_create_new_accounts(self.step_counter, accounts_len)
+ {
+ let mut new_accounts = Poisson::new(self.config.account_count_growth_rate)
+ .unwrap()
+ .sample(rng) as u64;
+ if self.config.has_maximum_account_count() {
+ new_accounts =
+ new_accounts.clamp(0, self.config.maximum_account_count - accounts_len);
+ }
+ for _ in 0..new_accounts {
+ updates.push(Update::CreateAccount {
+ account: Account::sample(&self.config, rng),
+ });
+ }
+ }
+ if self.config.maximum_updates_per_step > 0 {
+ choose_multiple(
+ &mut updates,
+ self.config.maximum_updates_per_step as usize,
+ rng,
+ );
+ }
+ updates
+ }
+
+ /// Applies `update` to the internal state of the simulator, returning the update back
+ /// if an error occured.
+ #[inline]
+ pub fn apply(&mut self, update: Update) -> Result<(), Update> {
+ match &update {
+ Update::CreateAccount { account } => {
+ self.accounts.push(account.clone());
+ return Ok(());
+ }
+ Update::PublicDeposit {
+ account_index,
+ asset,
+ } => {
+ if let Some(balances) = self.accounts.get_mut(*account_index) {
+ balances.public.deposit(*asset);
+ return Ok(());
+ }
+ }
+ Update::PublicWithdraw {
+ account_index,
+ asset,
+ } => {
+ if let Some(balances) = self.accounts.get_mut(*account_index) {
+ if balances.public.withdraw(*asset) {
+ return Ok(());
+ }
+ }
+ }
+ Update::Mint {
+ source_index,
+ asset,
+ } => {
+ if let Some(balances) = self.accounts.get_mut(*source_index) {
+ if balances.public.withdraw(*asset) {
+ balances.secret.deposit(*asset);
+ return Ok(());
+ }
+ }
+ }
+ Update::PrivateTransfer {
+ sender_index,
+ receiver_index,
+ asset,
+ } => {
+ if let Some(sender) = self.accounts.get_mut(*sender_index) {
+ if sender.secret.withdraw(*asset) {
+ if let Some(receiver) = self.accounts.get_mut(*receiver_index) {
+ receiver.secret.deposit(*asset);
+ return Ok(());
+ }
+ }
+ }
+ }
+ Update::Reclaim {
+ sender_index,
+ asset,
+ } => {
+ if let Some(balances) = self.accounts.get_mut(*sender_index) {
+ if balances.secret.withdraw(*asset) {
+ balances.public.deposit(*asset);
+ return Ok(());
+ }
+ }
+ }
+ }
+ Err(update)
+ }
+
+ /// Runs `self` for the given number of `steps`.
+ #[inline]
+ pub fn run(&mut self, steps: usize, rng: &mut R) -> Simulation
+ where
+ R: RngCore + ?Sized,
+ {
+ let initial_accounts = self.accounts.clone();
+ let mut updates = Vec::new();
+ for _ in 0..steps {
+ let mut next_updates = self.step(rng);
+ let update_limit = self.config.maximum_total_updates as usize;
+ if update_limit > 0 {
+ match update_limit - updates.len() {
+ 0 => break,
+ diff => next_updates.truncate(diff),
+ }
+ }
+ for update in &next_updates {
+ if let Err(update) = self.apply(update.clone()) {
+ panic!(
+ "ERROR: {}\n\n Panicked on the following state:\nSimulation: {:?}\nUpdate: {:?}",
+ "This is an internal simulation error. Please file a bug.",
+ self,
+ update
+ );
+ }
+ }
+ updates.append(&mut next_updates);
+ self.step_counter += 1;
+ }
+ Simulation {
+ config: self.config.clone(),
+ initial_accounts,
+ final_accounts: self.accounts.clone(),
+ updates,
+ }
+ }
+}
+
+/// Simulation Final State
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct Simulation {
+ /// Configuration
+ pub config: Config,
+
+ /// Initial Account State
+ pub initial_accounts: Vec,
+
+ /// Final Account State
+ pub final_accounts: Vec,
+
+ /// Updates
+ pub updates: Vec,
+}
+
+/// Runs a [`Simulator`] in a CLI.
+pub fn main() {
+ let matches = App::new("Manta Simulation")
+ .arg(
+ Arg::with_name("steps")
+ .help("The number of steps to run the simulation.")
+ .required(true),
+ )
+ .arg(
+ Arg::with_name("config")
+ .short("c")
+ .long("config")
+ .value_name("FILE")
+ .help("Sets a custom config file. By default, `default-config.json` is used.")
+ .takes_value(true),
+ )
+ .arg(
+ Arg::with_name("output")
+ .short("o")
+ .long("output")
+ .value_name("FILE")
+ .help("Sets a custom output file")
+ .takes_value(true),
+ )
+ .get_matches();
+
+ let config_path = matches.value_of("config").unwrap_or("default-config.json");
+ let config = match fs::read_to_string(&config_path) {
+ Ok(config) => match serde_json::from_str(&config) {
+ Ok(config) => config,
+ err => panic!("ERROR: {:?}", err),
+ },
+ _ => panic!("ERROR: Invalid configuration path: {:?}", config_path),
+ };
+
+ let steps = matches
+ .value_of("steps")
+ .unwrap()
+ .parse::()
+ .expect("ERROR: Invalid number of simulation steps.");
+
+ let mut rng = thread_rng();
+
+ print!("INFO: Running simulation ... ");
+ flush_stdout();
+ let simulation = Simulator::new(config, &mut rng).run(steps, &mut rng);
+ println!("DONE.");
+
+ if let Some(output_path) = matches.value_of("output") {
+ print!("INFO: Writing simulation to file ... ");
+ flush_stdout();
+ match serde_json::to_writer(
+ fs::File::create(output_path).expect("ERROR: Unable to create output file."),
+ &simulation,
+ ) {
+ Ok(()) => println!("DONE. Output written to `{}`.", output_path),
+ err => panic!("ERROR: {:?}", err),
+ }
+ } else if let Err(err) = serde_json::to_writer_pretty(std::io::stdout(), &simulation) {
+ panic!("ERROR: {:?}", err);
+ }
+}
diff --git a/js/e2e/test/constants.ts b/js/e2e/test/constants.ts
new file mode 100644
index 00000000..89aa88ac
--- /dev/null
+++ b/js/e2e/test/constants.ts
@@ -0,0 +1,23 @@
+export const DEFAULT_SIGNER_DAEMON_URL = 'http://127.0.0.1:29987';
+export const ALICE_SIGNER_DAEMON_URL = 'http://127.0.0.1:29987';
+export const BOB_SIGNER_DAEMON_URL = 'http://127.0.0.1:29988';
+export const CHARLIE_SIGNER_DAEMON_URL = 'http://127.0.0.1:29989';
+export const DAVE_SIGNER_DAEMON_URL = 'http://127.0.0.1:29990';
+
+// These dev accounts are created automatically on Dolphin testnet
+export const ALICE_POLKADOT_JS_SIGNER = '//Alice';
+export const BOB_POLKADOT_JS_SIGNER = '//Bob';
+export const CHARLIE_POLKADOT_JS_SIGNER = '//Charlie';
+export const DAVE_POLKADOT_JS_SIGNER = '//Dave';
+
+// These dev accounts are created automatically on Dolphin testnet
+export const ALICE_PUBLIC_ADDRESS =
+ '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
+export const BOB_PUBLIC_ADDRESS =
+ '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty';
+export const CHARLIE_PUBLIC_ADDRESS =
+ '5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y';
+export const DAVE_PUBLIC_ADDRESS =
+ '5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy';
+
+export const LOCAL_NODE_URL = 'ws://127.0.0.1:9944';
diff --git a/js/e2e/test/simlatedUser.ts b/js/e2e/test/simlatedUser.ts
new file mode 100644
index 00000000..86462b3a
--- /dev/null
+++ b/js/e2e/test/simlatedUser.ts
@@ -0,0 +1,68 @@
+import {
+ ALICE_SIGNER_DAEMON_URL,
+ BOB_SIGNER_DAEMON_URL,
+ CHARLIE_SIGNER_DAEMON_URL,
+ DAVE_SIGNER_DAEMON_URL,
+ ALICE_POLKADOT_JS_SIGNER,
+ BOB_POLKADOT_JS_SIGNER,
+ CHARLIE_POLKADOT_JS_SIGNER,
+ DAVE_POLKADOT_JS_SIGNER,
+ ALICE_PUBLIC_ADDRESS,
+ BOB_PUBLIC_ADDRESS,
+ CHARLIE_PUBLIC_ADDRESS,
+ DAVE_PUBLIC_ADDRESS
+} from './constants';
+import { NodeJsSignerInterfaceConfig } from 'signer-interface';
+
+export type SimulatedUser = {
+ name: string;
+ publicAddress: string;
+ polkadotJsSigner: string;
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+// Alice is the "bank" because she stars with all of the money on Dolphin;
+// End-to-end tests should not include Alice except during setup
+export const Alice: SimulatedUser = {
+ name: 'Alice',
+ publicAddress: ALICE_PUBLIC_ADDRESS,
+ polkadotJsSigner: ALICE_POLKADOT_JS_SIGNER,
+ signerInterface: new NodeJsSignerInterfaceConfig(
+ 1,
+ ALICE_SIGNER_DAEMON_URL,
+ 'Alice'
+ )
+};
+
+export const Bob: SimulatedUser = {
+ name: 'Bob',
+ publicAddress: BOB_PUBLIC_ADDRESS,
+ polkadotJsSigner: BOB_POLKADOT_JS_SIGNER,
+ signerInterface: new NodeJsSignerInterfaceConfig(
+ 1,
+ BOB_SIGNER_DAEMON_URL,
+ 'Bob'
+ )
+};
+
+export const Charlie: SimulatedUser = {
+ name: 'Charlie',
+ publicAddress: CHARLIE_PUBLIC_ADDRESS,
+ polkadotJsSigner: CHARLIE_POLKADOT_JS_SIGNER,
+ signerInterface: new NodeJsSignerInterfaceConfig(
+ 1,
+ CHARLIE_SIGNER_DAEMON_URL,
+ 'Charlie'
+ )
+};
+
+export const Dave: SimulatedUser = {
+ name: 'Dave',
+ publicAddress: DAVE_PUBLIC_ADDRESS,
+ polkadotJsSigner: DAVE_POLKADOT_JS_SIGNER,
+ signerInterface: new NodeJsSignerInterfaceConfig(
+ 1,
+ DAVE_SIGNER_DAEMON_URL,
+ 'Dave'
+ )
+};
diff --git a/js/e2e/test/test.ts b/js/e2e/test/test.ts
new file mode 100644
index 00000000..57fcd848
--- /dev/null
+++ b/js/e2e/test/test.ts
@@ -0,0 +1,319 @@
+// @ts-ignore FIXME
+import {
+ transferAssetWorkflow,
+ mintAssetWorkflow,
+ privateTransferAssetWorkflow,
+ reclaimAssetWorkflow,
+ recoverAccountWorkflow,
+ deriveAddressWorkflow,
+ resetStorageWorkflow
+} from 'workflows';
+import { waitReady } from '@polkadot/wasm-crypto';
+import { ApiPromise } from '@polkadot/api';
+import { initDolphinApi } from '../test/utils';
+import { assert, expect } from 'chai';
+import { readFileSync } from 'fs';
+import { Alice, Bob, Charlie, Dave, SimulatedUser } from './simlatedUser';
+import { LOCAL_NODE_URL } from './constants';
+
+// TODO: To start simulation run the following:
+// ```
+// cd simulation
+// cargo run --release --output=out.json
+// ```
+// where `` is the number of simulation steps to run.
+
+function loadSimulation(path) {
+ var simulation = null;
+ try {
+ const data = readFileSync(path, 'utf8');
+ simulation = JSON.parse(data);
+ console.log('[INFO] Simulation Configuration:', simulation.config);
+ } catch (err) {
+ console.log('Error loading simulation:', err);
+ }
+ return simulation;
+}
+
+async function getFinalPrivateBalances(api, user) {
+ const assets = await recoverAccount(api, user);
+ const balancesByAssetId = {};
+ for (let i = 0; i <= 4; i++) {
+ balancesByAssetId[i] = 0;
+ }
+ assets.forEach((asset) => {
+ const prevBalance = balancesByAssetId[asset.assetId];
+ balancesByAssetId[asset.assetId] =
+ prevBalance + asset.valueAtomicUnits.toNumber();
+ });
+ return balancesByAssetId;
+}
+
+async function getFinalPublicBalance(api, user, assetId) {
+ const balance = await api.query.mantaPay.balances(
+ user.publicAddress,
+ assetId
+ );
+ return balance.toNumber();
+}
+
+async function publicDeposit(
+ api,
+ recipient: SimulatedUser,
+ assetId: number,
+ valueAtomicUnits: number
+) {
+ return await transfer(
+ api,
+ Alice,
+ assetId,
+ valueAtomicUnits,
+ recipient.publicAddress
+ );
+}
+
+async function publicWithdraw(
+ api,
+ user: SimulatedUser,
+ assetId: string,
+ valueAtomicUnits: number
+) {
+ return await transfer(
+ api,
+ user,
+ assetId,
+ valueAtomicUnits,
+ Alice.publicAddress
+ );
+}
+
+async function mint(
+ api,
+ user: SimulatedUser,
+ assetId: number,
+ valueAtomicUnits: number
+) {
+ return await mintAssetWorkflow(
+ {
+ assetId: assetId,
+ valueAtomicUnits: valueAtomicUnits,
+ polkadotJsSigner: user.polkadotJsSigner,
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+async function transfer(api, user, assetId, valueAtomicUnits, receiver) {
+ return await transferAssetWorkflow(
+ {
+ assetId: assetId,
+ valueAtomicUnits: valueAtomicUnits,
+ polkadotJsSigner: user.polkadotJsSigner,
+ receiver: receiver
+ },
+ api
+ );
+}
+
+async function privateTransfer(
+ api,
+ user: SimulatedUser,
+ assetId: number,
+ valueAtomicUnits: number,
+ receiver: string
+) {
+ return await privateTransferAssetWorkflow(
+ {
+ assetId: assetId,
+ valueAtomicUnits: valueAtomicUnits,
+ receiver: receiver,
+ polkadotJsSigner: user.polkadotJsSigner,
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+async function reclaim(
+ api,
+ user: SimulatedUser,
+ assetId: number,
+ valueAtomicUnits: number
+) {
+ return await reclaimAssetWorkflow(
+ {
+ assetId: assetId,
+ valueAtomicUnits: valueAtomicUnits,
+ polkadotJsSigner: user.polkadotJsSigner,
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+async function driveAddress(api, user: SimulatedUser) {
+ return await deriveAddressWorkflow(
+ {
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+async function recoverAccount(api, user: SimulatedUser) {
+ return await recoverAccountWorkflow(
+ {
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+function resetStorage(api, user: SimulatedUser) {
+ resetStorageWorkflow(
+ {
+ signerInterface: user.signerInterface
+ },
+ api
+ );
+}
+
+describe('Manta e2e test suite', async () => {
+ let api: ApiPromise;
+
+ before(async () => {
+ await waitReady();
+ api = await initDolphinApi(LOCAL_NODE_URL);
+ });
+
+ describe('simulation', () => {
+ it('runs', async () => {
+ const simulation = loadSimulation('./simulation/out.json');
+ assert.notEqual(simulation, null, 'Unable to load simulation file.');
+ assert.equal(simulation.config.starting_account_count, 3);
+ assert.equal(simulation.config.new_account_sampling_cycle, 0);
+
+ // No Alice because she has all the money to begin with on Dolphin
+ const users = [Bob, Charlie, Dave];
+
+ for (let i = 0; i < simulation.initial_accounts.length; i++) {
+ const user = users[i];
+ console.log('\n[INFO] Setting up account for:', user.name, '\n');
+ const balances: Record =
+ simulation.initial_accounts[i].public;
+ for (const [assetIdString, valueAtomicUnits] of Object.entries(
+ balances
+ )) {
+ const assetId = parseInt(assetIdString);
+ if (valueAtomicUnits > 0) {
+ const status = await publicDeposit(
+ api,
+ user,
+ assetId,
+ valueAtomicUnits
+ );
+ expect(status.isFinalized()).equal(true);
+ }
+ }
+ }
+
+ for (let i = 0; i < simulation.updates.length; i++) {
+ const next = simulation.updates[i];
+ console.log('\n[INFO] Running Update:', next, '\n');
+ if (next.type === 'PublicDeposit') {
+ const publicDepositStatus = await publicDeposit(
+ api,
+ users[next.account_index],
+ next.asset.id,
+ next.asset.value
+ );
+ if (next.asset.value > 0) {
+ expect(publicDepositStatus.isFinalized()).equal(true);
+ } else {
+ expect(publicDepositStatus.isFinalized()).equal(false);
+ }
+ } else if (next.type === 'PublicWithdraw') {
+ const publicWithdrawStatus = await publicWithdraw(
+ api,
+ users[next.account_index],
+ next.asset.id,
+ next.asset.value
+ );
+ expect(publicWithdrawStatus.isFinalized()).equal(true);
+ } else if (next.type === 'Mint') {
+ const mintStatus = await mint(
+ api,
+ users[next.source_index],
+ next.asset.id,
+ next.asset.value
+ );
+ expect(mintStatus.isFinalized()).equal(true);
+ } else if (next.type === 'PrivateTransfer') {
+ const receivingAddress = await driveAddress(
+ api,
+ users[next.receiver_index]
+ );
+ const privateTransferStatus = await privateTransfer(
+ api,
+ users[next.sender_index],
+ next.asset.id,
+ next.asset.value,
+ receivingAddress
+ );
+ expect(privateTransferStatus.isFinalized()).equal(true);
+ } else if (next.type === 'Reclaim') {
+ const reclaimStatus = await reclaim(
+ api,
+ users[next.sender_index],
+ next.asset.id,
+ next.asset.value
+ );
+ expect(reclaimStatus.isFinalized()).equal(true);
+ } else {
+ throw Error('Unknown update');
+ }
+ }
+
+ for (let i = 0; i < simulation.final_accounts.length; i++) {
+ const user = users[i];
+ assert.notEqual(user, undefined);
+ console.log(
+ '\n[INFO] Checking final simulation state for:',
+ user.name,
+ '\n'
+ );
+ const publicBalancesExpected: Record =
+ simulation.final_accounts[i].public;
+ for (const [assetId, value] of Object.entries(publicBalancesExpected)) {
+ const expected = value;
+ const actual = await getFinalPublicBalance(api, users[i], assetId);
+ console.log(`Expecting public balance of ${expected} for user=${user.name} and assetId=${assetId}`);
+ assert.equal(expected, actual);
+ }
+ const privateBalancesExpected: Record =
+ simulation.final_accounts[i].secret;
+ const privateBalancesActual = await getFinalPrivateBalances(
+ api,
+ users[i]
+ );
+ for (const [assetId, value] of Object.entries(
+ privateBalancesExpected
+ )) {
+ const expected = value;
+ const actual = privateBalancesActual[assetId];
+ console.log(`Expecting private balance of ${expected} for user=${user.name} and assetId=${assetId}`);
+ assert.equal(expected, actual);
+ }
+ }
+ }).timeout(100000000000);
+ });
+
+ after(() => {
+ resetStorage(api, Alice);
+ resetStorage(api, Bob);
+ resetStorage(api, Charlie);
+ resetStorage(api, Dave);
+ api.disconnect();
+ });
+});
diff --git a/js/e2e/test/utils.ts b/js/e2e/test/utils.ts
new file mode 100644
index 00000000..d567c8c4
--- /dev/null
+++ b/js/e2e/test/utils.ts
@@ -0,0 +1,9 @@
+import { ApiPromise, WsProvider } from '@polkadot/api'
+import { waitReady } from '@polkadot/wasm-crypto'
+import { DolphinTypes } from 'dolphin-api'
+
+export async function initDolphinApi (url: string): Promise {
+ await waitReady()
+ const wsProvider = new WsProvider(url)
+ return ApiPromise.create({ provider: wsProvider, types: DolphinTypes })
+}
diff --git a/js/e2e/tsconfig.json b/js/e2e/tsconfig.json
new file mode 100644
index 00000000..c7c507bd
--- /dev/null
+++ b/js/e2e/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "skipLibCheck": true,
+ },
+ "include": [
+ "src"
+ ],
+ "exclude": [
+ "node_modules/",
+ "../node_modules/",
+ ]
+}
\ No newline at end of file
diff --git a/js/package.json b/js/package.json
new file mode 100644
index 00000000..e9ac427d
--- /dev/null
+++ b/js/package.json
@@ -0,0 +1,36 @@
+{
+ "repository": "git@github.com:Manta-Network/manta-signer",
+ "license": "GPL-3.0-only",
+ "workspaces": [
+ "dolphin-api",
+ "e2e",
+ "workflows",
+ "coin-selection",
+ "signer-interface"
+ ],
+ "name": "manta-js",
+ "private": true,
+ "scripts": {
+ "build": "yarn workspace coin-selection build; yarn workspace signer-interface build; yarn workspace dolphin-api build; yarn workspace workflows build;",
+ "lint:check": "eslint . --ext .ts,.tsx",
+ "lint": "npm run lint:check -- --fix",
+ "test": "yarn workspace e2e test"
+ },
+ "dependencies": {
+ "@polkadot/api": "^6.5.2",
+ "@polkadot/types": "^6.5.2",
+ "@types/node": "^16.7.10",
+ "typescript": "^4.4.2"
+ },
+ "devDependencies": {
+ "@typescript-eslint/eslint-plugin": "^5.3.1",
+ "@typescript-eslint/parser": "^5.3.1",
+ "eslint": "^7.32.0",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-config-standard": "^16.0.3",
+ "eslint-plugin-import": "^2.25.3",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^5.1.1",
+ "ts-node": "^10.2.1"
+ }
+}
\ No newline at end of file
diff --git a/js/signer-interface/README.md b/js/signer-interface/README.md
new file mode 100644
index 00000000..428dbe4a
--- /dev/null
+++ b/js/signer-interface/README.md
@@ -0,0 +1,68 @@
+# Manta Signer Interface
+
+An interface to simplify interacting with Manta Signer
+
+## Installation
+
+`yarn add signer-interface`
+
+## Usage
+
+### Initialization
+
+```js
+// get an instance of polkadot.js api
+import { ApiPromise, WsProvider } from '@polkadot/api';
+const api = new ApiPromise({ provider, types, rpc: jsonrpc });
+await api.isReady;
+
+// Create a config deppending on your environment
+import {
+ BrowserSignerInterfaceConfig,
+ NodeJsSignerInterfaceConfig
+} from 'signer-interface';
+
+const config = NodeJsSignerInterfaceConfig(
+ 1, // testnet
+ 'http://localhost:29986', // default Manta Signer url
+ 'User1'
+);
+const signerInterface = new SignerInterface(api, config);
+```
+
+### Recovering (or refreshing) a wallet
+
+```js
+// returns an array of ClientAsset
+const myRecoveredAssets = signerInterface.recoverAccount();
+```
+
+### Doing a private transfer (or reclaim, similarly)
+
+```js
+// The transfer you want to do
+const assetId = 1;
+const targetValue = 100;
+const receivingAddress = 'AAAAAAABBBBBBCCCCCCCDDDDDD...';
+
+// install 'manta-coin-selection' with yarn
+import { selectCoins, CoinSelection } from 'manta-coin-selection';
+
+// returns a `CoinSelection`, which contains the selected coins and associated metadata
+const coinSelection = selectCoins(targetValue, myRecoveredAssets, assetId);
+
+const transaction = await signerInterface.buildExternalPrivateTransferTxs(
+ receivingAddress,
+ coinSelection
+);
+
+// Submit the transaction using polkadot.js
+
+// wait ...
+
+// If transaction fails, run:
+signerInterface.cleanupTxFailure();
+
+// If transaction succeeds, run:
+signerInterface.cleanupTxSuccess();
+```
diff --git a/js/signer-interface/package.json b/js/signer-interface/package.json
new file mode 100644
index 00000000..7a7afccf
--- /dev/null
+++ b/js/signer-interface/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "signer-interface",
+ "version": "0.2.0",
+ "main": "dist/index.js",
+ "description": "JS interface for interacting with Manta Signer",
+ "types": "dist/index.d.ts",
+ "license": "GPL-3.0-only",
+ "scripts": {
+ "build": "rm -rf signer-interface/dist ; tsc"
+ },
+ "dependencies": {
+ "axios": "^0.23.0",
+ "bn.js": "^5.2.0",
+ "store": "^2.0.12"
+ },
+ "devDependencies": {
+ "typescript": "^4.4.4"
+ }
+}
\ No newline at end of file
diff --git a/js/signer-interface/src/classes/clientAsset.ts b/js/signer-interface/src/classes/clientAsset.ts
new file mode 100644
index 00000000..0d1545ff
--- /dev/null
+++ b/js/signer-interface/src/classes/clientAsset.ts
@@ -0,0 +1,72 @@
+// @ts-nocheck
+import BN from 'bn.js';
+
+export class ClientAsset {
+ assetId: number;
+ valueAtomicUnits: BN;
+ keypath: string;
+ utxo: Uint8Array;
+ voidNumber: Uint8Array;
+ shardIndex: number;
+ shard: Array;
+
+ constructor(
+ assetId,
+ valueAtomicUnits,
+ keypath = null,
+ utxo = null,
+ voidNumber = null,
+ shardIndex = null
+ ) {
+ this.assetId = assetId;
+ this.valueAtomicUnits = valueAtomicUnits;
+ this.keypath = keypath;
+ this.utxo = utxo;
+ this.voidNumber = voidNumber;
+ this.shardIndex = shardIndex;
+ this.shard = null;
+ }
+
+ static fromSignerAsset(signerAsset) {
+ return new ClientAsset(
+ signerAsset.asset_id.toNumber(),
+ signerAsset.value,
+ signerAsset.keypath,
+ signerAsset.utxo,
+ signerAsset.void_number,
+ signerAsset.shard_index
+ );
+ }
+
+ static fromU8a(u8a, api) {
+ const signerAsset = api.createType('MantaSignerInputAsset', u8a);
+ return ClientAsset.fromSignerAsset(signerAsset);
+ }
+
+ static newExternalOutput(assetId, valueAtomicUnits) {
+ return new ClientAsset(assetId, valueAtomicUnits);
+ }
+
+ toSignerAsset(api) {
+ return api.createType('MantaSignerInputAsset', {
+ asset_id: this.assetId,
+ value: this.valueAtomicUnits,
+ utxo: this.utxo,
+ keypath: this.keypath,
+ void_number: this.voidNumber,
+ shard_index: this.shardIndex
+ });
+ }
+
+ toU8a(api) {
+ return this.toSignerAsset(api).toU8a();
+ }
+
+ setShard(shard) {
+ this.shard = shard;
+ }
+
+ equals(other) {
+ return this.utxo.join(',') === other.utxo.join(',');
+ }
+}
diff --git a/js/signer-interface/src/classes/simulatedLedgerState.ts b/js/signer-interface/src/classes/simulatedLedgerState.ts
new file mode 100644
index 00000000..b099af7f
--- /dev/null
+++ b/js/signer-interface/src/classes/simulatedLedgerState.ts
@@ -0,0 +1,30 @@
+// @ts-nocheck
+export class SimulatedLedgerState {
+ constructor(api) {
+ this.api = api;
+ this.offChainAssets = [];
+ }
+
+ addOffChainAsset(offChainAsset) {
+ this.offChainAssets.push(offChainAsset);
+ }
+
+ async getShard(asset) {
+ const shardOnChain = await this._getShardOnChain(asset.shardIndex);
+ return this._addOffChainAssetsToShard(shardOnChain, asset.shardIndex);
+ }
+
+ async _getShardOnChain(shardIndex) {
+ const storage = await this.api.query.mantaPay.ledgerShards.entries(
+ shardIndex
+ );
+ return storage.map((storageItem) => storageItem[1][0]);
+ }
+
+ _addOffChainAssetsToShard(shardOnChain, shardIndex) {
+ const shardOffChain = this.offChainAssets
+ .filter((offChainAsset) => offChainAsset.shardIndex === shardIndex)
+ .map((asset) => asset.utxo);
+ return [...shardOnChain, ...shardOffChain];
+ }
+}
diff --git a/js/signer-interface/src/config/browserSignerInterfaceConfig.ts b/js/signer-interface/src/config/browserSignerInterfaceConfig.ts
new file mode 100644
index 00000000..a07d00f8
--- /dev/null
+++ b/js/signer-interface/src/config/browserSignerInterfaceConfig.ts
@@ -0,0 +1,10 @@
+// @ts-nocheck
+import { SignerInterfaceConfig } from './signerInterfaceConfig';
+
+export class BrowserSignerInterfaceConfig extends SignerInterfaceConfig {
+ constructor(bip44CoinTypeId, signerUrl, baseStorageKey) {
+ super(bip44CoinTypeId, signerUrl, baseStorageKey);
+ this.isInBrowser = true;
+ this.baseStorageKey = baseStorageKey;
+ }
+}
diff --git a/js/signer-interface/src/config/nodeJsSignerInterfaceConfig.ts b/js/signer-interface/src/config/nodeJsSignerInterfaceConfig.ts
new file mode 100644
index 00000000..bc5e044a
--- /dev/null
+++ b/js/signer-interface/src/config/nodeJsSignerInterfaceConfig.ts
@@ -0,0 +1,10 @@
+// @ts-nocheck
+import { SignerInterfaceConfig } from './signerInterfaceConfig';
+
+export class NodeJsSignerInterfaceConfig extends SignerInterfaceConfig {
+ constructor(bip44CoinTypeId, signerUrl, baseStorageKey) {
+ super(bip44CoinTypeId, signerUrl, baseStorageKey);
+ this.isInBrowser = false;
+ this.baseStorageKey = baseStorageKey;
+ }
+}
diff --git a/js/signer-interface/src/config/signerInterfaceConfig.ts b/js/signer-interface/src/config/signerInterfaceConfig.ts
new file mode 100644
index 00000000..d018a34a
--- /dev/null
+++ b/js/signer-interface/src/config/signerInterfaceConfig.ts
@@ -0,0 +1,10 @@
+// @ts-nocheck
+export class SignerInterfaceConfig {
+ constructor(
+ bip44CoinTypeId,
+ signerUrl
+ ) {
+ this.bip44CoinTypeId = bip44CoinTypeId;
+ this.signerUrl = signerUrl;
+ }
+}
diff --git a/js/signer-interface/src/constants/bip44Constants.ts b/js/signer-interface/src/constants/bip44Constants.ts
new file mode 100644
index 00000000..dcba54ac
--- /dev/null
+++ b/js/signer-interface/src/constants/bip44Constants.ts
@@ -0,0 +1,7 @@
+export const BIP_44_PURPOSE_INDEX = 44;
+export const DEFAULT_ACCOUNT_ID = 0;
+export const EXTERNAL_CHAIN_ID = 0;
+export const INTERNAL_CHAIN_ID = 1;
+export const TESTNET_COIN_TYPE_ID = 1;
+export const MANTA_MAINNET_COIN_TYPE_ID = 611;
+export const CALAMARI_MAINNET_COIN_TYPE_ID = 612;
diff --git a/js/signer-interface/src/index.ts b/js/signer-interface/src/index.ts
new file mode 100644
index 00000000..65678490
--- /dev/null
+++ b/js/signer-interface/src/index.ts
@@ -0,0 +1,11 @@
+import { SignerInterface } from './interface/signerInterface';
+import { ClientAsset } from './classes/clientAsset';
+import { BrowserSignerInterfaceConfig } from './config/browserSignerInterfaceConfig';
+import { NodeJsSignerInterfaceConfig } from './config/nodeJsSignerInterfaceConfig';
+
+export {
+ SignerInterface,
+ ClientAsset,
+ BrowserSignerInterfaceConfig,
+ NodeJsSignerInterfaceConfig
+};
diff --git a/js/signer-interface/src/interface/blockchainNodeClient.ts b/js/signer-interface/src/interface/blockchainNodeClient.ts
new file mode 100644
index 00000000..68cbc705
--- /dev/null
+++ b/js/signer-interface/src/interface/blockchainNodeClient.ts
@@ -0,0 +1,39 @@
+// @ts-nocheck
+import { base64Encode } from '@polkadot/util-crypto';
+
+export class BlockchainNodeClient {
+ constructor(api) {
+ this.api = api;
+ }
+
+ // Returns all on-chain void numbers
+ async getAllVoidNumbers() {
+ const entries = await this.api.query.mantaPay.voidNumbers.entries();
+ const voidNumbers = entries
+ .map((storageItem) => storageItem[0].args)
+ .flat();
+ return voidNumbers;
+ }
+
+ // Returns all UTXOS and encrypted notes void numbers that we haven't yet
+ // attempted to recover, along with an updted set of UTXOs we have attempted
+ // to recover. Attempting to recover a UTXO-encrypted note pair with Manta Signer
+ // is computationally expensive, so we don't want to perform this operation redundantly
+ async getNewUTXOsAndEncryptedNotes(utxoSet) {
+ const newUTXOs = [];
+ const newEncryptedNotes = [];
+ const entries = await this.api.query.mantaPay.ledgerShards.entries();
+ const pairs = entries.map((entry) => entry[1]);
+
+ pairs.forEach(([utxo, encryptedNote]) => {
+ const utxoStr = base64Encode(utxo.slice(0, 8));
+ if (!utxoSet[utxoStr]) {
+ newUTXOs.push(utxo);
+ newEncryptedNotes.push(encryptedNote);
+ utxoSet[utxoStr] = true;
+ }
+ });
+
+ return { newUTXOs, newEncryptedNotes, utxoSet };
+ }
+}
diff --git a/js/signer-interface/src/interface/signerClient.ts b/js/signer-interface/src/interface/signerClient.ts
new file mode 100644
index 00000000..5c83f83f
--- /dev/null
+++ b/js/signer-interface/src/interface/signerClient.ts
@@ -0,0 +1,72 @@
+// @ts-nocheck
+import * as axios from 'axios';
+import { base58Encode } from '@polkadot/util-crypto';
+import { ClientAsset } from '../classes/clientAsset';
+export class SignerClient {
+ constructor(api, signerURL) {
+ axios.defaults.baseURL = signerURL;
+ this.api = api;
+ }
+
+ async getSignerVersion() {
+ try {
+ const res = await axios.get('version', { timeout: 200 });
+ return res.data.version;
+ } catch (timeoutError) {
+ return null;
+ }
+ }
+
+ async recoverAccount(params) {
+ const res = await axios.post('recoverAccount', params.toU8a());
+ const account = this.api.createType(
+ 'RecoveredAccount',
+ new Uint8Array(res.data.recovered_account)
+ );
+ return account.assets.map((signerAsset) =>
+ ClientAsset.fromSignerAsset(signerAsset)
+ );
+ }
+
+ async deriveShieldedAddress(params) {
+ const res = await axios.post('deriveShieldedAddress', params.toU8a());
+ return base58Encode(
+ this.api
+ .createType(
+ 'MantaAssetShieldedAddress',
+ new Uint8Array(res.data.address)
+ )
+ .toU8a()
+ );
+ }
+
+ async generateAsset(params) {
+ const res = await axios.post('generateAsset', params.toU8a());
+ return this.api.createType(
+ 'MantaSignerInputAsset',
+ new Uint8Array(res.data.asset)
+ );
+ }
+
+ async generateMintData(params) {
+ const res = await axios.post('generateMintData', params.toU8a());
+ return new Uint8Array(res.data.mint_data);
+ }
+
+ async requestGeneratePrivateTransferData(params) {
+ const res = await axios.post('generatePrivateTransferData', params.toU8a());
+ const decoded = this.api.createType(
+ 'PrivateTransferBatch',
+ new Uint8Array(res.data.private_transfer_data)
+ );
+ return decoded.private_transfer_data_list.map((data) => data.toU8a());
+ }
+
+ async requestGenerateReclaimData(params) {
+ const res = await axios.post('generateReclaimData', params.toU8a());
+ return this.api.createType(
+ 'ReclaimBatch',
+ new Uint8Array(res.data.reclaim_data)
+ );
+ }
+}
diff --git a/js/signer-interface/src/interface/signerInterface.ts b/js/signer-interface/src/interface/signerInterface.ts
new file mode 100644
index 00000000..3457e5f3
--- /dev/null
+++ b/js/signer-interface/src/interface/signerInterface.ts
@@ -0,0 +1,381 @@
+// @ts-nocheck
+import * as BN from 'bn.js';
+import { SimulatedLedgerState } from '../classes/simulatedLedgerState';
+import { ClientAsset } from '../classes/clientAsset';
+import { SignerParamGen } from './signerParamGen';
+import { SignerClient } from './signerClient';
+import { BrowserAssetStore } from '../store/assetStore/browserAssetStore';
+import { BrowserBlockchainStore } from '../store/blockchainStore/browserBlockchainStore';
+import { BrowserAddressStore } from '../store/addressStore/browserAddressStore';
+import { BlockchainNodeClient } from './blockchainNodeClient';
+import { JsonAddressStore } from '../store/addressStore/jsonAddressStore';
+import { JsonAssetStore } from '../store/assetStore/jsonAssetStore';
+import { JsonBlockchainStore } from '../store/blockchainStore/jsonBlockchainStore';
+
+export class SignerInterface {
+ constructor(api, config) {
+ this.api = api;
+ this.ledgerState = new SimulatedLedgerState(api);
+ this.signerClient = new SignerClient(api, config.signerUrl);
+ this.signerParamGen = new SignerParamGen(api);
+ this.blockchainNodeClient = new BlockchainNodeClient(api);
+
+ if (config.isInBrowser) {
+ this.addressStore = new BrowserAddressStore(
+ config.bip44CoinTypeId,
+ config.baseStorageKey
+ );
+ this.assetStore = new BrowserAssetStore(api, config.baseStorageKey);
+ this.blockchainStore = new BrowserBlockchainStore(config.baseStorageKey);
+ } else {
+ this.addressStore = new JsonAddressStore(
+ config.bip44CoinTypeId,
+ config.baseStorageKey
+ );
+ this.assetStore = new JsonAssetStore(api, config.baseStorageKey);
+ this.blockchainStore = new JsonBlockchainStore(config.baseStorageKey);
+ }
+ }
+
+ // To be run after a transaction generated by SignerInterface is published on
+ // chain, before generating further transactions
+ cleanupTxSuccess() {
+ this.addressStore.commitInternalAddresses();
+ // reset simulated ledger state now that simulated changes are irrelevant
+ this.ledgerState = new SimulatedLedgerState(this.api);
+ }
+
+ // To be run after a transaction generated by SignerInterface fails
+ // (on or off chain), before generating further transactions
+ cleanupTxFailure() {
+ this.addressStore.rollBackInternalAddresses();
+ // reset ledger state now that simulated changes are on chain
+ this.ledgerState = new SimulatedLedgerState(this.api);
+ }
+
+ // Returns the version of the connected instance of Manta Signer
+ async getSignerVersion() {
+ return await this.signerClient.getSignerVersion();
+ }
+
+ // Returns true if Manta Signer can be pinged and false otherwise
+ async signerIsConnected() {
+ const version = await this.getSignerVersion();
+ return !!version;
+ }
+
+ // Generates a list of transaction that, when executed in sequence, accomplish
+ // a private transfer to the given receivingAddress
+ async buildExternalPrivateTransferTxs(receivingAddress, coinSelection) {
+ const mintZeroCoinTxs = await this._maybeBuildMintZeroCoinTxs(
+ coinSelection
+ );
+
+ // build params
+ const batchParams = await this._buildPrivateTransferBatchParams(
+ coinSelection,
+ receivingAddress
+ );
+
+ // build transaction data
+ const privateTransferDataList =
+ await this.signerClient.requestGeneratePrivateTransferData(batchParams);
+
+ // build transactions
+ const transactions = privateTransferDataList.map((privateTransferData) =>
+ this.api.tx.mantaPay.privateTransfer(privateTransferData)
+ );
+ mintZeroCoinTxs.forEach((mintZeroCointTx) =>
+ transactions.unshift(mintZeroCointTx)
+ );
+ return transactions;
+ }
+
+ // Generates a list of transaction that, when executed in sequence, accomplishes
+ // a reclaim of private assets owned by the connected instance of Manta Signer
+ // to some public address
+ async buildReclaimTxs(coinSelection) {
+ const mintZeroCoinTxs = await this._maybeBuildMintZeroCoinTxs(
+ coinSelection
+ );
+
+ // build params
+ const batchParams = await this._buildReclaimBatchParams(coinSelection);
+
+ // build transaction data
+ const reclaimData = await this.signerClient.requestGenerateReclaimData(
+ batchParams
+ );
+
+ // build transactions
+ const privateTransfersTransactions =
+ reclaimData.private_transfer_data_list.map((privateTransferData) =>
+ this.api.tx.mantaPay.privateTransfer(privateTransferData)
+ );
+ const reclaimTransaction = this.api.tx.mantaPay.reclaim(
+ reclaimData.reclaim_data
+ );
+ const transactions = [...privateTransfersTransactions, reclaimTransaction];
+ mintZeroCoinTxs.forEach((mintZeroCointTx) =>
+ transactions.unshift(mintZeroCointTx)
+ );
+
+ return transactions;
+ }
+
+ // Generates a single transaction to mint a private asset of the given id / value,
+ // to be owned by the connected instance of Manta Signer
+ async buildMintTx(assetId, valueAtomicUnits) {
+ await this._generateNextInternalAddress();
+ const mintAssetkeypath = this.addressStore.getCurrentInternalKeypath();
+ const mintAsset = new ClientAsset(
+ assetId,
+ valueAtomicUnits,
+ mintAssetkeypath
+ );
+ const mintParams = this.signerParamGen.generateMintParams(mintAsset);
+ const mintData = await this.signerClient.generateMintData(mintParams);
+ const mintTx = this.api.tx.mantaPay.mintPrivateAsset(mintData);
+ return mintTx;
+ }
+
+ // Generates the next external address in the standard BIP42 external keypath
+ // belonging to connected instance of Manta Signer. External addresses should
+ // only be used for receiving external payments, e.g. as the addresses
+ // displayed in Manta Web App
+ async generateNextExternalAddress() {
+ const keypath = this.addressStore.getNextExternalKeypath();
+ const params = this.signerParamGen.generateAddressParams(keypath);
+ const address = await this.signerClient.deriveShieldedAddress(params);
+ this.addressStore.saveExternalAddress(address);
+ return address;
+ }
+
+ // Returns all assets currently owned by the connected instance of Manta Signer
+ async recoverAccount() {
+ // Collect parameters from on chain
+ const voidNumbers = await this.blockchainNodeClient.getAllVoidNumbers();
+ const { newUTXOs, newEncryptedNotes, utxoSet } =
+ await this.blockchainNodeClient.getNewUTXOsAndEncryptedNotes(
+ this.blockchainStore.loadUTXOSet()
+ );
+ const params = this.signerParamGen.generateRecoverAccountParams(
+ newUTXOs,
+ newEncryptedNotes,
+ voidNumbers
+ );
+
+ // Get newly received assets from manta signer and add to storage
+ const newPrivateAssets = await this.signerClient.recoverAccount(params);
+ this.assetStore.addPrivateAssets(newPrivateAssets);
+ this.blockchainStore.saveUTXOSet(utxoSet);
+
+ // Get rid of assets we have spend since last refresh
+ this._purgeSpentAssets(voidNumbers);
+
+ return this.assetStore.loadPrivateAssets();
+ }
+
+ // Resets all persistent state that signer interface keeps
+ resetStorage() {
+ this.assetStore.reset();
+ this.addressStore.reset();
+ this.blockchainStore.reset();
+ }
+
+ // Removes assets from storage if their void number has been revealed on chain
+ _purgeSpentAssets(voidNumbers) {
+ const voidNumbersSet = new Set();
+ voidNumbers.forEach((voidNumber) => {
+ const voidNumberString = voidNumber.join(',');
+ voidNumbersSet.add(voidNumberString);
+ });
+ const privateAssets = this.assetStore.loadPrivateAssets();
+ const unspentAssets = privateAssets.filter(
+ (asset) => !voidNumbersSet.has(asset.voidNumber.join(','))
+ );
+ this.assetStore.savePrivateAssets(unspentAssets);
+ }
+
+ // Builds up to two transaction to mint a private asset of zero value, but
+ // only if this zero asset is required to complete a transaction, i.e. if the
+ // coin selection only contains contains less than two coins
+ async _maybeBuildMintZeroCoinTxs(coinSelection) {
+ const mintZeroCoinTxs = [];
+ const numberOfZeroCoinsRequired = coinSelection.numberOfZeroCoinsRequired();
+ for (let i = 0; i < numberOfZeroCoinsRequired; i++) {
+ const mintZeroCoinTx = await this._buildMintZeroCoinTx(coinSelection);
+ mintZeroCoinTxs.push(mintZeroCoinTx);
+ }
+ return mintZeroCoinTxs;
+ }
+
+ // Builds a single transaction that mints a coin of zero value
+ async _buildMintZeroCoinTx(coinSelection) {
+ const zeroCoinAsset = await this._generateInternalAsset(
+ coinSelection.assetId,
+ new BN(0)
+ );
+ coinSelection.coins.unshift(zeroCoinAsset);
+ this.ledgerState.addOffChainAsset(zeroCoinAsset);
+ const zeroCoinParams =
+ this.signerParamGen.generateMintParams(zeroCoinAsset);
+
+ const mintZeroCoinData = await this.signerClient.generateMintData(
+ zeroCoinParams
+ );
+ return this.api.tx.mantaPay.mintPrivateAsset(mintZeroCoinData);
+ }
+
+ // Builds the parameters required by Manta Signer to build a 'logical' private transfer
+ async _buildPrivateTransferBatchParams(coinSelection, receivingAddress) {
+ const { internalTransferParamsList, accumulatorInput } =
+ await this._buildInternalTransferParamsList(coinSelection);
+ const terminalPrivateTransferParams =
+ await this._buildTerminalPrivateTransferParams(
+ coinSelection,
+ accumulatorInput
+ );
+ const transferParamsList = [
+ ...internalTransferParamsList,
+ terminalPrivateTransferParams
+ ];
+ return await this.signerParamGen.generatePrivateTransferBatchParams(
+ coinSelection.assetId,
+ receivingAddress,
+ transferParamsList
+ );
+ }
+
+ // Builds the parameters required by Manta Signer to build a 'logical' reclaim transaction
+ async _buildReclaimBatchParams(coinSelection) {
+ const { internalTransferParamsList, accumulatorInput } =
+ await this._buildInternalTransferParamsList(coinSelection);
+ const reclaimParams = await this._buildTerminalReclaimParams(
+ coinSelection,
+ accumulatorInput
+ );
+ return await this.signerParamGen.generateReclaimBatchParams(
+ internalTransferParamsList,
+ reclaimParams
+ );
+ }
+
+ // Builds the parameters required by Manta Signer to build 'setup' transactions
+ // and accumulate assets into exacly two inputs within the user's own wallet,
+ // in preparation for some final transaction
+ async _buildInternalTransferParamsList(coinSelection) {
+ const internalTransferParamsList = [];
+ let accumulatorInput;
+ for (let i = 1; i < coinSelection.coins.length - 1; i++) {
+ const inputAsset1 = accumulatorInput || coinSelection.coins[0];
+ const inputAsset2 = coinSelection.coins[i];
+ await this._setShard(inputAsset1);
+ await this._setShard(inputAsset2);
+ const totalValueAtomicUnits = inputAsset2.valueAtomicUnits.add(
+ inputAsset1.valueAtomicUnits
+ );
+ const changeOutput = await this._generateInternalAsset(
+ coinSelection.assetId,
+ new BN(0)
+ );
+ const accumulatorOutput = await this._generateInternalAsset(
+ coinSelection.assetId,
+ totalValueAtomicUnits
+ );
+ this.ledgerState.addOffChainAsset(accumulatorOutput);
+ this.ledgerState.addOffChainAsset(changeOutput);
+
+ const params = await this.signerParamGen.generatePrivateTransferParams(
+ inputAsset1,
+ inputAsset2,
+ changeOutput,
+ accumulatorOutput
+ );
+ internalTransferParamsList.push(params);
+ accumulatorInput = accumulatorOutput;
+ }
+ return { internalTransferParamsList, accumulatorInput };
+ }
+
+ // Builds the parameters required by Manta Signer to build the final private
+ // transfer transaction, which finally sends assets accumulated within a
+ // user's own wallet to some external address
+ async _buildTerminalPrivateTransferParams(coinSelection, accumulatorInput) {
+ const inputAsset1 = accumulatorInput || coinSelection.secondLast();
+ const inputAsset2 = coinSelection.last();
+
+ await this._setShard(inputAsset1);
+ await this._setShard(inputAsset2);
+
+ const changeOutput = await this._generateInternalAsset(
+ coinSelection.assetId,
+ coinSelection.changeValueAtomicUnits
+ );
+ const nonChangeOutput = await ClientAsset.newExternalOutput(
+ coinSelection.assetId,
+ coinSelection.targetValueAtomicUnits
+ );
+
+ const params = await this.signerParamGen.generatePrivateTransferParams(
+ inputAsset1,
+ inputAsset2,
+ changeOutput,
+ nonChangeOutput
+ );
+ return params;
+ }
+
+ // Builds the parameters required by Manta Signer to build the final reclaim
+ // transaction, which finally redeems private assets accumulated within a
+ // user's own private wallet to some public address
+ async _buildTerminalReclaimParams(coinSelection, accumulatorInput) {
+ const inputAsset1 = accumulatorInput || coinSelection.secondLast();
+ const inputAsset2 = coinSelection.last();
+
+ await this._setShard(inputAsset1);
+ await this._setShard(inputAsset2);
+
+ const changeOutput = await this._generateInternalAsset(
+ coinSelection.assetId,
+ coinSelection.changeValueAtomicUnits
+ );
+ const params = await this.signerParamGen.generateReclaimParams(
+ inputAsset1,
+ inputAsset2,
+ changeOutput
+ );
+ return params;
+ }
+
+ // Generates the next address in the standard BIP42 internal keypath
+ // belonging to connected instance of Manta Signer. Internal addresses should
+ // only receive change outputs and freshly minted assets generated by the user's
+ // own wallet, and should never appear in a UI
+ async _generateNextInternalAddress() {
+ const keypath = this.addressStore.getNextInternalKeypath();
+ const params = this.signerParamGen.generateAddressParams(keypath);
+ const address = await this.signerClient.deriveShieldedAddress(params);
+ this.addressStore.saveInternalAddress(address);
+ }
+
+ // Generates an 'off chain' assets belonging to the connected instance of Manta Signer
+ async _generateInternalAsset(assetId, value) {
+ await this._generateNextInternalAddress();
+ const keypath = this.addressStore.getCurrentInternalKeypath();
+ const params = this.signerParamGen.generateAssetParams(
+ assetId,
+ keypath,
+ value
+ );
+ const asset = await this.signerClient.generateAsset(params);
+ return ClientAsset.fromSignerAsset(asset);
+ }
+
+ // Sets the shard for some asset to incorporate both current on-chain state and
+ // simulated future ledger state
+ async _setShard(asset) {
+ const shard = await this.ledgerState.getShard(asset);
+ asset.setShard(shard);
+ }
+}
diff --git a/js/signer-interface/src/interface/signerParamGen.ts b/js/signer-interface/src/interface/signerParamGen.ts
new file mode 100644
index 00000000..d7b471e5
--- /dev/null
+++ b/js/signer-interface/src/interface/signerParamGen.ts
@@ -0,0 +1,104 @@
+// @ts-nocheck
+import { base58Decode } from '@polkadot/util-crypto';
+
+export class SignerParamGen {
+ constructor(api) {
+ this.api = api;
+ }
+
+ generateAssetParams(assetId, keypath, value) {
+ return this.api.createType('GenerateAssetParams', {
+ asset_id: assetId,
+ keypath: keypath,
+ value: value
+ });
+ }
+
+ generateMintParams(asset) {
+ const res = this.api.createType('GenerateAssetParams', {
+ asset_id: asset.assetId,
+ keypath: asset.keypath,
+ value: asset.valueAtomicUnits
+ });
+ return res;
+ }
+
+ generateAddressParams(keypath) {
+ return this.api.createType('DeriveShieldedAddressParams', {
+ keypath: keypath
+ });
+ }
+
+ generatePrivateTransferParams(
+ inputAsset1,
+ inputAsset2,
+ changeOutputAsset,
+ nonChangeOutputAsset
+ ) {
+ const params = this.api.createType('GeneratePrivateTransferParams', {
+ sender_asset_1_value: inputAsset1.valueAtomicUnits,
+ sender_asset_2_value: inputAsset2.valueAtomicUnits,
+ sender_asset_1_keypath: inputAsset1.keypath,
+ sender_asset_2_keypath: inputAsset2.keypath,
+ sender_asset_1_shard: inputAsset1.shard,
+ sender_asset_2_shard: inputAsset2.shard,
+ change_output_keypath: changeOutputAsset.keypath,
+ non_change_output_keypath: nonChangeOutputAsset.keypath,
+ non_change_output_value: nonChangeOutputAsset.valueAtomicUnits,
+ change_output_value: changeOutputAsset.valueAtomicUnits
+ });
+ return params;
+ }
+
+ generateReclaimParams(
+ reclaimInputAsset1,
+ reclaimInputAsset2,
+ changeOutputAsset
+ ) {
+ const totalValueAtomicUnits = reclaimInputAsset1.valueAtomicUnits.add(
+ reclaimInputAsset2.valueAtomicUnits
+ );
+ const reclaimValueAtomicUnits = totalValueAtomicUnits.sub(
+ changeOutputAsset.valueAtomicUnits
+ );
+ const params = this.api.createType('GenerateReclaimParams', {
+ asset_id: reclaimInputAsset1.assetId,
+ input_asset_1_value: reclaimInputAsset1.valueAtomicUnits,
+ input_asset_2_value: reclaimInputAsset2.valueAtomicUnits,
+ input_asset_1_keypath: reclaimInputAsset1.keypath,
+ input_asset_2_keypath: reclaimInputAsset2.keypath,
+ input_asset_1_shard: reclaimInputAsset1.shard,
+ input_asset_2_shard: reclaimInputAsset2.shard,
+ change_keypath: changeOutputAsset.keypath,
+ reclaim_value: reclaimValueAtomicUnits
+ });
+ return params;
+ }
+
+ generatePrivateTransferBatchParams(
+ assetId,
+ receivingAddress,
+ privateTransferParamsList
+ ) {
+ return this.api.createType('GeneratePrivateTransferBatchParams', {
+ asset_id: assetId,
+ receiving_address: base58Decode(receivingAddress),
+ private_transfer_params_list: privateTransferParamsList
+ });
+ }
+
+ generateReclaimBatchParams(privateTransferParamsList, reclaimParams) {
+ return this.api.createType('GenerateReclaimBatchParams', {
+ private_transfer_params_list: privateTransferParamsList,
+ reclaim_params: reclaimParams
+ });
+ }
+
+ generateRecoverAccountParams(utxos, encryptedNotes, voidNumbers) {
+ return this.api.createType('RecoverAccountParams', {
+ void_numbers: voidNumbers,
+ utxos: utxos,
+ encrypted_notes: encryptedNotes
+ });
+ }
+}
diff --git a/js/signer-interface/src/store/addressStore/addressStore.ts b/js/signer-interface/src/store/addressStore/addressStore.ts
new file mode 100644
index 00000000..ffc0daf6
--- /dev/null
+++ b/js/signer-interface/src/store/addressStore/addressStore.ts
@@ -0,0 +1,80 @@
+// @ts-nocheck
+import {
+ BIP_44_PURPOSE_INDEX,
+ DEFAULT_ACCOUNT_ID,
+ EXTERNAL_CHAIN_ID,
+ INTERNAL_CHAIN_ID
+} from '../../constants/bip44Constants';
+
+export class AddressStore {
+ constructor(coinTypeId) {
+ this.baseKeypath = `m/${BIP_44_PURPOSE_INDEX}'/${coinTypeId}'/${DEFAULT_ACCOUNT_ID}'`;
+ }
+
+ reset() {
+ this._saveInternalAddresses([]);
+ this._saveExternalAddresses([]);
+ this._saveUncommitedOffset(0);
+ }
+
+ _loadInternalAddresses() {}
+
+ _loadExternalAddresses() {}
+
+ _loadUncommitedOffset() {}
+
+ _saveInternalAddresses(addresses) {}
+
+ _saveExternalAddresses(addresses) {}
+
+ _saveUncommitedOffset(uncommitedOffset) {}
+
+ _incrementUncommitedOffset() {
+ this._saveUncommitedOffset(this._loadUncommitedOffset() + 1);
+ }
+
+ _resetUncommitedOffset() {
+ this._saveUncommitedOffset(0);
+ }
+
+ saveInternalAddress(address) {
+ const internalAddresses = this._loadInternalAddresses();
+ internalAddresses.push(address);
+ this._saveInternalAddresses(internalAddresses);
+ this._incrementUncommitedOffset();
+ }
+
+ saveExternalAddress(address) {
+ const externalAddresses = this._loadExternalAddresses();
+ externalAddresses.push(address);
+ this._saveExternalAddresses(externalAddresses);
+ }
+
+ rollBackInternalAddresses() {
+ const internalAddresses = this._loadInternalAddresses();
+ for (let i = 0; i < this._loadUncommitedOffset(); i++) {
+ internalAddresses.pop();
+ }
+ this._saveInternalAddresses(internalAddresses);
+ this._resetUncommitedOffset();
+ }
+
+ commitInternalAddresses() {
+ this._resetUncommitedOffset();
+ }
+
+ getNextInternalKeypath() {
+ const addressIdx = this._loadInternalAddresses().length;
+ return `${this.baseKeypath}/${INTERNAL_CHAIN_ID}/${addressIdx}`;
+ }
+
+ getCurrentInternalKeypath() {
+ const addressIdx = this._loadInternalAddresses().length - 1;
+ return `${this.baseKeypath}/${INTERNAL_CHAIN_ID}/${addressIdx}`;
+ }
+
+ getNextExternalKeypath() {
+ const addressIdx = this._loadExternalAddresses().length;
+ return `${this.baseKeypath}/${EXTERNAL_CHAIN_ID}/${addressIdx}`;
+ }
+}
diff --git a/js/signer-interface/src/store/addressStore/browserAddressStore.ts b/js/signer-interface/src/store/addressStore/browserAddressStore.ts
new file mode 100644
index 00000000..d6b1d2a2
--- /dev/null
+++ b/js/signer-interface/src/store/addressStore/browserAddressStore.ts
@@ -0,0 +1,36 @@
+// @ts-nocheck
+import { AddressStore } from './addressStore';
+import * as store from 'store';
+
+export class BrowserAddressStore extends AddressStore {
+ constructor(bip44CoinTypeId, baseStorageKey) {
+ super(bip44CoinTypeId);
+ this.externalAddressesStorageKey = `${baseStorageKey}ExternalAddresses`;
+ this.internalAddressesStorageKey = `${baseStorageKey}InternalAddresses`;
+ this.internalAddressesUncommitedOffset = `${this.baseStorageKey}InternalAddressesUncommitedOffset`;
+ }
+
+ _loadInternalAddresses() {
+ return store.get(this.internalAddressesStorageKey, []);
+ }
+
+ _loadExternalAddresses() {
+ return store.get(this.externalAddressesStorageKey, []);
+ }
+
+ _loadUncommitedOffset() {
+ return store.get(this.internalAddressesUncommitedOffset, 0);
+ }
+
+ _saveInternalAddresses(addresses) {
+ return store.set(this.internalAddressesStorageKey, addresses);
+ }
+
+ _saveExternalAddresses(addresses) {
+ return store.set(this.externalAddressesStorageKey, addresses);
+ }
+
+ _saveUncommitedOffset(offset) {
+ store.set(this.internalAddressesUncommitedOffset, offset);
+ }
+}
diff --git a/js/signer-interface/src/store/addressStore/jsonAddressStore.ts b/js/signer-interface/src/store/addressStore/jsonAddressStore.ts
new file mode 100644
index 00000000..2895f2c9
--- /dev/null
+++ b/js/signer-interface/src/store/addressStore/jsonAddressStore.ts
@@ -0,0 +1,50 @@
+// @ts-nocheck
+import { AddressStore } from './addressStore';
+import * as fs from 'fs';
+
+export class JsonAddressStore extends AddressStore {
+ fileName: string;
+
+ constructor(bip44CoinTypeId, baseFileName) {
+ super(bip44CoinTypeId);
+ this.fileName = `${baseFileName}AddressStore.json`;
+ if (!fs.existsSync(this.fileName)) {
+ const emptyAddressStore = JSON.stringify({
+ internalAddresses: [],
+ externalAddresses: [],
+ uncommitedOffset: 0
+ });
+ fs.writeFileSync(this.fileName, emptyAddressStore);
+ }
+ }
+
+ _loadInternalAddresses() {
+ return JSON.parse(fs.readFileSync(this.fileName)).internalAddresses;
+ }
+
+ _loadExternalAddresses() {
+ return JSON.parse(fs.readFileSync(this.fileName)).externalAddresses;
+ }
+
+ _loadUncommitedOffset() {
+ return JSON.parse(fs.readFileSync(this.fileName)).uncommitedOffset;
+ }
+
+ _saveInternalAddresses(internalAddresses) {
+ const storeJson = JSON.parse(fs.readFileSync(this.fileName));
+ storeJson.internalAddresses = internalAddresses;
+ fs.writeFileSync(this.fileName, JSON.stringify(storeJson));
+ }
+
+ _saveExternalAddresses(externalAddresses) {
+ const storeJson = JSON.parse(fs.readFileSync(this.fileName));
+ storeJson.externalAddresses = externalAddresses;
+ fs.writeFileSync(this.fileName, JSON.stringify(storeJson));
+ }
+
+ _saveUncommitedOffset(uncommitedOffset) {
+ const storeJson = JSON.parse(fs.readFileSync(this.fileName));
+ storeJson.uncommitedOffset = uncommitedOffset;
+ fs.writeFileSync(this.fileName, JSON.stringify(storeJson));
+ }
+}
diff --git a/js/signer-interface/src/store/assetStore/assetStore.ts b/js/signer-interface/src/store/assetStore/assetStore.ts
new file mode 100644
index 00000000..86fdae87
--- /dev/null
+++ b/js/signer-interface/src/store/assetStore/assetStore.ts
@@ -0,0 +1,38 @@
+// @ts-nocheck
+import { ClientAsset } from '../..';
+
+export class AssetStore {
+ constructor(api) {
+ this.api = api;
+ }
+
+ reset() {
+ this.savePrivateAssets([]);
+ }
+
+ savePrivateAssets(privateAssets: ClientAsset[]) {}
+
+ loadPrivateAssets() {}
+
+ addPrivateAssets(newAssets: ClientAsset[]) {
+ // Check for duplicates before saving--this avoids a bug:
+ // If the user has Manta Web App open in two browser windows, they will both
+ // attempt to fetch new assets, and will sometimes save duplicates
+ const prevAssets = this.loadPrivateAssets();
+ const uniqueNewAssets = newAssets.filter((newAsset) => {
+ return !prevAssets.some(prevAsset => prevAsset.equals(newAsset));
+ });
+ this.savePrivateAssets([...prevAssets, ...uniqueNewAssets]);
+ }
+
+ _serializeAssetsForStorage(privateAssets) {
+ return privateAssets.map((asset) => Array.from(asset.toU8a(this.api)));
+ }
+
+ _deserializeAssetsFromStorage(serializedAssets) {
+ const privateAssetsRaw = serializedAssets || [];
+ return privateAssetsRaw.map((bytes) =>
+ ClientAsset.fromU8a(new Uint8Array(bytes), this.api)
+ );
+ }
+}
diff --git a/js/signer-interface/src/store/assetStore/browserAssetStore.ts b/js/signer-interface/src/store/assetStore/browserAssetStore.ts
new file mode 100644
index 00000000..aa08ec6e
--- /dev/null
+++ b/js/signer-interface/src/store/assetStore/browserAssetStore.ts
@@ -0,0 +1,21 @@
+// @ts-nocheck
+import { AssetStore } from './assetStore';
+import * as store from 'store';
+import { ClientAsset } from '../..';
+
+export class BrowserAssetStore extends AssetStore {
+ constructor(api, baseStorageKey) {
+ super(api);
+ this.baseStorageKey = baseStorageKey;
+ }
+
+ savePrivateAssets(privateAssets: ClientAsset[]) {
+ const serializedAssets = this._serializeAssetsForStorage(privateAssets);
+ store.set(`${this.baseStorageKey}PrivateAssets`, serializedAssets);
+ }
+
+ loadPrivateAssets(): ClientAsset[] {
+ const serializedAssets = store.get(`${this.baseStorageKey}PrivateAssets`);
+ return this._deserializeAssetsFromStorage(serializedAssets);
+ }
+}
diff --git a/js/signer-interface/src/store/assetStore/jsonAssetStore.ts b/js/signer-interface/src/store/assetStore/jsonAssetStore.ts
new file mode 100644
index 00000000..2dc65e2e
--- /dev/null
+++ b/js/signer-interface/src/store/assetStore/jsonAssetStore.ts
@@ -0,0 +1,27 @@
+// @ts-nocheck
+import { AssetStore } from './assetStore';
+import * as fs from 'fs';
+import { ClientAsset } from '../..';
+
+export class JsonAssetStore extends AssetStore {
+ constructor(api, baseFileName) {
+ super(api);
+ this.fileName = `${baseFileName}AssetStore.json`;
+ if (!fs.existsSync(this.fileName)) {
+ const emptyAssetStore = JSON.stringify([]);
+ fs.writeFileSync(this.fileName, emptyAssetStore);
+ }
+ }
+
+ savePrivateAssets(privateAssets: ClientAsset[]) {
+ const serializedAssets = JSON.stringify(
+ this._serializeAssetsForStorage(privateAssets)
+ );
+ fs.writeFileSync(this.fileName, serializedAssets);
+ }
+
+ loadPrivateAssets() {
+ const serializedAssets = JSON.parse(fs.readFileSync(this.fileName));
+ return this._deserializeAssetsFromStorage(serializedAssets);
+ }
+}
diff --git a/js/signer-interface/src/store/blockchainStore/blockchainStore.ts b/js/signer-interface/src/store/blockchainStore/blockchainStore.ts
new file mode 100644
index 00000000..8345b31a
--- /dev/null
+++ b/js/signer-interface/src/store/blockchainStore/blockchainStore.ts
@@ -0,0 +1,10 @@
+// @ts-nocheck
+export class BlockchainStore {
+ reset() {
+ this.saveUTXOSet({});
+ }
+
+ loadUTXOSet() {}
+
+ saveUTXOSet(utxoSet) {}
+}
diff --git a/js/signer-interface/src/store/blockchainStore/browserBlockchainStore.ts b/js/signer-interface/src/store/blockchainStore/browserBlockchainStore.ts
new file mode 100644
index 00000000..b513a40c
--- /dev/null
+++ b/js/signer-interface/src/store/blockchainStore/browserBlockchainStore.ts
@@ -0,0 +1,18 @@
+// @ts-nocheck
+import * as store from 'store';
+import { BlockchainStore } from './blockchainStore';
+
+export class BrowserBlockchainStore extends BlockchainStore {
+ constructor(baseStorageKey) {
+ super();
+ this.utxoSetStorageKey = `${baseStorageKey}UTXOSet`;
+ }
+
+ loadUTXOSet() {
+ return store.get(this.utxoSetStorageKey, {});
+ }
+
+ saveUTXOSet(utxoSet) {
+ store.set(this.utxoSetStorageKey, utxoSet);
+ }
+}
diff --git a/js/signer-interface/src/store/blockchainStore/jsonBlockchainStore.ts b/js/signer-interface/src/store/blockchainStore/jsonBlockchainStore.ts
new file mode 100644
index 00000000..85eace11
--- /dev/null
+++ b/js/signer-interface/src/store/blockchainStore/jsonBlockchainStore.ts
@@ -0,0 +1,22 @@
+// @ts-nocheck
+import { BlockchainStore } from './blockchainStore';
+import * as fs from 'fs';
+
+export class JsonBlockchainStore extends BlockchainStore {
+ constructor(baseFileName) {
+ super();
+ this.fileName = `${baseFileName}BlockchainStore.json`;
+ if (!fs.existsSync(this.fileName)) {
+ const emptyAddressStore = JSON.stringify({});
+ fs.writeFileSync(this.fileName, emptyAddressStore);
+ }
+ }
+
+ loadUTXOSet() {
+ return JSON.parse(fs.readFileSync(this.fileName));
+ }
+
+ saveUTXOSet(utxoSet) {
+ fs.writeFileSync(this.fileName, JSON.stringify(utxoSet));
+ }
+}
diff --git a/js/signer-interface/tsconfig.json b/js/signer-interface/tsconfig.json
new file mode 100644
index 00000000..ce91a36f
--- /dev/null
+++ b/js/signer-interface/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "target": "ES6",
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "skipLibCheck": true,
+ "esModuleInterop": false
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules"]
+}
diff --git a/js/tsconfig.json b/js/tsconfig.json
new file mode 100644
index 00000000..23f57437
--- /dev/null
+++ b/js/tsconfig.json
@@ -0,0 +1,45 @@
+{
+ "exclude": ["node_modules"],
+ "references": [
+ {
+ "path": "./e2e"
+ },
+ {
+ "path": "./dev-cli"
+ },
+ {
+ "path": "./workflows"
+ },
+ {
+ "path": "./signer-interface"
+ },
+ {
+ "path": "./coin-selection"
+ }
+ ],
+ "files": [],
+ "include": [],
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["es2019"],
+ "module": "umd",
+ "outDir": "./bin",
+ "esModuleInterop": false,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true,
+ "strictFunctionTypes": true,
+ "strictBindCallApply": true,
+ "strictPropertyInitialization": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "exactOptionalPropertyTypes": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedIndexedAccess": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "skipLibCheck": true
+ }
+}
diff --git a/js/workflows/package.json b/js/workflows/package.json
new file mode 100644
index 00000000..1249b5ce
--- /dev/null
+++ b/js/workflows/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "workflows",
+ "version": "0.2.0",
+ "description": "A library of workflows using Manta extrinsics",
+ "main": "./dist/index.js",
+ "repository": "git@github.com:Manta-Network/manta-js",
+ "author": "Gabriela Brown ",
+ "scripts": {
+ "build": "rm -rf workflows/dist; tsc"
+ },
+ "license": "GPL-3.0-only",
+ "resolutions": {
+ "@polkadot/api": "^6.5.2",
+ "@polkadot/types": "^6.5.2"
+ },
+ "dependencies": {
+ "signer-interface": "^0.1.0",
+ "coin-selection": "^0.1.0"
+ }
+}
\ No newline at end of file
diff --git a/js/workflows/src/index.ts b/js/workflows/src/index.ts
new file mode 100644
index 00000000..759a6b11
--- /dev/null
+++ b/js/workflows/src/index.ts
@@ -0,0 +1,28 @@
+export {
+ ConfigTransferAssetWorkflow,
+ transferAssetWorkflow
+} from './workflows/transfer_asset_workflow';
+export {
+ ConfigMintAssetWorkflow,
+ mintAssetWorkflow
+} from './workflows/mint_asset_workflow';
+export {
+ ConfigReclaimAssetWorkflow,
+ reclaimAssetWorkflow
+} from './workflows/reclaim_asset_workflow';
+export {
+ ConfigPrivateTransferAssetWorkflow,
+ privateTransferAssetWorkflow
+} from './workflows/private_transfer_asset_workflow';
+export {
+ ConfigRecoverAccountWorkflow,
+ recoverAccountWorkflow
+} from './workflows/recover_account_workflow';
+export {
+ ConfigDeriveAddressWorkflow,
+ deriveAddressWorkflow
+} from './workflows/derive_address_workflow';
+export {
+ ConfigResetStorageWorkflow,
+ resetStorageWorkflow
+} from './workflows/reset_storage_workflow';
diff --git a/js/workflows/src/utils/GetFailedExtrinsicError.ts b/js/workflows/src/utils/GetFailedExtrinsicError.ts
new file mode 100644
index 00000000..02a80819
--- /dev/null
+++ b/js/workflows/src/utils/GetFailedExtrinsicError.ts
@@ -0,0 +1,36 @@
+import { EventRecord } from '@polkadot/types/interfaces';
+import { ApiPromise } from '@polkadot/api';
+
+export default function getFailedExtrinsicError(
+ events: Array,
+ api: ApiPromise
+): String {
+ let errorMessage = null;
+
+ events
+ .filter(({ event }) =>
+ // @ts-ignore FIXME
+ api.events.system.ExtrinsicFailed.is(event)
+ )
+ .forEach(
+ ({
+ event: {
+ data: [error, info]
+ }
+ }) => {
+ // @ts-ignore FIXME
+ if (error.isModule) {
+ // for module errors, we have the section indexed, lookup
+ // @ts-ignore FIXME
+ const decoded = api.registry.findMetaError(error.asModule);
+ // @ts-ignore FIXME
+ const { docs, method, section } = decoded;
+ errorMessage = `${section}.${method}: ${docs.join(' ')}`;
+ } else {
+ // Other, CannotLookup, BadOrigin, no extra info
+ errorMessage = error.toString();
+ }
+ }
+ );
+ return errorMessage; // TODO: JS option type?
+}
diff --git a/js/workflows/src/utils/MakeTxResHandler.ts b/js/workflows/src/utils/MakeTxResHandler.ts
new file mode 100644
index 00000000..73c1d268
--- /dev/null
+++ b/js/workflows/src/utils/MakeTxResHandler.ts
@@ -0,0 +1,52 @@
+import { EventRecord, ExtrinsicStatus } from '@polkadot/types/interfaces';
+import getFailedExtrinsicError from './GetFailedExtrinsicError';
+import TxStatus from './TxStatus';
+
+interface EventHandler {
+ status: ExtrinsicStatus;
+ events: EventRecord[];
+}
+
+export function makeTxResHandler(
+ api,
+ onSuccess = (block) => null,
+ onFailure = (block, error) => null,
+ onUpdate = (message) => null
+) {
+ return (input: EventHandler) => {
+ let error;
+ if (input.status.isInBlock || input.status.isFinalized) {
+ error = getFailedExtrinsicError(input.events, api);
+ }
+ if (input.status.isInBlock && error) {
+ onFailure(input.status.asInBlock.toString(), error);
+ } else if (input.status.isFinalized && error) {
+ onFailure(input.status.asFinalized.toString(), error);
+ } else if (input.status.isFinalized) {
+ onSuccess(input.status.asFinalized.toString());
+ } else {
+ onUpdate(input.status.type);
+ }
+ };
+}
+
+export function makeDefaultTxResHandler(api, setStatus, logStatus: boolean) {
+ const onSuccess = (block) => {
+ if (logStatus) {
+ console.log(TxStatus.finalized(block));
+ }
+ setStatus(TxStatus.finalized(block));
+ };
+ const onFailure = (block, error) => {
+ if (logStatus) {
+ console.log(TxStatus.failed(block, error));
+ }
+ setStatus(TxStatus.failed(block, error));
+ };
+ const onUpdate = (message) => {
+ if (logStatus) {
+ console.log(TxStatus.processing(message));
+ }
+ };
+ return makeTxResHandler(api, onSuccess, onFailure, onUpdate);
+}
diff --git a/js/workflows/src/utils/TxStatus.ts b/js/workflows/src/utils/TxStatus.ts
new file mode 100644
index 00000000..ab862e6e
--- /dev/null
+++ b/js/workflows/src/utils/TxStatus.ts
@@ -0,0 +1,50 @@
+const FINALIZED = 'finalized';
+const FAILED = 'failed';
+const PROCESSING = 'processing';
+
+export default class TxStatus {
+ status: string;
+ block: string;
+ message: string;
+
+ constructor(status: string, block: string = null, message: string = null) {
+ this.status = status;
+ this.block = block;
+ this.message = message;
+ }
+
+ static processing(message: string): TxStatus {
+ return new TxStatus(PROCESSING, null, message);
+ }
+
+ static finalized(block: string): TxStatus {
+ return new TxStatus(FINALIZED, block, null);
+ }
+
+ static failed(block: string, message: string): TxStatus {
+ return new TxStatus(FAILED, block, message);
+ }
+
+ isProcessing(): boolean {
+ return this.status === PROCESSING;
+ }
+
+ isFinalized(): boolean {
+ return this.status === FINALIZED;
+ }
+
+ isFailed(): boolean {
+ return this.status === FAILED;
+ }
+
+ toString(): string {
+ let message = this.status;
+ if (this.block) {
+ message += `;\n block hash: ${this.block}`;
+ }
+ if (this.message) {
+ message += `;\n ${this.message}`;
+ }
+ return message;
+ }
+}
diff --git a/js/workflows/src/workflows/derive_address_workflow.ts b/js/workflows/src/workflows/derive_address_workflow.ts
new file mode 100644
index 00000000..56a468c2
--- /dev/null
+++ b/js/workflows/src/workflows/derive_address_workflow.ts
@@ -0,0 +1,15 @@
+import { ApiPromise } from '@polkadot/api';
+import { SignerInterface, NodeJsSignerInterfaceConfig } from 'signer-interface';
+
+export type ConfigDeriveAddressWorkflow = {
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export async function deriveAddressWorkflow(
+ config: ConfigDeriveAddressWorkflow,
+ api: ApiPromise
+): Promise {
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+ const address = await signerInterface.generateNextExternalAddress();
+ return address;
+}
diff --git a/js/workflows/src/workflows/mint_asset_workflow.ts b/js/workflows/src/workflows/mint_asset_workflow.ts
new file mode 100644
index 00000000..514688f0
--- /dev/null
+++ b/js/workflows/src/workflows/mint_asset_workflow.ts
@@ -0,0 +1,45 @@
+import { ApiPromise, Keyring } from '@polkadot/api';
+import { makeTxResHandler } from '../utils/MakeTxResHandler';
+import TxStatus from '../utils/TxStatus';
+import { SignerInterface, NodeJsSignerInterfaceConfig } from 'signer-interface';
+
+export type ConfigMintAssetWorkflow = {
+ assetId: number;
+ valueAtomicUnits: number;
+ polkadotJsSigner: string;
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export async function mintAssetWorkflow(
+ config: ConfigMintAssetWorkflow,
+ api: ApiPromise
+): Promise {
+ const keyring = new Keyring({ type: 'sr25519' });
+ const signer = keyring.addFromUri(config.polkadotJsSigner);
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+
+ const mintTx = await signerInterface.buildMintTx(
+ config.assetId,
+ config.valueAtomicUnits
+ );
+
+ const status: Promise = new Promise((resolve) => {
+ const txResHandler = makeTxResHandler(
+ api,
+ (block) => {
+ signerInterface.cleanupTxSuccess();
+ console.log(TxStatus.finalized(block));
+ resolve(TxStatus.finalized(block));
+ },
+ (block, error) => {
+ signerInterface.cleanupTxFailure();
+ console.log(TxStatus.failed(block, error));
+ resolve(TxStatus.failed(block, error));
+ }
+ );
+
+ mintTx.signAndSend(signer, txResHandler);
+ });
+
+ return await status;
+}
diff --git a/js/workflows/src/workflows/private_transfer_asset_workflow.ts b/js/workflows/src/workflows/private_transfer_asset_workflow.ts
new file mode 100644
index 00000000..94d7e9e0
--- /dev/null
+++ b/js/workflows/src/workflows/private_transfer_asset_workflow.ts
@@ -0,0 +1,57 @@
+import { ApiPromise, Keyring } from '@polkadot/api';
+import { SignerInterface, NodeJsSignerInterfaceConfig } from 'signer-interface';
+import { makeTxResHandler } from '../utils/MakeTxResHandler';
+import TxStatus from '../utils/TxStatus';
+import { selectCoins } from 'coin-selection';
+import * as BN from 'bn.js';
+
+export type ConfigPrivateTransferAssetWorkflow = {
+ assetId: number;
+ valueAtomicUnits: number;
+ receiver: string;
+ polkadotJsSigner: string;
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export async function privateTransferAssetWorkflow(
+ config: ConfigPrivateTransferAssetWorkflow,
+ api: ApiPromise
+): Promise {
+ const keyring = new Keyring({ type: 'sr25519' });
+ const polkadotJsSigner = keyring.addFromUri(config.polkadotJsSigner);
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+
+ const assets = await signerInterface.recoverAccount();
+ const coinSelection = selectCoins(
+ new BN(config.valueAtomicUnits),
+ assets,
+ config.assetId
+ );
+
+ const privateTransferTxs =
+ await signerInterface.buildExternalPrivateTransferTxs(
+ config.receiver,
+ coinSelection
+ );
+
+ const status: Promise = new Promise((resolve) => {
+ const txResHandler = makeTxResHandler(
+ api,
+ (block) => {
+ console.log(TxStatus.finalized(block));
+ signerInterface.cleanupTxSuccess();
+ resolve(TxStatus.finalized(block));
+ },
+ (block, error) => {
+ signerInterface.cleanupTxFailure();
+ console.log(TxStatus.failed(block, error));
+ resolve(TxStatus.failed(block, error));
+ }
+ );
+ api.tx.utility
+ .batch(privateTransferTxs)
+ .signAndSend(polkadotJsSigner, txResHandler);
+ });
+
+ return await status;
+}
diff --git a/js/workflows/src/workflows/reclaim_asset_workflow.ts b/js/workflows/src/workflows/reclaim_asset_workflow.ts
new file mode 100644
index 00000000..e9dd1c1b
--- /dev/null
+++ b/js/workflows/src/workflows/reclaim_asset_workflow.ts
@@ -0,0 +1,50 @@
+import { ApiPromise, Keyring } from '@polkadot/api';
+import { SignerInterface, NodeJsSignerInterfaceConfig } from 'signer-interface';
+import { makeTxResHandler } from '../utils/MakeTxResHandler';
+import TxStatus from '../utils/TxStatus';
+import { selectCoins } from 'coin-selection';
+import * as BN from 'bn.js';
+
+export type ConfigReclaimAssetWorkflow = {
+ assetId: number;
+ valueAtomicUnits: number;
+ polkadotJsSigner: string;
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export async function reclaimAssetWorkflow(
+ config: ConfigReclaimAssetWorkflow,
+ api: ApiPromise
+): Promise {
+ const keyring = new Keyring({ type: 'sr25519' });
+ const polkadotJsSigner = keyring.addFromUri(config.polkadotJsSigner);
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+
+ const assets = await signerInterface.recoverAccount();
+ const coinSelection = selectCoins(
+ new BN(config.valueAtomicUnits),
+ assets,
+ config.assetId
+ );
+ const reclaimTxs = await signerInterface.buildReclaimTxs(coinSelection);
+ const status: Promise = new Promise((resolve) => {
+ const txResHandler = makeTxResHandler(
+ api,
+ (block) => {
+ console.log(TxStatus.finalized(block));
+ signerInterface.cleanupTxSuccess();
+ resolve(TxStatus.finalized(block));
+ },
+ (block, error) => {
+ signerInterface.cleanupTxFailure();
+ console.log(TxStatus.failed(block, error));
+ resolve(TxStatus.failed(block, error));
+ }
+ );
+ api.tx.utility
+ .batch(reclaimTxs)
+ .signAndSend(polkadotJsSigner, txResHandler);
+ });
+
+ return await status;
+}
diff --git a/js/workflows/src/workflows/recover_account_workflow.ts b/js/workflows/src/workflows/recover_account_workflow.ts
new file mode 100644
index 00000000..dd9c99c4
--- /dev/null
+++ b/js/workflows/src/workflows/recover_account_workflow.ts
@@ -0,0 +1,19 @@
+import { ApiPromise } from '@polkadot/api';
+import {
+ SignerInterface,
+ NodeJsSignerInterfaceConfig,
+ ClientAsset
+} from 'signer-interface';
+
+export type ConfigRecoverAccountWorkflow = {
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export async function recoverAccountWorkflow(
+ config: ConfigRecoverAccountWorkflow,
+ api: ApiPromise
+): Promise> {
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+ const recoveredAccount = await signerInterface.recoverAccount();
+ return recoveredAccount;
+}
diff --git a/js/workflows/src/workflows/reset_storage_workflow.ts b/js/workflows/src/workflows/reset_storage_workflow.ts
new file mode 100644
index 00000000..b017b419
--- /dev/null
+++ b/js/workflows/src/workflows/reset_storage_workflow.ts
@@ -0,0 +1,14 @@
+import { ApiPromise } from '@polkadot/api';
+import { NodeJsSignerInterfaceConfig, SignerInterface } from 'signer-interface';
+
+export type ConfigResetStorageWorkflow = {
+ signerInterface: NodeJsSignerInterfaceConfig;
+};
+
+export function resetStorageWorkflow(
+ config: ConfigResetStorageWorkflow,
+ api: ApiPromise
+) {
+ const signerInterface = new SignerInterface(api, config.signerInterface);
+ signerInterface.resetStorage();
+}
diff --git a/js/workflows/src/workflows/transfer_asset_workflow.ts b/js/workflows/src/workflows/transfer_asset_workflow.ts
new file mode 100644
index 00000000..4364b3d0
--- /dev/null
+++ b/js/workflows/src/workflows/transfer_asset_workflow.ts
@@ -0,0 +1,37 @@
+import { ApiPromise, Keyring } from '@polkadot/api';
+import { makeTxResHandler } from '../utils/MakeTxResHandler';
+import TxStatus from '../utils/TxStatus';
+
+export type ConfigTransferAssetWorkflow = {
+ assetId: number;
+ valueAtomicUnits: number;
+ polkadotJsSigner: string;
+ receiver: string;
+};
+
+export async function transferAssetWorkflow(
+ config: ConfigTransferAssetWorkflow,
+ api: ApiPromise
+): Promise {
+ const keyring = new Keyring({ type: 'sr25519' });
+ const signer = keyring.addFromUri(config.polkadotJsSigner);
+
+ const status: Promise = new Promise((resolve) => {
+ const txResHandler = makeTxResHandler(
+ api,
+ (block) => {
+ console.log(TxStatus.finalized(block));
+ resolve(TxStatus.finalized(block));
+ },
+ (block, error) => {
+ console.log(TxStatus.failed(block, error));
+ resolve(TxStatus.failed(block, error));
+ }
+ );
+ api.tx.mantaPay
+ .transferAsset(config.receiver, config.assetId, config.valueAtomicUnits)
+ // @ts-ignore FIXME
+ .signAndSend(signer, txResHandler);
+ });
+ return await status;
+}
diff --git a/js/workflows/tsconfig.json b/js/workflows/tsconfig.json
new file mode 100644
index 00000000..6a5a1ca3
--- /dev/null
+++ b/js/workflows/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "skipLibCheck": true,
+ "esModuleInterop": false
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules"]
+}
diff --git a/js/yarn.lock b/js/yarn.lock
new file mode 100644
index 00000000..f678645b
--- /dev/null
+++ b/js/yarn.lock
@@ -0,0 +1,2430 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
+ integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
+ dependencies:
+ "@babel/highlight" "^7.10.4"
+
+"@babel/helper-validator-identifier@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
+ integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+
+"@babel/highlight@^7.10.4":
+ version "7.16.10"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88"
+ integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.16.7"
+ chalk "^2.0.0"
+ js-tokens "^4.0.0"
+
+"@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7":
+ version "7.17.0"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.0.tgz#b8d142fc0f7664fb3d9b5833fd40dcbab89276c0"
+ integrity sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
+"@cspotcode/source-map-consumer@0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
+ integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
+
+"@cspotcode/source-map-support@0.7.0":
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
+ integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
+ dependencies:
+ "@cspotcode/source-map-consumer" "0.8.0"
+
+"@eslint/eslintrc@^0.4.3":
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
+ integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
+ 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"
+
+"@humanwhocodes/config-array@^0.5.0":
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
+ integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
+ dependencies:
+ "@humanwhocodes/object-schema" "^1.2.0"
+ debug "^4.1.1"
+ minimatch "^3.0.4"
+
+"@humanwhocodes/object-schema@^1.2.0":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
+ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+
+"@noble/hashes@0.5.7":
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-0.5.7.tgz#8605d84b34daf43d15c344fae54f0a1d5d5a4632"
+ integrity sha512-R9PPYv7TqoYi+enikzZvwRQesGTxR0+jwqzZJGL0uNcf2NFL+lt/uvCCewtXXmr6jWBxiMuNjBfJwKv9UJaCng==
+
+"@noble/secp256k1@1.3.4":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.3.4.tgz#158ded712d09237c0d3428be60dc01ce8ebab9fb"
+ integrity sha512-ZVRouDO5mbdCiDg4zCd3ZZABduRtpy4tCnB33Gh9upHe9tRzpiqbRSN1VTjrj/2g8u2c6MBi0YLNnNQpBYOiWg==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@polkadot/api-derive@6.12.1":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-6.12.1.tgz#f5356104d4cb1bed8f0dcac32afc4b0a5c05c232"
+ integrity sha512-5LOVlG5EBCT+ytY6aHmQ4RdEWZovZQqRoc6DLd5BLhkR7BFTHKSkLQW+89so8jd0zEtmSXBVPPnsrXS8joM35Q==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/api" "6.12.1"
+ "@polkadot/rpc-core" "6.12.1"
+ "@polkadot/types" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+ "@polkadot/util-crypto" "^8.1.2"
+ rxjs "^7.4.0"
+
+"@polkadot/api@6.12.1", "@polkadot/api@^6.5.2":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-6.12.1.tgz#685a2727eb532fdacd9b86f9ddf595d58be71ee4"
+ integrity sha512-RVdTiA2WaEvproM3i6E9TKS1bfXpPd9Ly9lUG/kVLaspjKoIot9DJUDTl97TJ+7xr8LXGbXqm448Ud0hsEBV8Q==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/api-derive" "6.12.1"
+ "@polkadot/keyring" "^8.1.2"
+ "@polkadot/rpc-core" "6.12.1"
+ "@polkadot/rpc-provider" "6.12.1"
+ "@polkadot/types" "6.12.1"
+ "@polkadot/types-known" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+ "@polkadot/util-crypto" "^8.1.2"
+ eventemitter3 "^4.0.7"
+ rxjs "^7.4.0"
+
+"@polkadot/keyring@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-8.3.3.tgz#931c809f9a3b092231b2d319007e02e64bec8f21"
+ integrity sha512-TgoIpaTqn7voT7lDu5W6p0Z+216OImpqtHuaiFy125ekCQurrf9BVIdwp56y5qoFLDAZ5i9gnWHMIgOQ6AJj/Q==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/util" "8.3.3"
+ "@polkadot/util-crypto" "8.3.3"
+
+"@polkadot/networks@8.3.3", "@polkadot/networks@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-8.3.3.tgz#2def73213451f12bc940b0c9ce8942aebbe5d4a8"
+ integrity sha512-yj0DMqmzRZbvgaoZztV3/RPgYJjBhT17Dhu+FX/LUJzVbAF/RfjkzNsJT4Ta4kLDxQMYZq1avUac0ia2j9NcNw==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/util" "8.3.3"
+
+"@polkadot/rpc-core@6.12.1":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-6.12.1.tgz#b5d65589349a0db6edb25fdfd141707a3a5698fa"
+ integrity sha512-Hb08D9zho3SB1UNlUCmG5q0gdgbOx25JKGLDfSYpD/wtD0Y1Sf2X5cfgtMoSYE3USWiRdCu4BxQkXTiRjPjzJg==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/rpc-provider" "6.12.1"
+ "@polkadot/types" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+ rxjs "^7.4.0"
+
+"@polkadot/rpc-provider@6.12.1":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-6.12.1.tgz#1b5b7ceffefa8735010b61ace04f3eece6145622"
+ integrity sha512-uUHD3fLTOeZYWJoc6DQlhz+MJR33rVelasV+OxFY2nSD9MSNXRwQh+9UKDQBnyxw5B4BZ2QaEGfucDeavXmVDw==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/types" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+ "@polkadot/util-crypto" "^8.1.2"
+ "@polkadot/x-fetch" "^8.1.2"
+ "@polkadot/x-global" "^8.1.2"
+ "@polkadot/x-ws" "^8.1.2"
+ eventemitter3 "^4.0.7"
+
+"@polkadot/types-known@6.12.1":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-6.12.1.tgz#2dd3ca4e4aa20b86ef182eb75672690f8c14a84e"
+ integrity sha512-Z8bHpPQy+mqUm0uR1tai6ra0bQIoPmgRcGFYUM+rJtW1kx/6kZLh10HAICjLpPeA1cwLRzaxHRDqH5MCU6OgXw==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/networks" "^8.1.2"
+ "@polkadot/types" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+
+"@polkadot/types@6.12.1", "@polkadot/types@^6.5.2":
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-6.12.1.tgz#e5d6dff997740c3da947fa67abe2e1ec144c4757"
+ integrity sha512-O37cAGUL0xiXTuO3ySweVh0OuFUD6asrd0TfuzGsEp3jAISWdElEHV5QDiftWq8J9Vf8BMgTcP2QLFbmSusxqA==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/types-known" "6.12.1"
+ "@polkadot/util" "^8.1.2"
+ "@polkadot/util-crypto" "^8.1.2"
+ rxjs "^7.4.0"
+
+"@polkadot/util-crypto@8.3.3", "@polkadot/util-crypto@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-8.3.3.tgz#684a04c26bd390a150e83fe34840d9e219a22d24"
+ integrity sha512-kXaT2VTEbJq1wNiV0Dz5qJuVWy7pK+x1QLcyWC+6OFERYO+BCp1Y2bTOcLUeF/gyyR/ZaRMMdTyu0ZbHrwH0xg==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@noble/hashes" "0.5.7"
+ "@noble/secp256k1" "1.3.4"
+ "@polkadot/networks" "8.3.3"
+ "@polkadot/util" "8.3.3"
+ "@polkadot/wasm-crypto" "^4.5.1"
+ "@polkadot/x-bigint" "8.3.3"
+ "@polkadot/x-randomvalues" "8.3.3"
+ ed2curve "^0.3.0"
+ micro-base "^0.10.2"
+ tweetnacl "^1.0.3"
+
+"@polkadot/util@8.3.3", "@polkadot/util@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-8.3.3.tgz#0bd79f771a82a8276b0ca0e713068d23ee53abf2"
+ integrity sha512-8u1NShSHrCFeFvxWL8WAyRN8y1/iPvijqYCDeeHziBxCNBrL3VKDc9GNF11skeay/EKQiCHBSBeAYyyQOpLebA==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-bigint" "8.3.3"
+ "@polkadot/x-global" "8.3.3"
+ "@polkadot/x-textdecoder" "8.3.3"
+ "@polkadot/x-textencoder" "8.3.3"
+ "@types/bn.js" "^4.11.6"
+ bn.js "^4.12.0"
+ ip-regex "^4.3.0"
+
+"@polkadot/wasm-crypto-asmjs@^4.5.1":
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.5.1.tgz#e1025a49e106db11d1187caf65f56c960ea2ad2b"
+ integrity sha512-DOdRiWhxVvmqTvp+E9z1j+Yr0zDOGsDvqnT/eNw0Dl1FVUOImsEa7FKns/urASmcxCVEE1jtUWSnij29jrORMQ==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+
+"@polkadot/wasm-crypto-wasm@^4.5.1":
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.5.1.tgz#063a58ff7ddd939b7886a6a238109a8d2c416e46"
+ integrity sha512-hPwke85HxpgG/RAlwdCE8u5w7bThvWg399mlB+XjogXMxOUWBZSgq2XYbgzROUXx27inK9nStF4Pnc4zJnqs9A==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+
+"@polkadot/wasm-crypto@^4.5.1":
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-4.5.1.tgz#e1ac6d846a0ad8e991cec128994524183ef6e8fd"
+ integrity sha512-Cr21ais3Kq3aedIHZ3J1tjgeD/+K8FCiwEawr0oRywNBSJR8wyuZMePs4swR/6xm8wbBkpqoBVHz/UQHqqQJmA==
+ dependencies:
+ "@babel/runtime" "^7.16.3"
+ "@polkadot/wasm-crypto-asmjs" "^4.5.1"
+ "@polkadot/wasm-crypto-wasm" "^4.5.1"
+
+"@polkadot/x-bigint@8.3.3":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-8.3.3.tgz#3787c4cbfc996bda05c342a80c04bd58a1beaf4b"
+ integrity sha512-2CT25f0zN/uhch3KpM38jtQfFJ1zJCNT41exg49ztsOvm4f6l+6hW91NLhNAZ313B/c6Z4Lm3DalsjAOdBZ8Nw==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+
+"@polkadot/x-fetch@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-8.3.3.tgz#8c81b928868efd573219c231b25f0bcc38107a1b"
+ integrity sha512-+ScnWnt0i1IF+fM9IC+OnjkTi5NonK+ji8q861hwkNCtK2ziibibcD3mGavCA6wZvij4wUTovWEsTc5Su0+KTA==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+ "@types/node-fetch" "^2.5.12"
+ node-fetch "^2.6.7"
+
+"@polkadot/x-global@8.3.3", "@polkadot/x-global@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-8.3.3.tgz#ee2f4a0acd46626bc04174e1bf966478a2feef94"
+ integrity sha512-7DWjcNhTDIpYNiQmLq56o6xYOONr0i6WXdoPUxYrToxZWeWyj/FWaYMfttedLydABPcy87lmvIy8ECp7qCcnyw==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+
+"@polkadot/x-randomvalues@8.3.3":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-8.3.3.tgz#29f855d903fdcac1cb42cacbbc85ca5db7eaccd8"
+ integrity sha512-yxM6GWQholf+vY4dHxKVwtJwDzNUz4UJlL/iN3PA0cuhQ37gxmtJugnNAllcFd8LDNXEN47Ky6Ifw1OHHmZaVw==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+
+"@polkadot/x-textdecoder@8.3.3":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-8.3.3.tgz#d2ef1c63c712f015489025eb95e01a466a5614a7"
+ integrity sha512-oEvFJv/F+fQ336ciRuJJgJFtfyOX6a2Nyr/5GCkiSQjkEIdnBUuO49yXpHNmQsNI0WndLWIEitiVVa9KuDslYw==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+
+"@polkadot/x-textencoder@8.3.3":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-8.3.3.tgz#f59bf164fcd5ca9899c61065f36911cabec7c9f8"
+ integrity sha512-acVsJjmlQ7aluUq8JARY2wJAbf+6dvZNoUrvgzdX/jl5MqvqeIXmX3LX71MyidLt27Z537VDgNzWw8V/524AVQ==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+
+"@polkadot/x-ws@^8.1.2":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-8.3.3.tgz#ab06d87637cb9b86fa341cc95e52f06cc4265d74"
+ integrity sha512-Dd0kscZSb7MULVqo5isPZyqvErvgE7lYIwZ4IA0rNdgUWi3mrJWeeWrzVMxC6nbg6q1ahIEGxxZLMVzeI3u/Ew==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+ "@polkadot/x-global" "8.3.3"
+ "@types/websocket" "^1.0.4"
+ websocket "^1.0.34"
+
+"@tsconfig/node10@^1.0.7":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
+ integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
+
+"@tsconfig/node12@^1.0.7":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
+ integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
+
+"@tsconfig/node14@^1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
+ integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
+
+"@tsconfig/node16@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
+ integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
+
+"@types/bn.js@^4.11.6":
+ version "4.11.6"
+ resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c"
+ integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/chai@^4.2.21":
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc"
+ integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==
+
+"@types/json-schema@^7.0.9":
+ version "7.0.9"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
+ integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
+
+"@types/json5@^0.0.29":
+ version "0.0.29"
+ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
+
+"@types/mocha@^9.0.0":
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.0.tgz#baf17ab2cca3fcce2d322ebc30454bff487efad5"
+ integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==
+
+"@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"
+
+"@types/node@*":
+ version "17.0.14"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.14.tgz#33b9b94f789a8fedd30a68efdbca4dbb06b61f20"
+ integrity sha512-SbjLmERksKOGzWzPNuW7fJM7fk3YXVTFiZWB/Hs99gwhk+/dnrQRPBQjPW9aO+fi1tAffi9PrwFvsmOKmDTyng==
+
+"@types/node@^16.7.10":
+ version "16.11.22"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.22.tgz#e704150225bfc4195f8ce68a7ac8da02b753549a"
+ integrity sha512-DYNtJWauMQ9RNpesl4aVothr97/tIJM8HbyOXJ0AYT1Z2bEjLHyfjOBPAQQVMLf8h3kSShYfNk8Wnto8B2zHUA==
+
+"@types/websocket@^1.0.4":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.5.tgz#3fb80ed8e07f88e51961211cd3682a3a4a81569c"
+ integrity sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==
+ dependencies:
+ "@types/node" "*"
+
+"@typescript-eslint/eslint-plugin@^5.3.1":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.2.tgz#f8c1d59fc37bd6d9d11c97267fdfe722c4777152"
+ integrity sha512-4W/9lLuE+v27O/oe7hXJKjNtBLnZE8tQAFpapdxwSVHqtmIoPB1gph3+ahNwVuNL37BX7YQHyGF9Xv6XCnIX2Q==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.10.2"
+ "@typescript-eslint/type-utils" "5.10.2"
+ "@typescript-eslint/utils" "5.10.2"
+ debug "^4.3.2"
+ functional-red-black-tree "^1.0.1"
+ ignore "^5.1.8"
+ regexpp "^3.2.0"
+ semver "^7.3.5"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/parser@^5.3.1":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.2.tgz#b6076d27cc5499ce3f2c625f5ccde946ecb7db9a"
+ integrity sha512-JaNYGkaQVhP6HNF+lkdOr2cAs2wdSZBoalE22uYWq8IEv/OVH0RksSGydk+sW8cLoSeYmC+OHvRyv2i4AQ7Czg==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.10.2"
+ "@typescript-eslint/types" "5.10.2"
+ "@typescript-eslint/typescript-estree" "5.10.2"
+ debug "^4.3.2"
+
+"@typescript-eslint/scope-manager@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.2.tgz#92c0bc935ec00f3d8638cdffb3d0e70c9b879639"
+ integrity sha512-39Tm6f4RoZoVUWBYr3ekS75TYgpr5Y+X0xLZxXqcZNDWZdJdYbKd3q2IR4V9y5NxxiPu/jxJ8XP7EgHiEQtFnw==
+ dependencies:
+ "@typescript-eslint/types" "5.10.2"
+ "@typescript-eslint/visitor-keys" "5.10.2"
+
+"@typescript-eslint/type-utils@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.10.2.tgz#ad5acdf98a7d2ab030bea81f17da457519101ceb"
+ integrity sha512-uRKSvw/Ccs5FYEoXW04Z5VfzF2iiZcx8Fu7DGIB7RHozuP0VbKNzP1KfZkHBTM75pCpsWxIthEH1B33dmGBKHw==
+ dependencies:
+ "@typescript-eslint/utils" "5.10.2"
+ debug "^4.3.2"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/types@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.2.tgz#604d15d795c4601fffba6ecb4587ff9fdec68ce8"
+ integrity sha512-Qfp0qk/5j2Rz3p3/WhWgu4S1JtMcPgFLnmAKAW061uXxKSa7VWKZsDXVaMXh2N60CX9h6YLaBoy9PJAfCOjk3w==
+
+"@typescript-eslint/typescript-estree@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.2.tgz#810906056cd3ddcb35aa333fdbbef3713b0fe4a7"
+ integrity sha512-WHHw6a9vvZls6JkTgGljwCsMkv8wu8XU8WaYKeYhxhWXH/atZeiMW6uDFPLZOvzNOGmuSMvHtZKd6AuC8PrwKQ==
+ dependencies:
+ "@typescript-eslint/types" "5.10.2"
+ "@typescript-eslint/visitor-keys" "5.10.2"
+ debug "^4.3.2"
+ globby "^11.0.4"
+ is-glob "^4.0.3"
+ semver "^7.3.5"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/utils@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.2.tgz#1fcd37547c32c648ab11aea7173ec30060ee87a8"
+ integrity sha512-vuJaBeig1NnBRkf7q9tgMLREiYD7zsMrsN1DA3wcoMDvr3BTFiIpKjGiYZoKPllfEwN7spUjv7ZqD+JhbVjEPg==
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ "@typescript-eslint/scope-manager" "5.10.2"
+ "@typescript-eslint/types" "5.10.2"
+ "@typescript-eslint/typescript-estree" "5.10.2"
+ eslint-scope "^5.1.1"
+ eslint-utils "^3.0.0"
+
+"@typescript-eslint/visitor-keys@5.10.2":
+ version "5.10.2"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.2.tgz#fdbf272d8e61c045d865bd6c8b41bea73d222f3d"
+ integrity sha512-zHIhYGGGrFJvvyfwHk5M08C5B5K4bewkm+rrvNTKk1/S15YHR+SA/QUF8ZWscXSfEaB8Nn2puZj+iHcoxVOD/Q==
+ dependencies:
+ "@typescript-eslint/types" "5.10.2"
+ eslint-visitor-keys "^3.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"
+ integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
+
+acorn-jsx@^5.3.1:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn-walk@^8.1.1:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
+ integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
+
+acorn@^7.4.0:
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+
+acorn@^8.4.1:
+ version "8.7.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
+ integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
+
+ajv@^6.10.0, ajv@^6.12.4:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ajv@^8.0.1:
+ version "8.9.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18"
+ integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
+ansi-colors@4.1.1, ansi-colors@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+ integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+anymatch@~3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+ integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+arg@^4.1.0:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+ integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+array-includes@^3.1.4:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9"
+ integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.1"
+ get-intrinsic "^1.1.1"
+ is-string "^1.0.7"
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+array.prototype.flat@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13"
+ integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.0"
+
+assertion-error@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
+ integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
+
+astral-regex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
+ integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+axios@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.23.0.tgz#b0fa5d0948a8d1d75e3d5635238b6c4625b05149"
+ integrity sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==
+ dependencies:
+ follow-redirects "^1.14.4"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+bn.js@^4.12.0:
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+ integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+bn.js@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
+ integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^3.0.1, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+browser-stdout@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
+ integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
+
+bufferutil@^4.0.1:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433"
+ integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==
+ dependencies:
+ node-gyp-build "^4.3.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.2"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camelcase@^6.0.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+chai@^4.3.4:
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c"
+ integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==
+ dependencies:
+ assertion-error "^1.1.0"
+ check-error "^1.0.2"
+ deep-eql "^3.0.1"
+ get-func-name "^2.0.0"
+ loupe "^2.3.1"
+ pathval "^1.1.1"
+ type-detect "^4.0.5"
+
+chalk@^2.0.0:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chalk@^4.0.0, chalk@^4.1.0:
+ 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"
+
+check-error@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
+ integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
+
+chokidar@3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+create-require@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
+ integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+
+cross-spawn@^7.0.2:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+d@1, d@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
+ integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
+ dependencies:
+ es5-ext "^0.10.50"
+ type "^1.0.1"
+
+debug@4.3.3, debug@^4.0.1, debug@^4.1.1, debug@^4.3.2:
+ version "4.3.3"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
+ integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
+ dependencies:
+ ms "2.1.2"
+
+debug@^2.2.0, debug@^2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.2.7:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+decamelize@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+ integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
+
+deep-eql@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
+ integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
+ dependencies:
+ type-detect "^4.0.0"
+
+deep-is@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+define-properties@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+ dependencies:
+ object-keys "^1.0.12"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+diff@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+ integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
+
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+doctrine@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+ dependencies:
+ esutils "^2.0.2"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
+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"
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+enquirer@^2.3.5:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
+ integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
+ dependencies:
+ ansi-colors "^4.1.1"
+
+es-abstract@^1.19.0, es-abstract@^1.19.1:
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
+ integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==
+ dependencies:
+ call-bind "^1.0.2"
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ get-intrinsic "^1.1.1"
+ get-symbol-description "^1.0.0"
+ has "^1.0.3"
+ has-symbols "^1.0.2"
+ internal-slot "^1.0.3"
+ is-callable "^1.2.4"
+ is-negative-zero "^2.0.1"
+ is-regex "^1.1.4"
+ is-shared-array-buffer "^1.0.1"
+ is-string "^1.0.7"
+ is-weakref "^1.0.1"
+ object-inspect "^1.11.0"
+ object-keys "^1.1.1"
+ object.assign "^4.1.2"
+ string.prototype.trimend "^1.0.4"
+ string.prototype.trimstart "^1.0.4"
+ unbox-primitive "^1.0.1"
+
+es-to-primitive@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+ integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+ dependencies:
+ is-callable "^1.1.4"
+ is-date-object "^1.0.1"
+ is-symbol "^1.0.2"
+
+es5-ext@^0.10.35, es5-ext@^0.10.50:
+ version "0.10.53"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
+ integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
+ dependencies:
+ es6-iterator "~2.0.3"
+ es6-symbol "~3.1.3"
+ next-tick "~1.0.0"
+
+es6-iterator@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
+es6-symbol@^3.1.1, es6-symbol@~3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
+ integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
+ dependencies:
+ d "^1.0.1"
+ ext "^1.1.2"
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+eslint-config-prettier@^8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a"
+ integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==
+
+eslint-config-standard@^16.0.3:
+ version "16.0.3"
+ 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.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 "^3.2.7"
+ resolve "^1.20.0"
+
+eslint-module-utils@^2.7.2:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
+ integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
+ dependencies:
+ debug "^3.2.7"
+ find-up "^2.1.0"
+
+eslint-plugin-es@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
+ integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
+ dependencies:
+ eslint-utils "^2.0.0"
+ regexpp "^3.0.0"
+
+eslint-plugin-import@^2.25.3:
+ version "2.25.4"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1"
+ integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==
+ dependencies:
+ array-includes "^3.1.4"
+ array.prototype.flat "^1.2.5"
+ debug "^2.6.9"
+ doctrine "^2.1.0"
+ eslint-import-resolver-node "^0.3.6"
+ eslint-module-utils "^2.7.2"
+ has "^1.0.3"
+ is-core-module "^2.8.0"
+ is-glob "^4.0.3"
+ minimatch "^3.0.4"
+ object.values "^1.1.5"
+ resolve "^1.20.0"
+ tsconfig-paths "^3.12.0"
+
+eslint-plugin-node@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
+ integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
+ dependencies:
+ eslint-plugin-es "^3.0.0"
+ eslint-utils "^2.0.0"
+ ignore "^5.1.1"
+ minimatch "^3.0.4"
+ resolve "^1.10.1"
+ semver "^6.1.0"
+
+eslint-plugin-promise@^5.1.1:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz#a596acc32981627eb36d9d75f9666ac1a4564971"
+ integrity sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==
+
+eslint-scope@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
+eslint-utils@^2.0.0, eslint-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+ integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
+ dependencies:
+ eslint-visitor-keys "^1.1.0"
+
+eslint-utils@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
+ integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
+ dependencies:
+ eslint-visitor-keys "^2.0.0"
+
+eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+ integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
+
+eslint-visitor-keys@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
+ integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+
+eslint-visitor-keys@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1"
+ integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==
+
+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"
+ "@humanwhocodes/config-array" "^0.5.0"
+ ajv "^6.10.0"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ enquirer "^2.3.5"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^5.1.1"
+ eslint-utils "^2.1.0"
+ eslint-visitor-keys "^2.0.0"
+ espree "^7.3.1"
+ esquery "^1.4.0"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob-parent "^5.1.2"
+ globals "^13.6.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ js-yaml "^3.13.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.0.4"
+ natural-compare "^1.4.0"
+ optionator "^0.9.1"
+ progress "^2.0.0"
+ regexpp "^3.1.0"
+ semver "^7.2.1"
+ strip-ansi "^6.0.0"
+ strip-json-comments "^3.1.0"
+ table "^6.0.9"
+ text-table "^0.2.0"
+ v8-compile-cache "^2.0.3"
+
+espree@^7.3.0, espree@^7.3.1:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
+ integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
+ dependencies:
+ acorn "^7.4.0"
+ acorn-jsx "^5.3.1"
+ eslint-visitor-keys "^1.3.0"
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
+ integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
+ dependencies:
+ estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+eventemitter3@^4.0.7:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
+ext@^1.1.2:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52"
+ integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==
+ dependencies:
+ type "^2.5.0"
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.2.9:
+ version "3.2.11"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
+ integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+fastq@^1.6.0:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
+ integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+ dependencies:
+ reusify "^1.0.4"
+
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+ dependencies:
+ flat-cache "^3.0.4"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+find-up@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+find-up@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+ integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
+ dependencies:
+ locate-path "^2.0.0"
+
+flat-cache@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
+ integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
+ dependencies:
+ flatted "^3.1.0"
+ rimraf "^3.0.2"
+
+flat@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+ integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
+flatted@^3.1.0:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
+ integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
+
+follow-redirects@^1.14.4:
+ version "1.14.7"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
+ integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
+
+form-data@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
+ integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@~2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+functional-red-black-tree@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+ integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-func-name@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
+ integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+
+get-symbol-description@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
+ integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob@7.2.0, glob@^7.1.3:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
+ integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+globals@^13.6.0, globals@^13.9.0:
+ version "13.12.1"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.1.tgz#ec206be932e6c77236677127577aa8e50bf1c5cb"
+ integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==
+ dependencies:
+ type-fest "^0.20.2"
+
+globby@^11.0.4:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
+
+growl@1.10.5:
+ version "1.10.5"
+ resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
+ integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
+
+has-bigints@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
+ integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-symbols@^1.0.1, has-symbols@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
+ integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
+
+has-tostringtag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+ dependencies:
+ has-symbols "^1.0.2"
+
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
+he@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+ignore@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
+ integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+
+import-fresh@^3.0.0, import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+internal-slot@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
+ integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
+ dependencies:
+ get-intrinsic "^1.1.0"
+ has "^1.0.3"
+ side-channel "^1.0.4"
+
+ip-regex@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
+ integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
+
+is-bigint@^1.0.1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+ integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+ dependencies:
+ has-bigints "^1.0.1"
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-boolean-object@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+ integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-callable@^1.1.4, is-callable@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
+ integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
+
+is-core-module@^2.8.0, is-core-module@^2.8.1:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
+ integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
+ dependencies:
+ has "^1.0.3"
+
+is-date-object@^1.0.1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+ integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-negative-zero@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
+ integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
+
+is-number-object@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0"
+ integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-plain-obj@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+ integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
+
+is-regex@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-shared-array-buffer@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
+ integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
+
+is-string@^1.0.5, is-string@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+ integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-symbol@^1.0.2, is-symbol@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+ integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+ dependencies:
+ has-symbols "^1.0.2"
+
+is-typedarray@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-unicode-supported@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+ integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
+is-weakref@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
+ integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+ dependencies:
+ call-bind "^1.0.2"
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+js-yaml@^3.13.1:
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+json5@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+ integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ dependencies:
+ minimist "^1.2.0"
+
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
+locate-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
+ dependencies:
+ p-locate "^2.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+lodash.truncate@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
+ integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
+
+log-symbols@4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+ integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+ dependencies:
+ chalk "^4.1.0"
+ is-unicode-supported "^0.1.0"
+
+loupe@^2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.2.tgz#799a566ba5aa8d11b93ddccc92c569bbae7e9490"
+ integrity sha512-QgVamnvj0jX1LMPlCAq0MK6hATORFtGqHoUKXTkwNe13BqlN6aePQCKnnTcFvdDYEEITcJ+gBl4mTW7YJtJbyQ==
+ dependencies:
+ get-func-name "^2.0.0"
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+make-error@^1.1.1:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
+ integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
+
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micro-base@^0.10.2:
+ version "0.10.2"
+ resolved "https://registry.yarnpkg.com/micro-base/-/micro-base-0.10.2.tgz#f6f9f0bd949ce511883e5a99f9147d80ddc32f5a"
+ integrity sha512-lqqJrT7lfJtDmmiQ4zRLZuIJBk96t0RAc5pCrrWpL9zDeH5i/SUL85mku9HqzTI/OCZ8EQ3aicbMW+eK5Nyu5w==
+
+micromatch@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
+ integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
+ dependencies:
+ braces "^3.0.1"
+ picomatch "^2.2.3"
+
+mime-db@1.51.0:
+ version "1.51.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
+ integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
+
+mime-types@^2.1.12:
+ version "2.1.34"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24"
+ integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==
+ dependencies:
+ mime-db "1.51.0"
+
+minimatch@3.0.4, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@^1.2.0:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+
+mocha@^9.1.1:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.0.tgz#2bfba73d46e392901f877ab9a47b7c9c5d0275cc"
+ integrity sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==
+ dependencies:
+ "@ungap/promise-all-settled" "1.1.2"
+ ansi-colors "4.1.1"
+ browser-stdout "1.3.1"
+ chokidar "3.5.3"
+ debug "4.3.3"
+ diff "5.0.0"
+ escape-string-regexp "4.0.0"
+ find-up "5.0.0"
+ glob "7.2.0"
+ growl "1.10.5"
+ he "1.2.0"
+ js-yaml "4.1.0"
+ log-symbols "4.1.0"
+ minimatch "3.0.4"
+ ms "2.1.3"
+ nanoid "3.2.0"
+ serialize-javascript "6.0.0"
+ strip-json-comments "3.1.1"
+ supports-color "8.1.1"
+ which "2.0.2"
+ workerpool "6.2.0"
+ yargs "16.2.0"
+ yargs-parser "20.2.4"
+ yargs-unparser "2.0.0"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@2.1.3, ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nanoid@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
+ integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
+next-tick@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
+ integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+
+node-fetch@^2.6.7:
+ version "2.6.7"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
+ integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-gyp-build@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
+ integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+object-inspect@^1.11.0, object-inspect@^1.9.0:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
+ integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
+
+object-keys@^1.0.12, object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object.assign@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+ integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+ has-symbols "^1.0.1"
+ object-keys "^1.1.1"
+
+object.values@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac"
+ integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.1"
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+optionator@^0.9.1:
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+ integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
+ dependencies:
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+ word-wrap "^1.2.3"
+
+p-limit@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
+ dependencies:
+ p-try "^1.0.0"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+ integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
+ dependencies:
+ p-limit "^1.1.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+ integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pathval@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+ integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+progress@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+regenerator-runtime@^0.13.4:
+ version "0.13.9"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
+ integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
+
+regexpp@^3.0.0, regexpp@^3.1.0, regexpp@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
+ integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve@^1.10.1, resolve@^1.20.0:
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
+ integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
+ dependencies:
+ is-core-module "^2.8.1"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+rxjs@^7.4.0:
+ version "7.5.2"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b"
+ integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==
+ dependencies:
+ tslib "^2.1.0"
+
+safe-buffer@^5.1.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+semver@^6.1.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+ integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+semver@^7.2.1, semver@^7.3.5:
+ version "7.3.5"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+ dependencies:
+ lru-cache "^6.0.0"
+
+serialize-javascript@6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
+ integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
+ dependencies:
+ randombytes "^2.1.0"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+ dependencies:
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
+
+signer-interface@^0.1.0:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/signer-interface/-/signer-interface-0.1.5.tgz#108de6122b7f5f1db33685cb2da4cfe7e293c10e"
+ integrity sha512-keWejhBVGOsVACRqnu03pLOKhkwfweFlmHwu560P1GzR3NbsyVK0eFQxhkcupr3h57TjKam/rR0ISrh4/Ewc/g==
+ dependencies:
+ axios "^0.23.0"
+ bn.js "^5.2.0"
+ store "^2.0.12"
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+slice-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
+ integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
+ dependencies:
+ ansi-styles "^4.0.0"
+ astral-regex "^2.0.0"
+ is-fullwidth-code-point "^3.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+store@^2.0.12:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/store/-/store-2.0.12.tgz#8c534e2a0b831f72b75fc5f1119857c44ef5d593"
+ integrity sha1-jFNOKguDH3K3X8XxEZhXxE711ZM=
+
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string.prototype.trimend@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80"
+ integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+
+string.prototype.trimstart@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"
+ integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
+strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+supports-color@8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+table@^6.0.9:
+ version "6.8.0"
+ resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
+ integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==
+ dependencies:
+ ajv "^8.0.1"
+ lodash.truncate "^4.4.2"
+ slice-ansi "^4.0.0"
+ string-width "^4.2.3"
+ strip-ansi "^6.0.1"
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
+
+ts-node@^10.2.1:
+ version "10.4.0"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7"
+ integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==
+ dependencies:
+ "@cspotcode/source-map-support" "0.7.0"
+ "@tsconfig/node10" "^1.0.7"
+ "@tsconfig/node12" "^1.0.7"
+ "@tsconfig/node14" "^1.0.0"
+ "@tsconfig/node16" "^1.0.2"
+ acorn "^8.4.1"
+ acorn-walk "^8.1.1"
+ arg "^4.1.0"
+ create-require "^1.1.0"
+ diff "^4.0.1"
+ make-error "^1.1.1"
+ yn "3.1.1"
+
+tsconfig-paths@^3.12.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b"
+ integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==
+ dependencies:
+ "@types/json5" "^0.0.29"
+ json5 "^1.0.1"
+ minimist "^1.2.0"
+ strip-bom "^3.0.0"
+
+tslib@^1.8.1:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
+ integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
+
+tsutils@^3.21.0:
+ version "3.21.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
+ integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
+ dependencies:
+ tslib "^1.8.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==
+
+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"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
+type-detect@^4.0.0, type-detect@^4.0.5:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
+ integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
+
+type@^2.5.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f"
+ integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==
+
+typedarray-to-buffer@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+ dependencies:
+ is-typedarray "^1.0.0"
+
+typescript@^4.4.2, typescript@^4.4.4:
+ version "4.5.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
+ integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
+
+unbox-primitive@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
+ integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
+ dependencies:
+ function-bind "^1.1.1"
+ has-bigints "^1.0.1"
+ has-symbols "^1.0.2"
+ which-boxed-primitive "^1.0.2"
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+utf-8-validate@^5.0.2:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.8.tgz#4a735a61661dbb1c59a0868c397d2fe263f14e58"
+ integrity sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==
+ dependencies:
+ node-gyp-build "^4.3.0"
+
+v8-compile-cache@^2.0.3:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
+ integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
+
+websocket@^1.0.34:
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111"
+ integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==
+ dependencies:
+ bufferutil "^4.0.1"
+ debug "^2.2.0"
+ es5-ext "^0.10.50"
+ typedarray-to-buffer "^3.1.5"
+ utf-8-validate "^5.0.2"
+ yaeti "^0.0.6"
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+which-boxed-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
+ integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+ dependencies:
+ is-bigint "^1.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ is-symbol "^1.0.3"
+
+which@2.0.2, which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+word-wrap@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+ integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+
+workerpool@6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
+ integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yaeti@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
+ integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yargs-parser@20.2.4:
+ version "20.2.4"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+ integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs-unparser@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+ integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
+ dependencies:
+ camelcase "^6.0.0"
+ decamelize "^4.0.0"
+ flat "^5.0.2"
+ is-plain-obj "^2.1.0"
+
+yargs@16.2.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ 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"
+ integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==