diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..9f8d3f7
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+src/scripts
\ No newline at end of file
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..9534218
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,29 @@
+PORT: 5002
+ENV: 'prod'
+
+#Chain to run dispute on when none specified
+CHAINID= 1
+#Account to send the dispute from, must be loaded with gas & enough dispute token
+DISPUTE_BOT_PRIVATE_KEY= ""
+
+#Polygon
+PROVIDER_137= ""
+#Optimism
+PROVIDER_10= ""
+#Ethereum
+PROVIDER_1= ""
+#Arbitrum one
+PROVIDER_42161= ""
+#Polygon zkEVM
+PROVIDER_1101= ""
+#Base
+PROVIDER_8453= ""
+
+#Github auth token (used to generate a gist for diff tables)
+KEEPER_GITHUB_AUTH_TOKEN= ""
+
+#Discord Bot Token (https://discord.com/developers/applications)
+DISCORD_TOKEN= ""
+#Discord channels to log to
+DISCORD_LOG_CHANNEL=""
+DISCORD_ALERT_CHANNEL=""
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..4157b74
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,22 @@
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ plugins: ['@typescript-eslint', 'prettier', 'simple-import-sort'],
+ extends: ['plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended'],
+ rules: {
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ 'prettier/prettier': 'error',
+ '@typescript-eslint/no-explicit-any': 'off',
+ 'simple-import-sort/imports': 'error',
+ 'simple-import-sort/exports': 'error',
+ 'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 1 }],
+ 'max-len': [
+ 'error',
+ {
+ code: 180,
+ ignoreComments: true,
+ ignoreTrailingComments: true,
+ ignoreStrings: true,
+ },
+ ],
+ },
+};
diff --git a/.gcloudignore b/.gcloudignore
new file mode 100644
index 0000000..4d7d693
--- /dev/null
+++ b/.gcloudignore
@@ -0,0 +1,17 @@
+# This file specifies files that are *not* uploaded to Google Cloud
+# using gcloud. It follows the same syntax as .gitignore, with the addition of
+# "#!include" directives (which insert the entries of the given .gitignore-style
+# file at that point).
+#
+# For more information, run:
+# $ gcloud topic gcloudignore
+#
+.gcloudignore
+# If you would like to upload your .git directory, .gitignore file or files
+# from your .gitignore file, remove the corresponding line
+# below:
+.git
+.gitignore
+
+# Node.js dependencies:
+node_modules/
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..4595975
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+# .github/workflows/ci.yml
+
+name: CI
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ build-and-test:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [14.x] # Use the version of Node.js that matches your project's requirements
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: 16
+
+ - name: Install dependencies
+ run: yarn install --frozen-lockfile
+
+ - name: Compile TypeScript
+ run: yarn tsc --noEmit
+
+ - name: Run tests
+ run: yarn test
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..26f68c8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+node_modules
+yarn-error.lock
+build
+src/script/debug.ts
+.env
+.env.local
+.vscode
+.npmrc
+.DS_Store
+secrets*
+config
+staging-app-polygon.yaml
+report.txt
+
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..59f723c
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "printWidth": 140
+}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..4c254ff
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+contact@angle.money.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..de7db21
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,9 @@
+# Submit a change or a new feature
+
+First of all thank you for your interest in this repository!
+
+This is only the beginning of the Angle protocol and codebase, and anyone is welcome to improve it.
+
+To submit some code, please work in a fork, reach out to explain what you've done and open a Pull Request from your fork.
+
+Feel free to reach out in the [#developers channel](https://discord.gg/HcRB8QMeKU) of our Discord Server if you need a hand!
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a020e7d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,29 @@
+# Use an official Node.js runtime as the builder image
+FROM node:16-alpine
+
+# Set the working directory inside the container
+WORKDIR /app
+
+# Copy the package.json file to the container
+COPY package.json ./
+
+# Copy the yarn.lock file to the container
+COPY yarn.lock ./
+
+# Install the app dependencies
+RUN yarn install
+
+# Copy the tsconfig.json to be able to compile the typescript
+COPY tsconfig.json ./
+
+# Copy the code
+COPY ./src ./src
+
+# Build the app
+RUN yarn build
+
+# Expose the port that the app listens on
+EXPOSE 5002
+
+# Launch the app for local development (hot reloading)
+CMD ["yarn", "start"]
diff --git a/Dockerfile.local b/Dockerfile.local
new file mode 100644
index 0000000..cc8b949
--- /dev/null
+++ b/Dockerfile.local
@@ -0,0 +1,24 @@
+# Use an official Node.js runtime as the builder image
+FROM node:16-alpine
+
+WORKDIR /app
+
+# Copy the package.json file to the container
+COPY package.json ./
+
+# Copy the yarn.lock file to the container
+COPY yarn.lock ./
+
+# Yalc for local package development
+# COPY ./.yalc ./.yalc
+
+# Install the app dependencies
+RUN yarn install
+
+# Copy the tsconfig.json to be able to compile the typescript
+COPY tsconfig.json ./
+
+EXPOSE 5002
+
+# Launch the app for local development (hot reloading)
+CMD ["yarn", "start:local"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..15813e1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,93 @@
+# Merkl Dispute bot
+
+## How does it work?
+
+The bot runs when a dispute period is ongoing and checks if the merkle root submitted on chain is correct.
+If the data is incorrect or it is unable to fetch enough data to be able to make the checks, it will send a dispute.
+
+![image](./docs/bot-decision-tree.png)
+
+## What is a dispute ?
+
+A dispute is a halt of the merkl root update on the contract, which allows the DAO to come in and resolve the conflict.
+This mechanism can prevent a malicious or accidental update of the new reward data which might be invalid.
+
+![image](./docs/dispute-process.png)
+
+## Pre-requisites
+
+You must provide some necessary environment variables (see [.env.example](./.env.example)):
+
+```env
+PORT= 5002
+ENV= 'prod'
+
+CHAINID= 1
+DISPUTE_BOT_PRIVATE_KEY= ""
+PROVIDER_137= ""
+PROVIDER_10= ""
+PROVIDER_1= ""
+PROVIDER_42161= ""
+PROVIDER_1101= ""
+```
+
+## Run the bot
+
+Install the dependencies and build the bot:
+
+```bash
+yarn install
+yarn build
+```
+
+```bash
+yarn bot diff --chain 1 --from 1695734659 --to 1695821059 --gist
+```
+
+### Every n seconds
+
+Run the bot periodically (recommended interval is 1 hour):
+
+```bash
+yarn bot watch --chain --time
+```
+
+### As a one-time check
+
+You can also run the bot once to try to dispute the latest block or check the bot against a previous block:
+
+```bash
+yarn bot run --chain
+yarn bot run --chain --block
+```
+
+### Compare two points in time
+
+You can compare two points in time and generate a diff table, using `--gist` requires `KEEPER_GITHUB_AUTH_TOKEN` env variable.
+
+```bash
+yarn bot diff --chain --from --to
+yarn bot diff --chain --from --to --gist
+```
+
+### As a server
+
+Run the bot as an Express server to call a dispute check from an HTTP request:
+
+```bash
+yarn bot serve
+```
+
+`chain` and `blockNumber` parameters are optional, if not provided, the chain will be set from the environement variable `CHAINID`, the blockNumber as the latest one.
+
+```http
+GET http://localhost:5002/
+GET http://localhost:5002//
+GET http://localhost:5002//
+```
+
+## Optional logging tools
+
+The bot supports Discord logging and gist creation for the diff tables, enable those features by providing env variables `DISCORD_TOKEN`, `DISCORD_LOG_CHANNEL`, `DISCORD_ALERT_CHANNEL` and `KEEPER_GITHUB_AUTH_TOKEN` respectively.
+
+![image](./docs/discord-logging.png)
diff --git a/cloudrun.yaml b/cloudrun.yaml
new file mode 100644
index 0000000..c85ead3
--- /dev/null
+++ b/cloudrun.yaml
@@ -0,0 +1,85 @@
+apiVersion: serving.knative.dev/v1
+kind: Service
+metadata:
+ generation: 4
+ labels:
+ cloud.googleapis.com/location: europe-west1
+ name: merkl-dispute-base # metadata.name
+spec:
+ template:
+ metadata:
+ annotations:
+ autoscaling.knative.dev/maxScale: '2'
+ autoscaling.knative.dev/minScale: '0'
+ spec:
+ containerConcurrency: '1'
+ containers:
+ - env:
+ - name: CHAINID
+ value: "8453" # spec.template.spec.containers.env[0].value
+ - name: ENV
+ value: dev
+ - name: DISPUTE_BOT_PRIVATE_KEY
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: DISPUTE_BOT_PRIVATE_KEY
+ - name: PROVIDER_1
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_1
+ - name: PROVIDER_10
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_10
+ - name: PROVIDER_137
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_137
+ - name: PROVIDER_42161
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_42161
+ - name: PROVIDER_1101
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_1101
+ - name: PROVIDER_8453
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_8453
+ - name: DISCORD_TOKEN
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: DISCORD_TOKEN
+ - name: KEEPER_GITHUB_AUTH_TOKEN
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: KEEPER_GITHUB_AUTH_TOKEN
+ image: europe-west1-docker.pkg.dev/merkl-dispute-2/registry/merkl-dispute:v0.0.4 # spec.template.spec.containers.image
+ ports:
+ - containerPort: '5002'
+ name: http1
+ resources:
+ limits:
+ cpu: '1'
+ memory: 1Gi
+ startupProbe:
+ failureThreshold: 1
+ periodSeconds: 240
+ tcpSocket:
+ port: '5002'
+ timeoutSeconds: 240
+ serviceAccountName: merkl-dispute-sa@merkl-dispute-2.iam.gserviceaccount.com # spec.template.spec.serviceAccountName
+ timeoutSeconds: '600'
+ traffic:
+ - latestRevision: true
+ percent: 100
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..1bb12e5
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+version: '3.8'
+services:
+ merkl-dispute:
+ image: merkl-dispute
+ build:
+ context: .
+ dockerfile: Dockerfile.local
+ env_file:
+ - .env
+ environment:
+ - CHAINID=1
+ - PORT=5002
+ ports:
+ - '5002:5002'
+ volumes:
+ - ./src:/app/src
+ - ~/docker/volumes/yalc:/app/yalc
diff --git a/docs/bot-decision-tree.png b/docs/bot-decision-tree.png
new file mode 100644
index 0000000..da6cd17
Binary files /dev/null and b/docs/bot-decision-tree.png differ
diff --git a/docs/discord-logging.png b/docs/discord-logging.png
new file mode 100644
index 0000000..313763d
Binary files /dev/null and b/docs/discord-logging.png differ
diff --git a/docs/dispute-process.png b/docs/dispute-process.png
new file mode 100644
index 0000000..0740925
Binary files /dev/null and b/docs/dispute-process.png differ
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..3f17c4f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "merkl-dispute",
+ "version": "1.0.0",
+ "main": "index.js",
+ "author": "picodes ",
+ "license": "MIT",
+ "scripts": {
+ "bot:hot": "yarn ts-node ./src/index.ts",
+ "bot": "node ./build/index.js",
+ "start": "node ./build/index.js serve",
+ "dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts serve",
+ "build": "tsc -p .",
+ "lint": "eslint src --fix",
+ "test": "mocha --require ts-node/register tests/**/*.test.ts",
+ "update": "chmod +x ./scripts/deploy.sh && ./scripts/deploy.sh",
+ "deploy": "chmod +x ./scripts/publishAndDeploy.sh && ./scripts/publishAndDeploy.sh",
+ "gcp-build": "yarn build",
+ "merge": "git checkout staging && git pull origin staging && yarn && git checkout main && git pull origin main && git merge --ff-only staging && git push --force-with-lease origin main",
+ "start:local": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts serve",
+ "publish-image": "chmod +x ./scripts/publish.sh && ./scripts/publish.sh"
+ },
+ "dependencies": {
+ "@angleprotocol/sdk": "^3.0.118",
+ "@google-cloud/secret-manager": "^4.2.2",
+ "@octokit/rest": "19.0.13",
+ "@types/chai": "^4.3.6",
+ "@types/mocha": "^10.0.1",
+ "axios": "^0.27.2",
+ "chai": "^4.3.8",
+ "chalk": "^4.1.0",
+ "commander": "^11.0.0",
+ "discord.js": "^14.7.1",
+ "dotenv": "^16.0.1",
+ "ethers": "^5.7.2",
+ "express": "^4.18.1",
+ "graphql-request": "^6.1.0",
+ "keccak256": "^1.0.6",
+ "merkletreejs": "^0.3.10",
+ "moment": "^2.29.4"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.13",
+ "@types/graceful-fs": "^4.1.5",
+ "@types/node": "^16.9.6",
+ "@typescript-eslint/eslint-plugin": "^5.2.0",
+ "@typescript-eslint/parser": "^5.2.0",
+ "eslint": "^8.1.0",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-prettier": "^4.0.0",
+ "eslint-plugin-simple-import-sort": "^7.0.0",
+ "mocha": "^10.2.0",
+ "nodemon": "^2.0.22",
+ "prettier": "^2.4.1",
+ "ts-node": "^10.4.0",
+ "typescript": "^4.4.4"
+ }
+}
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
new file mode 100755
index 0000000..352e37d
--- /dev/null
+++ b/scripts/deploy.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+account=$1
+version=$2
+
+chainKeys=("polygon" "ethereum" "optimism" "arbitrum" "zkevm" "base")
+chainValues=(137 1 10 42161 1101 8453)
+
+for ((i=0; i<${#chainKeys[@]}; i++))
+do
+ chain=${chainKeys[$i]}
+
+ echo "Updating merkl-dispute-${chain} to $account with version $version"
+
+ cp scripts/templates/cloudrun.yaml ./cloudrun.yaml
+
+ export APP_NAME=merkl-dispute-$chain
+ yq -i '.metadata.name=strenv(APP_NAME)' ./cloudrun.yaml
+
+ export IMAGE=europe-west1-docker.pkg.dev/$account/registry/merkl-dispute:$version
+ yq -i '.spec.template.spec.containers[0].image= strenv(IMAGE)' ./cloudrun.yaml
+
+ export CHAIN_ID=${chainValues[$i]}
+ yq -i '.spec.template.spec.containers[0].env[0].value= strenv(CHAIN_ID)' ./cloudrun.yaml
+
+ export SERVICE_ACCOUNT=merkl-dispute-sa@$account.iam.gserviceaccount.com
+ yq -i '.spec.template.spec.serviceAccountName= strenv(SERVICE_ACCOUNT)' ./cloudrun.yaml
+
+ gcloud run services replace ./cloudrun.yaml --platform managed --region europe-west1
+ rm ./cloudrun.yaml
+done
diff --git a/scripts/publish.sh b/scripts/publish.sh
new file mode 100755
index 0000000..e94debf
--- /dev/null
+++ b/scripts/publish.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+account=$1
+version=$2
+
+echo "Building docker image"
+docker build -t merkl-dispute:latest --platform linux/amd64 .
+
+docker tag merkl-dispute:latest europe-west1-docker.pkg.dev/$account/registry/merkl-dispute:$version
+
+echo "Login to docker registry $account"
+
+gcloud auth configure-docker europe-west1-docker.pkg.dev
+
+echo "Pushing to docker registry 1"
+docker push europe-west1-docker.pkg.dev/$account/registry/merkl-dispute:$version
+docker push europe-west1-docker.pkg.dev/merkl-dispute-2/registry/merkl-dispute:v0.0.2
diff --git a/scripts/publishAndDeploy.sh b/scripts/publishAndDeploy.sh
new file mode 100755
index 0000000..bc3cfbd
--- /dev/null
+++ b/scripts/publishAndDeploy.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+echo "Please enter the version to publish in the following format: vX.X.X "
+read version
+
+echo "Please enter the account to deploy to: (merkl-dispute-1 or merkl-dispute-2)"
+read account
+
+sh scripts/publish.sh $account $version
+bash scripts/deploy.sh $account $version
diff --git a/scripts/templates/cloudrun.yaml b/scripts/templates/cloudrun.yaml
new file mode 100644
index 0000000..a8063ab
--- /dev/null
+++ b/scripts/templates/cloudrun.yaml
@@ -0,0 +1,85 @@
+apiVersion: serving.knative.dev/v1
+kind: Service
+metadata:
+ generation: 4
+ labels:
+ cloud.googleapis.com/location: europe-west1
+ name: CHANGE_ME # metadata.name
+spec:
+ template:
+ metadata:
+ annotations:
+ autoscaling.knative.dev/maxScale: '2'
+ autoscaling.knative.dev/minScale: '0'
+ spec:
+ containerConcurrency: '1'
+ containers:
+ - env:
+ - name: CHAINID
+ value: CHANGE_ME # spec.template.spec.containers.env[0].value
+ - name: ENV
+ value: dev
+ - name: DISPUTE_BOT_PRIVATE_KEY
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: DISPUTE_BOT_PRIVATE_KEY
+ - name: PROVIDER_1
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_1
+ - name: PROVIDER_10
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_10
+ - name: PROVIDER_137
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_137
+ - name: PROVIDER_42161
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_42161
+ - name: PROVIDER_1101
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_1101
+ - name: PROVIDER_8453
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: PROVIDER_8453
+ - name: DISCORD_TOKEN
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: DISCORD_TOKEN
+ - name: KEEPER_GITHUB_AUTH_TOKEN
+ valueFrom:
+ secretKeyRef:
+ key: latest
+ name: KEEPER_GITHUB_AUTH_TOKEN
+ image: CHANGE_ME # spec.template.spec.containers.image
+ ports:
+ - containerPort: '5002'
+ name: http1
+ resources:
+ limits:
+ cpu: '1'
+ memory: 1Gi
+ startupProbe:
+ failureThreshold: 1
+ periodSeconds: 240
+ tcpSocket:
+ port: '5002'
+ timeoutSeconds: 240
+ serviceAccountName: CHANGE_ME # spec.template.spec.serviceAccountName
+ timeoutSeconds: '600'
+ traffic:
+ - latestRevision: true
+ percent: 100
diff --git a/src/bot/context.ts b/src/bot/context.ts
new file mode 100644
index 0000000..35ceeda
--- /dev/null
+++ b/src/bot/context.ts
@@ -0,0 +1,46 @@
+import { ChainId, registry } from '@angleprotocol/sdk';
+
+import ConsoleLogger from '../helpers/logger/ConsoleLogger';
+import DiscordWebhookLogger from '../helpers/logger/DiscordWebhookLogger';
+import Logger from '../helpers/logger/Logger';
+import Loggers from '../helpers/logger/Loggers';
+import GithubRootsProvider from '../providers/merkl-roots/GithubRootsProvider';
+import MerkleRootsProvider from '../providers/merkl-roots/MerkleRootsProvider';
+import OnChainProvider from '../providers/on-chain/OnChainProvider';
+import RpcProvider from '../providers/on-chain/RpcProvider';
+
+export interface DisputeContext {
+ chainId: ChainId;
+ onChainProvider: OnChainProvider;
+ merkleRootsProvider: MerkleRootsProvider;
+ blockNumber?: number;
+ logger?: Logger;
+ uploadDiffTable?: boolean;
+}
+
+const NETWORKS: { [chainId: number]: string } = [];
+for (const c of Object.keys(ChainId)) {
+ try {
+ NETWORKS[c] = process.env[`PROVIDER_${c}`];
+ } catch {}
+}
+
+export const defaultContext = (chainId: number, blockNumber?: number): DisputeContext => {
+ const merklRegistry = registry(chainId).Merkl;
+ const loggers = [new ConsoleLogger()];
+ const discordAvailable = !!process.env['DISCORD_TOKEN'];
+ const onChainProvider = new RpcProvider(NETWORKS[chainId], merklRegistry.Distributor, merklRegistry.DistributionCreator);
+
+ blockNumber && onChainProvider.setBlock(blockNumber);
+
+ if (discordAvailable) loggers.push(new DiscordWebhookLogger());
+
+ return {
+ chainId,
+ blockNumber,
+ onChainProvider,
+ merkleRootsProvider: new GithubRootsProvider('https://raw.githubusercontent.com/AngleProtocol/merkl-rewards/main/', chainId),
+ logger: new Loggers(loggers),
+ uploadDiffTable: true,
+ };
+};
diff --git a/src/bot/dispute.ts b/src/bot/dispute.ts
new file mode 100644
index 0000000..7e180c9
--- /dev/null
+++ b/src/bot/dispute.ts
@@ -0,0 +1,72 @@
+import { ChainId } from '@angleprotocol/sdk';
+import { utils, Wallet } from 'ethers';
+
+import { BotError, Result, Step } from '../types/bot';
+
+export const createSigner: Step = async (_, report) => {
+ try {
+ const privateKey = process.env.DISPUTE_BOT_PRIVATE_KEY;
+
+ if (!privateKey || privateKey === '') throw 'Signer not provided';
+
+ const signer = new Wallet(privateKey);
+
+ return Result.Success({ ...report, disputeReport: { signer } });
+ } catch (reason) {
+ return Result.Error({ code: BotError.KeeperCreate, reason, report });
+ }
+};
+
+export const approveDisputeStake: Step = async ({ onChainProvider, chainId }, report) => {
+ try {
+ const { disputeToken, disputeAmount } = report?.params;
+ const { signer } = report?.disputeReport;
+
+ const approval = await onChainProvider.fetchApproval(signer.address, disputeToken);
+
+ if (approval >= disputeAmount) return Result.Success(report);
+
+ const txnOverrides =
+ chainId === ChainId.POLYGON
+ ? {
+ maxPriorityFeePerGas: utils.parseUnits('50', 9),
+ maxFeePerGas: utils.parseUnits('350', 9),
+ }
+ : {};
+
+ const approveReceipt = await onChainProvider.sendApproveTxn(signer, disputeToken, disputeAmount, txnOverrides);
+
+ return Result.Success({ ...report, disputeReport: { ...report.disputeReport, approveReceipt } });
+ } catch (err) {
+ return Result.Error({
+ code: BotError.KeeperApprove,
+ reason: err?.reason ?? "Couldn't send transaction",
+ report,
+ });
+ }
+};
+
+export const disputeTree: Step = async ({ onChainProvider, chainId }, report) => {
+ try {
+ const { disputeToken, disputeAmount } = report?.params;
+ const { signer } = report?.disputeReport;
+
+ const txnOverrides =
+ chainId === ChainId.POLYGON
+ ? {
+ maxPriorityFeePerGas: utils.parseUnits('50', 9),
+ maxFeePerGas: utils.parseUnits('350', 9),
+ }
+ : {};
+
+ const disputeReceipt = await onChainProvider.sendApproveTxn(signer, disputeToken, disputeAmount, txnOverrides);
+
+ return Result.Success({ ...report, disputeReport: { ...report.disputeReport, disputeReceipt } });
+ } catch (err) {
+ return Result.Error({
+ code: BotError.KeeperApprove,
+ reason: err?.reason ?? "Couldn't send transaction",
+ report,
+ });
+ }
+};
diff --git a/src/bot/runner.ts b/src/bot/runner.ts
new file mode 100644
index 0000000..81ef782
--- /dev/null
+++ b/src/bot/runner.ts
@@ -0,0 +1,206 @@
+import moment from 'moment';
+
+import { NULL_ADDRESS } from '../constants';
+import { buildMerklTree } from '../helpers';
+import createDiffTable from '../helpers/diffTable';
+import { BotError, MerklReport, Resolver, Result, Step, StepResult } from '../types/bot';
+import { HoldersReport } from '../types/holders';
+import { DisputeContext } from './context';
+import { approveDisputeStake, createSigner, disputeTree } from './dispute';
+import { validateClaims, validateHolders } from './validity';
+
+export const checkBlockTime: Step = async (context, report) => {
+ try {
+ const { onChainProvider, blockNumber, logger } = context;
+ const timestamp = !!blockNumber ? await onChainProvider.fetchTimestampAt(blockNumber) : moment().unix();
+ const block = blockNumber ?? (await onChainProvider.mountLastBlock());
+
+ logger?.context(context, timestamp);
+
+ return Result.Success({ ...report, blockNumber: block, startTime: timestamp });
+ } catch (err) {
+ return Result.Error({ code: BotError.BlocktimeFetch, reason: `Unable to get block: ${err}`, report });
+ }
+};
+
+export const checkOnChainParams: Step = async ({ onChainProvider, logger }, report) => {
+ try {
+ onChainProvider.setBlock(report.blockNumber);
+ const params = await onChainProvider.fetchOnChainParams();
+
+ logger?.onChainParams(params, report.startTime);
+
+ return Result.Success({ ...report, params });
+ } catch (err) {
+ return Result.Error({ code: BotError.OnChainFetch, reason: `Unable to get on-chain params: ${err}`, report });
+ }
+};
+
+export const checkDisputeWindow: Step = async (context, report) => {
+ try {
+ const { startTime } = report;
+ const { disputer, disputeToken, endOfDisputePeriod } = report?.params;
+
+ if (!!disputer && disputer !== NULL_ADDRESS) return Result.Exit({ reason: 'Already disputed', report });
+ else if (disputeToken === NULL_ADDRESS) return Result.Exit({ reason: 'No dispute token set', report });
+ else if (endOfDisputePeriod <= startTime) return Result.Exit({ reason: 'Not in dispute period', report });
+ return Result.Success(report);
+ } catch (err) {
+ return Result.Error({ code: BotError.OnChainFetch, reason: `Unable to check dispute status: ${err}`, report });
+ }
+};
+
+export const checkEpochs: Step = async ({ merkleRootsProvider }, report) => {
+ try {
+ const { startRoot, endRoot } = report.params;
+
+ const startEpoch = await merkleRootsProvider.fetchEpochFor(startRoot);
+ const endEpoch = await merkleRootsProvider.fetchEpochFor(endRoot);
+
+ return Result.Success({ ...report, startEpoch, endEpoch });
+ } catch (err) {
+ return Result.Error({ code: BotError.EpochFetch, reason: `Unable to get epochs: ${err}`, report });
+ }
+};
+
+export const checkTrees: Step = async ({ merkleRootsProvider, logger }, report) => {
+ try {
+ const { startEpoch, endEpoch } = report;
+
+ const startTree = await merkleRootsProvider.fetchTreeFor(startEpoch);
+ const endTree = await merkleRootsProvider.fetchTreeFor(endEpoch);
+
+ logger?.trees(startEpoch, startTree, endEpoch, endTree);
+
+ return Result.Success({ ...report, startTree, endTree });
+ } catch (err) {
+ return Result.Error({ code: BotError.TreeFetch, reason: `Unable to get trees: ${err}`, report });
+ }
+};
+
+export const checkRoots: Step = async ({ logger }, report) => {
+ try {
+ const { startTree, endTree } = report;
+
+ const startRoot = buildMerklTree(startTree.rewards).tree.getHexRoot();
+ const endRoot = buildMerklTree(endTree.rewards).tree.getHexRoot();
+
+ logger?.computedRoots(startRoot, endRoot);
+
+ if (startRoot !== startTree.merklRoot) throw 'Start merkle root is not correct';
+ if (endRoot !== endTree.merklRoot) throw 'End merkle root is not correct';
+ else return Result.Success({ ...report, startRoot, endRoot });
+ } catch (reason) {
+ return Result.Error({ code: BotError.TreeRoot, reason, report });
+ }
+};
+
+export const checkHolderValidity: Step = async ({ onChainProvider }, report) => {
+ let holdersReport: HoldersReport;
+
+ try {
+ const { startTree, endTree } = report;
+ holdersReport = await validateHolders(onChainProvider, startTree, endTree);
+ const negativeDiffs = holdersReport.negativeDiffs;
+
+ if (negativeDiffs.length > 0) throw negativeDiffs.join('\n');
+
+ return Result.Success({ ...report, holdersReport });
+ } catch (reason) {
+ return Result.Error({ code: BotError.NegativeDiff, reason, report: { ...report, holdersReport } });
+ }
+};
+
+export const checkOverclaimedRewards: Step = async ({ onChainProvider }, report) => {
+ let expandedHoldersReport: HoldersReport;
+
+ try {
+ const { holdersReport } = report;
+ expandedHoldersReport = await validateClaims(onChainProvider, holdersReport);
+ const overclaims = expandedHoldersReport.overclaimed;
+
+ if (overclaims.length > 0) throw overclaims.join('\n');
+
+ return Result.Success({ ...report, holdersReport: expandedHoldersReport });
+ } catch (reason) {
+ return Result.Error({ code: BotError.AlreadyClaimed, reason, report: { ...report, holdersReport: expandedHoldersReport } });
+ }
+};
+
+export async function runSteps(
+ context: DisputeContext,
+ steps: Step[] = [
+ checkBlockTime,
+ checkOnChainParams,
+ checkDisputeWindow,
+ checkEpochs,
+ checkTrees,
+ checkRoots,
+ checkHolderValidity,
+ checkOverclaimedRewards,
+ ],
+ report: MerklReport = {}
+): Promise {
+ return new Promise(async function (resolve: Resolver) {
+ let resolved = false;
+
+ const handleStep = async (step: Step) => {
+ const result = await step(context, report);
+
+ if (result.exit) resolve(result);
+ else report = result.res.report;
+
+ resolved = result.exit;
+ };
+
+ for (let i = 0; i < steps.length && !resolved; i++) await handleStep(steps[i]);
+
+ resolve(Result.Exit({ reason: 'No problemo', report }));
+ });
+}
+
+export default async function run(context: DisputeContext) {
+ const { logger } = context;
+ let report: MerklReport;
+
+ const checkUpResult = await runSteps(
+ context,
+ [
+ checkBlockTime,
+ checkOnChainParams,
+ checkDisputeWindow,
+ checkEpochs,
+ checkTrees,
+ checkRoots,
+ checkHolderValidity,
+ checkOverclaimedRewards,
+ ],
+ report
+ );
+
+ const holdersReport = checkUpResult?.res?.report?.holdersReport;
+
+ if (holdersReport) {
+ checkUpResult.res.report.diffTableUrl = await createDiffTable(
+ holdersReport.details,
+ holdersReport.changePerDistrib,
+ !context.uploadDiffTable
+ );
+ }
+
+ if (!checkUpResult.err) {
+ await logger?.success(context, checkUpResult.res.reason, checkUpResult.res.report);
+ return;
+ }
+
+ await logger?.error(context, checkUpResult.res.reason, checkUpResult.res.code, checkUpResult.res.report);
+
+ const disputeResult = await runSteps(context, [createSigner, approveDisputeStake, disputeTree], checkUpResult.res.report);
+
+ if (!disputeResult.err) {
+ await logger?.disputeSuccess(context, disputeResult.res.reason, disputeResult.res.report);
+ return;
+ }
+
+ await logger?.disputeError(context, disputeResult.res.reason, disputeResult.res.code, disputeResult.res.report);
+}
diff --git a/src/bot/validity.ts b/src/bot/validity.ts
new file mode 100644
index 0000000..0c60196
--- /dev/null
+++ b/src/bot/validity.ts
@@ -0,0 +1,149 @@
+import { AggregatedRewardsType, Int256 } from '@angleprotocol/sdk';
+import { BigNumber } from 'ethers';
+
+import { round } from '../helpers';
+import OnChainProvider from '../providers/on-chain/OnChainProvider';
+import { DistributionChanges, HolderClaims, HolderDetail, HoldersReport, UnclaimedRewards } from '../types/holders';
+
+function gatherHolders(startTree: AggregatedRewardsType, endTree: AggregatedRewardsType): any[] {
+ const holders = [];
+
+ for (const d of Object.values(startTree.rewards)) {
+ for (const h of Object.keys(d.holders)) {
+ if (!holders.includes(h)) {
+ holders.push(h);
+ }
+ }
+ }
+ for (const d of Object.values(endTree.rewards)) {
+ for (const h of Object.keys(d.holders)) {
+ if (!holders.includes(h)) {
+ holders.push(h);
+ }
+ }
+ }
+
+ return holders;
+}
+
+export async function validateHolders(
+ onChainProvider: OnChainProvider,
+ startTree: AggregatedRewardsType,
+ endTree: AggregatedRewardsType
+): Promise {
+ const holders = gatherHolders(startTree, endTree);
+ const activeDistributions = await onChainProvider.fetchActiveDistributions();
+
+ const poolName = {};
+
+ const details: HolderDetail[] = [];
+ const changePerDistrib: DistributionChanges = {};
+ const unclaimed: UnclaimedRewards = {};
+ const negativeDiffs: string[] = [];
+
+ for (const holder of holders) {
+ unclaimed[holder] = {};
+ for (const k of Object.keys(endTree.rewards)) {
+ const symbol = endTree?.rewards?.[k].tokenSymbol;
+ const decimals = endTree?.rewards?.[k].tokenDecimals;
+ const pool = endTree?.rewards?.[k]?.pool;
+
+ if (!unclaimed[holder]) unclaimed[holder] = {};
+ if (!unclaimed[holder][symbol]) {
+ unclaimed[holder][symbol] = Int256.from(endTree?.rewards?.[k]?.holders?.[holder]?.amount ?? 0, decimals);
+ } else {
+ unclaimed[holder][symbol] = unclaimed[holder][symbol].add(
+ Int256.from(endTree?.rewards?.[k]?.holders?.[holder]?.amount ?? 0, decimals)
+ );
+ }
+ if (startTree?.rewards?.[k]?.holders?.[holder]?.amount !== endTree?.rewards?.[k]?.holders?.[holder]?.amount) {
+ const diff = Int256.from(
+ BigNumber.from(endTree?.rewards?.[k]?.holders?.[holder]?.amount ?? 0).sub(
+ startTree?.rewards?.[k]?.holders?.[holder]?.amount ?? 0
+ ),
+ decimals
+ ).toNumber();
+ if (diff < 0) negativeDiffs.push(`${holder}: ${diff.toFixed(2)} ${symbol}`);
+ const diffBoost =
+ Number(endTree?.rewards?.[k]?.holders?.[holder]?.averageBoost) ??
+ 0 - Number(startTree?.rewards?.[k]?.holders?.[holder]?.averageBoost) ??
+ 0;
+
+ if (!poolName[pool]) {
+ try {
+ poolName[pool] = await onChainProvider.fetchPoolName(pool, endTree?.rewards?.[k]?.amm);
+ } catch (err) {
+ console.log(`Error fetching poolName ${poolName[pool]} (${pool}):${endTree?.rewards?.[k]?.amm}`, err);
+ }
+ }
+ let ratePerEpoch;
+ try {
+ const solidityDist = activeDistributions?.find((d) => d.base.rewardId === k);
+ ratePerEpoch = Int256.from(solidityDist?.base?.amount ?? 0, decimals)?.toNumber() / solidityDist?.base?.numEpoch;
+ } catch {
+ ratePerEpoch = 1;
+ }
+ changePerDistrib[k] = {
+ diff: (changePerDistrib[k]?.diff ?? 0) + diff,
+ symbol,
+ poolName: poolName[pool],
+ pool,
+ recipients: (changePerDistrib[k]?.recipients ?? 0) + 1,
+ ratePerEpoch,
+ epoch: (changePerDistrib[k]?.epoch ?? 0) + diff / ratePerEpoch,
+ };
+ details.push({
+ holder,
+ decimals,
+ diff,
+ diffAverageBoost: diffBoost,
+ symbol,
+ poolName: poolName[pool],
+ distribution: k,
+ tokenAddress: endTree?.rewards?.[k].token,
+ });
+ }
+ }
+ }
+
+ for (const l of details) {
+ l.percent = (l?.diff / changePerDistrib[l?.distribution]?.diff) * 100;
+ }
+
+ return { details, changePerDistrib, unclaimed, negativeDiffs };
+}
+
+export async function validateClaims(onChainProvider: OnChainProvider, holdersReport: HoldersReport): Promise {
+ const { details, unclaimed } = holdersReport;
+ const alreadyClaimed: HolderClaims = await onChainProvider.fetchClaimed(details);
+
+ const overclaimed: string[] = [];
+
+ // Sort details by distribution and format numbers
+ const expandedDetails = await Promise.all(
+ details
+ .sort((a, b) =>
+ a.poolName > b.poolName ? 1 : b.poolName > a.poolName ? -1 : a.percent > b.percent ? -1 : b.percent > a.percent ? 1 : 0
+ )
+ .map(async (d) => {
+ const alreadyClaimedValue = round(Int256.from(alreadyClaimed[d.holder][d.tokenAddress], d.decimals).toNumber(), 2);
+ const totalCumulated = round(unclaimed[d.holder][d.symbol].toNumber(), 2);
+
+ if (totalCumulated < alreadyClaimedValue) {
+ overclaimed.push(`${d.holder}: ${alreadyClaimedValue} / ${totalCumulated} ${d.symbol}`);
+ }
+ return {
+ ...d,
+ diff: round(d.diff, 2),
+ percent: round(d.percent, 2),
+ averageBoost: round(d.diffAverageBoost, 2),
+ distribution: d.distribution.slice(0, 5),
+ totalCumulated,
+ alreadyClaimed: alreadyClaimedValue,
+ issueSpotted: totalCumulated < alreadyClaimedValue,
+ };
+ })
+ );
+
+ return { ...holdersReport, details: expandedDetails, overclaimed };
+}
diff --git a/src/constants/index.ts b/src/constants/index.ts
new file mode 100644
index 0000000..609b458
--- /dev/null
+++ b/src/constants/index.ts
@@ -0,0 +1,9 @@
+export const TVL_THRESHOLD = 10;
+export const BATCH_NUMBER = 1_000;
+export const MULTICALL_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
+export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
+export const GITHUB_URL = `https://raw.githubusercontent.com/AngleProtocol/merkl-rewards/main/`; // TODO switch to public gcloud buckets
+export const ANGLE_API = `https://api.angle.money/`;
+export const MAX_NUM_SUBCALLS = 50;
+export const HOUR = 3600;
+export const YEAR = 3600 * 24 * 365;
diff --git a/src/diff.ts b/src/diff.ts
new file mode 100644
index 0000000..d808875
--- /dev/null
+++ b/src/diff.ts
@@ -0,0 +1,40 @@
+import moment from 'moment';
+
+import { DisputeContext } from './bot/context';
+import { validateClaims, validateHolders } from './bot/validity';
+import { buildMerklTree } from './helpers';
+import createDiffTable from './helpers/diffTable';
+import ConsoleLogger from './helpers/logger/ConsoleLogger';
+import blockFromTimestamp from './providers/blockNumberFromTimestamp';
+
+export default async function (context: DisputeContext, fromTimeStamp: number, toTimeStamp: number) {
+ const { merkleRootsProvider, onChainProvider } = context;
+ const logger = new ConsoleLogger();
+
+ const fromDate = moment.unix(fromTimeStamp);
+ const toDate = moment.unix(toTimeStamp);
+
+ console.log(`Comparing ${fromDate.format('MMMM Do YYYY, h:mm:ss a')} to ${toDate.format('MMMM Do YYYY, h:mm:ss a')}...`);
+
+ const endBlock: number = parseInt(await blockFromTimestamp(toTimeStamp, context.chainId));
+ console.log(`Using block ${endBlock} as onchain reference`);
+
+ onChainProvider.setBlock(endBlock);
+
+ const startEpoch = await merkleRootsProvider.epochFromTimestamp(fromTimeStamp);
+ const endEpoch = await merkleRootsProvider.epochFromTimestamp(toTimeStamp);
+ const startTree = await merkleRootsProvider.fetchTreeFor(startEpoch);
+ const endTree = await merkleRootsProvider.fetchTreeFor(endEpoch);
+
+ logger.trees(startEpoch, startTree, endEpoch, endTree);
+
+ const endRoot = buildMerklTree(endTree.rewards).tree.getHexRoot();
+ const startRoot = buildMerklTree(startTree.rewards).tree.getHexRoot();
+
+ logger.computedRoots(startRoot, endRoot);
+
+ const holdersReport = await validateClaims(onChainProvider, await validateHolders(onChainProvider, startTree, endTree));
+
+ const res = await createDiffTable(holdersReport.details, holdersReport.changePerDistrib, !context.uploadDiffTable);
+ context.uploadDiffTable && console.log('output:', res);
+}
diff --git a/src/helpers/diffTable.ts b/src/helpers/diffTable.ts
new file mode 100644
index 0000000..6ae0c4e
--- /dev/null
+++ b/src/helpers/diffTable.ts
@@ -0,0 +1,58 @@
+import { Octokit } from '@octokit/rest';
+import { Console } from 'console';
+import { Transform } from 'stream';
+
+import { DistributionChanges, HolderDetail } from '../types/holders';
+import { round } from '.';
+
+const octokit = new Octokit({ auth: process.env.KEEPER_GITHUB_AUTH_TOKEN });
+export async function createGist(description: string, content: string): Promise {
+ const response = await octokit.gists.create({
+ files: {
+ 'diff.txt': {
+ content: content,
+ },
+ },
+ description,
+ public: false,
+ });
+ return response.data.html_url;
+}
+
+export default async function createDiffTable(details: HolderDetail[], changePerDistrib: DistributionChanges, local = true) {
+ try {
+ const ts = new Transform({
+ transform(chunk, _, cb) {
+ cb(null, chunk);
+ },
+ });
+ const output = local ? console : new Console({ stdout: ts });
+
+ output.table(details, [
+ 'holder',
+ 'diff',
+ 'symbol',
+ 'poolName',
+ 'distribution',
+ 'percent',
+ 'diffAverageBoost',
+ 'totalCumulated',
+ 'alreadyClaimed',
+ 'issueSpotted',
+ ]);
+
+ output.table(
+ Object.keys(changePerDistrib)
+ .map((k) => {
+ return { ...changePerDistrib[k], epoch: round(changePerDistrib[k].epoch, 4) };
+ })
+ .sort((a, b) => (a.poolName > b.poolName ? 1 : b.poolName > a.poolName ? -1 : 0))
+ );
+
+ if (local) return undefined;
+
+ return await createGist('Merkl Dispute Bot diff', (ts.read() || '').toString());
+ } catch (err) {
+ return undefined;
+ }
+}
diff --git a/src/helpers/index.ts b/src/helpers/index.ts
new file mode 100644
index 0000000..f618ced
--- /dev/null
+++ b/src/helpers/index.ts
@@ -0,0 +1,134 @@
+import {
+ AggregatedRewardsType,
+ AMMAlgorithmMapping,
+ AMMAlgorithmType,
+ AMMType,
+ Erc20__factory,
+ Multicall__factory,
+ UnderlyingTreeType,
+} from '@angleprotocol/sdk';
+import { BigNumber, ethers, utils } from 'ethers';
+import keccak256 from 'keccak256';
+import MerkleTree from 'merkletreejs';
+
+import { MULTICALL_ADDRESS } from '../constants';
+import { httpProvider } from '../providers';
+import { PoolInterface } from '../types';
+
+export const fetchPoolName = async (chainId: number, pool: string, amm: AMMType) => {
+ const provider = httpProvider(chainId);
+ const multicall = Multicall__factory.connect(MULTICALL_ADDRESS, provider);
+ const poolInterface = PoolInterface(AMMAlgorithmMapping[amm]);
+ const erc20Interface = Erc20__factory.createInterface();
+
+ let calls = [
+ {
+ callData: poolInterface.encodeFunctionData('token0'),
+ target: pool,
+ allowFailure: false,
+ },
+ {
+ callData: poolInterface.encodeFunctionData('token1'),
+ target: pool,
+ allowFailure: false,
+ },
+ ...(AMMAlgorithmMapping[amm] === AMMAlgorithmType.UniswapV3
+ ? [
+ {
+ callData: poolInterface.encodeFunctionData('fee'),
+ target: pool,
+ allowFailure: false,
+ },
+ ]
+ : []),
+ ];
+ let res = await multicall.callStatic.aggregate3(calls);
+ let i = 0;
+ const token0 = poolInterface.decodeFunctionResult('token0', res[i++].returnData)[0];
+ const token1 = poolInterface.decodeFunctionResult('token1', res[i++].returnData)[0];
+ let fee;
+ if (AMMAlgorithmMapping[amm] === AMMAlgorithmType.UniswapV3) {
+ fee = poolInterface.decodeFunctionResult('fee', res[i].returnData)[0];
+ }
+ calls = [
+ {
+ callData: erc20Interface.encodeFunctionData('symbol'),
+ target: token0,
+ allowFailure: false,
+ },
+ {
+ callData: erc20Interface.encodeFunctionData('symbol'),
+ target: token1,
+ allowFailure: false,
+ },
+ ];
+ res = await multicall.callStatic.aggregate3(calls);
+ const token0Symbol = erc20Interface.decodeFunctionResult('symbol', res[0].returnData)[0];
+ const token1Symbol = erc20Interface.decodeFunctionResult('symbol', res[1].returnData)[0];
+
+ return `${AMMType[amm]} ${token0Symbol}-${token1Symbol}-${fee ?? ``}`;
+};
+
+export const round = (n: number, dec: number) => Math.round(n * 10 ** dec) / 10 ** dec;
+
+export const buildMerklTree = (
+ underylingTreeData: UnderlyingTreeType
+): {
+ tree: MerkleTree;
+ tokens: string[];
+} => {
+ /**
+ * 1 - Build the global list of users
+ */
+ const users: string[] = [];
+ for (const id of Object.keys(underylingTreeData)) {
+ const rewardUsers = Object.keys(underylingTreeData[id].holders);
+ for (const r of rewardUsers) {
+ if (!users.includes(r)) {
+ users.push(r);
+ }
+ }
+ }
+
+ /**
+ * 2 - Build the global list of tokens
+ */
+ const tokens: string[] = tokensFromTree(underylingTreeData);
+
+ /**
+ * 3 - Build the tree
+ */
+ const elements = [];
+ for (const u of users) {
+ for (const t of tokens) {
+ let sum = BigNumber.from(0);
+ for (const id of Object.keys(underylingTreeData)) {
+ const distribution = underylingTreeData[id];
+ if (distribution.token === t) {
+ sum = sum?.add(distribution?.holders[u]?.amount.toString() ?? 0);
+ }
+ }
+ const hash = ethers.utils.keccak256(
+ ethers.utils.defaultAbiCoder.encode(['address', 'address', 'uint256'], [utils.getAddress(u), t, sum])
+ );
+
+ elements.push(hash);
+ }
+ }
+ const tree = new MerkleTree(elements, keccak256, { hashLeaves: false, sortPairs: true, sortLeaves: false });
+
+ return {
+ tokens,
+ tree,
+ };
+};
+
+export const tokensFromTree = (json: AggregatedRewardsType['rewards']): string[] => {
+ const tokens: string[] = [];
+ for (const id of Object.keys(json)) {
+ if (!tokens.includes(json[id].token)) {
+ tokens.push(json[id].token);
+ }
+ }
+ return tokens;
+};
diff --git a/src/helpers/logger/ConsoleLogger.ts b/src/helpers/logger/ConsoleLogger.ts
new file mode 100644
index 0000000..ba2afef
--- /dev/null
+++ b/src/helpers/logger/ConsoleLogger.ts
@@ -0,0 +1,76 @@
+import { AggregatedRewardsType, NETWORK_LABELS } from '@angleprotocol/sdk';
+import chalk from 'chalk';
+import { BigNumber } from 'ethers';
+
+import { DisputeContext } from '../../bot/context';
+import { OnChainParams } from '../../providers/on-chain/OnChainProvider';
+import { MerklReport } from '../../types/bot';
+import Logger from './Logger';
+
+export default class ConsoleLogger extends Logger {
+ override context = (context: DisputeContext, timestamp?: number) => {
+ const date = new Date(timestamp * 1000);
+
+ console.log(
+ chalk.yellow(
+ `Merkl Dispute Bot checks ${NETWORK_LABELS[context.chainId] ?? ''} (${context.chainId}) at block ${
+ !!context.blockNumber ? context.blockNumber : 'latest'
+ } (${date.toLocaleDateString()} at ${date.toLocaleTimeString()})`
+ )
+ );
+ };
+ override onChainParams = (params: OnChainParams, timestamp?: number) => {
+ const endDate = new Date(params.endOfDisputePeriod * 1000);
+ const log = (...a) => console.log(chalk.blue(...a));
+
+ console.groupCollapsed(chalk.blue(`On-chain data:`));
+
+ log('token address:', params.disputeToken);
+ log('token amount:', BigNumber.from(params.disputeAmount).toString());
+ log('dispute period:', params.disputePeriod, 'hour(s)');
+ log('dispute ends:', `${endDate.toLocaleDateString()} at ${endDate.toLocaleTimeString()}`);
+ log('dispute open:', params.endOfDisputePeriod >= timestamp);
+
+ console.groupEnd();
+ };
+ override trees = (startEpoch: number, startTree: AggregatedRewardsType, endEpoch: number, endTree: AggregatedRewardsType) => {
+ const log = (...a) => console.log(chalk.green(...a));
+
+ console.group(chalk.green('Epochs/merkle roots data:'));
+ log('startEpoch:', startEpoch);
+ log('endEpoch:', endEpoch);
+ log('startRoot:', startTree.merklRoot);
+ log('endRoot:', endTree.merklRoot);
+ console.groupEnd();
+ };
+ override computedRoots = (start: string, end: string) => {
+ console.group('Computed roots:');
+ console.log('startRoot:', start);
+ console.log('endRoot:', end);
+ console.groupEnd();
+ };
+
+ override error = async (context, reason: string, code?: number, report?: MerklReport) => {
+ const log = (...a) => console.log(chalk.red(...a));
+
+ log('[CHECKS ERROR]:', reason);
+ };
+
+ override success = async (context, reason: string, report?: MerklReport) => {
+ const log = (...a) => console.log(chalk.green(...a));
+
+ log('[CHECKS OK]:', reason);
+ };
+
+ override disputeError = async (context, reason: string, code?: number, report?: MerklReport) => {
+ const log = (...a) => console.log(chalk.red(...a));
+
+ log('[DISPUTE ERROR]:', reason);
+ };
+
+ override disputeSuccess = async (context, reason: string, report?: MerklReport) => {
+ const log = (...a) => console.log(chalk.green(...a));
+
+ log('[DISPUTE SUCCESS ]:', reason);
+ };
+}
diff --git a/src/helpers/logger/DiscordWebhookLogger.ts b/src/helpers/logger/DiscordWebhookLogger.ts
new file mode 100644
index 0000000..4d75e56
--- /dev/null
+++ b/src/helpers/logger/DiscordWebhookLogger.ts
@@ -0,0 +1,135 @@
+import { DisputeContext } from '../../bot/context';
+import { BotError, MerklReport } from '../../types/bot';
+import { sendDiscordNotification } from '../../utils/discord';
+import Logger from './Logger';
+
+function fieldsFromReport(report?: MerklReport) {
+ const fields = [];
+
+ report?.diffTableUrl &&
+ fields.push({
+ name: 'gist',
+ value: `${report?.diffTableUrl}`,
+ });
+
+ report?.startRoot &&
+ report?.startRoot &&
+ fields.push({
+ name: 'roots',
+ value: `${report?.startRoot}\n${report?.endRoot}`,
+ });
+
+ report?.blockNumber?.toString() &&
+ fields.push({
+ name: 'block',
+ inline: true,
+ value: `${report?.blockNumber?.toString()}`,
+ });
+
+ report?.startEpoch?.toString() &&
+ fields.push({
+ name: 'startEpoch',
+ inline: true,
+ value: `${report?.startEpoch?.toString()}`,
+ });
+
+ report?.endEpoch?.toString() &&
+ fields.push({
+ name: 'endEpoch',
+ inline: true,
+ value: `${report?.endEpoch?.toString()}`,
+ });
+
+ return fields;
+}
+
+const noLog = () => {
+ return;
+};
+
+export default class DiscordWebhookLogger extends Logger {
+ override context = noLog;
+ override onChainParams = noLog;
+ override computedRoots = noLog;
+ override trees = () => noLog;
+
+ override error = async (context: DisputeContext, reason: string, code?: number, report?: MerklReport) => {
+ const errorTitles = {};
+ errorTitles[BotError.TreeRoot] = '❌ Roots do not match';
+ errorTitles[BotError.OnChainFetch] = '🔴 On-chain data unavailable';
+ errorTitles[BotError.BlocktimeFetch] = '🔴 Block data unavailable';
+ errorTitles[BotError.EpochFetch] = '🔴 Merkle root data unavailable';
+ errorTitles[BotError.TreeFetch] = '🔴 Merkle tree data unavailable';
+ errorTitles[BotError.NegativeDiff] = '🚸 Negative diff detected';
+ errorTitles[BotError.AlreadyClaimed] = '🚸 Already claimed detected';
+
+ try {
+ await sendDiscordNotification({
+ title: errorTitles[code],
+ description: reason,
+ isAlert: true,
+ severity: 'warning',
+ fields: fieldsFromReport(report),
+ key: 'merkl dispute bot',
+ chain: context.chainId,
+ });
+ } catch (err) {
+ console.log('Failed to send error discord notification:', err);
+ }
+ };
+
+ override disputeError = async (context: DisputeContext, reason: string, code?: number, report?: MerklReport) => {
+ const errorTitles = {};
+ errorTitles[BotError.KeeperApprove] = '❌ Transaction failed (approve)';
+ errorTitles[BotError.KeeperDispute] = '❌ Transaction failed (disputeTree)';
+ errorTitles[BotError.KeeperCreate] = '❌ Signer creation failed';
+
+ console.log('??', reason, errorTitles[code]);
+
+ try {
+ await sendDiscordNotification({
+ title: errorTitles[code],
+ description: reason ?? '',
+ isAlert: true,
+ severity: 'error',
+ fields: fieldsFromReport(report),
+ key: 'merkl dispute bot',
+ chain: context.chainId,
+ });
+ } catch (err) {
+ console.log('Failed to send error discord notification:', err);
+ }
+ };
+
+ override success = async (context: DisputeContext, reason: string, report?: MerklReport) => {
+ try {
+ await sendDiscordNotification({
+ title: `✅ Nothing to report \n`,
+ description: reason,
+ isAlert: false,
+ severity: 'success',
+ fields: fieldsFromReport(report),
+ key: 'merkl dispute bot',
+ chain: context.chainId,
+ });
+ } catch (err) {
+ console.log('Failed to send success discord notification:', err);
+ }
+ };
+
+ override disputeSuccess = async (context: DisputeContext, reason: string, report?: MerklReport) => {
+ try {
+ await sendDiscordNotification({
+ title: `⚔️ Dispute Successful \n`,
+ description: 'Anomalies found, a dispute has been triggered',
+ isAlert: true,
+ severity: 'success',
+ fields: fieldsFromReport(report),
+ key: 'merkl dispute bot',
+ chain: context.chainId,
+ });
+ } catch (err) {
+ console.log('Failed to send success discord notification:', err);
+ }
+ };
+}
diff --git a/src/helpers/logger/Logger.ts b/src/helpers/logger/Logger.ts
new file mode 100644
index 0000000..64bb08d
--- /dev/null
+++ b/src/helpers/logger/Logger.ts
@@ -0,0 +1,16 @@
+import { AggregatedRewardsType } from '@angleprotocol/sdk';
+
+import { DisputeContext } from '../../bot/context';
+import { OnChainParams } from '../../providers/on-chain/OnChainProvider';
+import { MerklReport } from '../../types/bot';
+
+export default abstract class Logger {
+ context: (context: DisputeContext, timestamp?: number) => void;
+ onChainParams: (params: OnChainParams, timestamp?: number) => void;
+ trees: (startEpoch: number, startTree: AggregatedRewardsType, endEpoch: number, endTree: AggregatedRewardsType) => void;
+ computedRoots: (start: string, end: string) => void;
+ error: (context: DisputeContext, reason: string, code?: number, report?: MerklReport) => Promise;
+ success: (context: DisputeContext, reason: string, report?: MerklReport) => Promise;
+ disputeError: (context: DisputeContext, reason: string, code?: number, report?: MerklReport) => Promise;
+ disputeSuccess: (context: DisputeContext, reason: string, report?: MerklReport) => Promise;
+}
diff --git a/src/helpers/logger/Loggers.ts b/src/helpers/logger/Loggers.ts
new file mode 100644
index 0000000..7d95cc2
--- /dev/null
+++ b/src/helpers/logger/Loggers.ts
@@ -0,0 +1,30 @@
+import { AggregatedRewardsType } from '@angleprotocol/sdk';
+
+import { DisputeContext } from '../../bot/context';
+import { OnChainParams } from '../../providers/on-chain/OnChainProvider';
+import { MerklReport } from '../../types/bot';
+import Logger from './Logger';
+
+export default class Loggers extends Logger {
+ loggers: Logger[];
+
+ constructor(loggers: Logger[]) {
+ super();
+ this.loggers = loggers;
+ }
+
+ override context = (context: DisputeContext, timestamp?: number) => this.loggers.forEach((l) => l.context(context, timestamp));
+ override onChainParams = (params: OnChainParams, timestamp?: number) => this.loggers.forEach((l) => l.onChainParams(params, timestamp));
+ override trees = (startEpoch: number, startTree: AggregatedRewardsType, endEpoch: number, endTree: AggregatedRewardsType) =>
+ this.loggers.forEach((l) => l.trees(startEpoch, startTree, endEpoch, endTree));
+ override computedRoots = (start: string, end: string) => this.loggers.forEach((l) => l.computedRoots(start, end));
+ override error = async (context: DisputeContext, reason: string, code?: number, report?: MerklReport) =>
+ this.loggers.forEach((l) => l.error(context, reason, code, report));
+ override success = async (context: DisputeContext, reason: string, report?: MerklReport) => {
+ await Promise.all(this.loggers.map((l) => l.success(context, reason, report)));
+ };
+ override disputeError = async (context: DisputeContext, reason: string, code?: number, report?: MerklReport) =>
+ this.loggers.forEach((l) => l.disputeError(context, reason, code, report));
+ override disputeSuccess = async (context: DisputeContext, reason: string, report?: MerklReport) =>
+ this.loggers.forEach((l) => l.disputeSuccess(context, reason, report));
+}
diff --git a/src/helpers/networks.ts b/src/helpers/networks.ts
new file mode 100644
index 0000000..83d185b
--- /dev/null
+++ b/src/helpers/networks.ts
@@ -0,0 +1,10 @@
+import { ChainId } from '@angleprotocol/sdk';
+
+const NETWORKS: { [chainId: number]: string } = [];
+for (const c of Object.keys(ChainId)) {
+ try {
+ NETWORKS[c] = process.env[`PROVIDER_${c}`];
+ } catch {}
+}
+
+export default NETWORKS;
diff --git a/src/helpers/queries.ts b/src/helpers/queries.ts
new file mode 100644
index 0000000..79cba93
--- /dev/null
+++ b/src/helpers/queries.ts
@@ -0,0 +1,186 @@
+import { gql } from 'graphql-request';
+
+import { BATCH_NUMBER } from '../constants';
+
+export const wrapperQuery = gql`
+ query Query($poolId: ID!) {
+ pool(id: $poolId) {
+ arrakisPools
+ gammaPools
+ }
+ }
+`;
+
+export const vaultQuery = gql`
+ query Vaults($poolId: String!) {
+ vaults(where: { pool: $poolId }) {
+ id
+ }
+ }
+`;
+
+export const swapQuery = gql`
+ query getSwaps($pool: String!, $uTimestamp: BigInt!, $lTimestamp: BigInt!, $first: Int!) {
+ swaps(
+ where: { pool_: { id: $pool }, timestamp_gt: $lTimestamp, timestamp_lt: $uTimestamp }
+ orderBy: amount0
+ orderDirection: desc
+ first: $first
+ ) {
+ timestamp
+ amount0
+ amount1
+ amountUSD
+ tick
+ sqrtPriceX96
+ transaction {
+ blockNumber
+ }
+ }
+ }
+`;
+
+export const swapQueryUniV3 = gql`
+ query Swaps($pool: String!, $uTimestamp: BigInt!, $lTimestamp: BigInt!, $first: Int!) {
+ swaps(
+ where: { pool_: { id: $pool }, timestamp_gt: $lTimestamp, timestamp_lt: $uTimestamp }
+ orderBy: amount0
+ orderDirection: desc
+ first: $first
+ ) {
+ timestamp
+ amount0
+ amount1
+ amountUSD
+ tick
+ sqrtPriceX96
+ transaction {
+ blockNumber
+ }
+ }
+ }
+`;
+
+export const nftPositionsQuery = gql`
+ query Positions($pool: String!, $minLiquidityOpen: BigInt!, $minLiquidityClosed: BigInt!, $startTimestamp: Int!) {
+ openPositions: nftpositions(
+ where: { pool_: { id: $pool }, endTimestamp: 0, liquidity_lt: $minLiquidityOpen },
+ first: ${BATCH_NUMBER}
+ orderBy: liquidity
+ orderDirection: desc
+ ) {
+ endTimestamp,
+ liquidity
+ id
+ owner
+ startTimestamp,
+ liquidity,
+ tickLower,
+ tickUpper,
+ }
+ closedPositions: nftpositions(
+ where: { pool_: { id: $pool }, endTimestamp_gt: $startTimestamp, liquidity_lt: $minLiquidityClosed},
+ first: ${BATCH_NUMBER}
+ orderBy: liquidity
+ orderDirection: desc
+ ) {
+ endTimestamp,
+ id
+ owner
+ startTimestamp,
+ liquidity,
+ tickLower,
+ tickUpper,
+ }
+ }`;
+
+export const directPositionsQuery = gql`
+ query Positions($pool: String!, $minLiquidityOpen: BigInt!, $minLiquidityClosed: BigInt!, $startTimestamp: Int!) {
+ openPositions: directPositions(
+ where: { pool_: { id: $pool }, endTimestamp: 0, liquidity_lt: $minLiquidityOpen },
+ first: ${BATCH_NUMBER}
+ orderBy: liquidity
+ orderDirection: desc
+ ) {
+ endTimestamp,
+ owner
+ startTimestamp,
+ id,
+ tickLower,
+ tickUpper,
+ liquidity
+ }
+ closedPositions: directPositions(
+ where: { pool_: { id: $pool }, endTimestamp_gt: $startTimestamp, liquidity_lt: $minLiquidityClosed },
+ first: ${BATCH_NUMBER}
+ orderBy: liquidity
+ orderDirection: desc
+ ) {
+ endTimestamp,
+ id
+ owner
+ startTimestamp,
+ liquidity,
+ }
+ }`;
+
+export const holdersQuery = gql`
+ query Holders($where: [Int!], $token: String!, $skip: Int!) {
+ holders(where: { week_in: $where, token: $token }, first: ${BATCH_NUMBER}, skip: $skip) {
+ holder
+ }
+ }
+ `;
+
+export const positionsQuery = gql`
+ query Positions($owners: [String!], $timestamp: Int!, $pool: String!) {
+ nft: nftpositions(where: { owner_in: $owners, pool: $pool, endTimestamp: 0 }) {
+ id
+ pool {
+ id
+ }
+ startTimestamp
+ endTimestamp
+ tickLower
+ tickUpper
+ liquidity
+ owner
+ }
+ nftPast: nftpositions(where: { owner_in: $owners, pool: $pool, endTimestamp_gt: $timestamp }) {
+ id
+ pool {
+ id
+ }
+ startTimestamp
+ endTimestamp
+ tickLower
+ tickUpper
+ liquidity
+ owner
+ }
+ direct: directPositions(where: { owner_in: $owners, pool: $pool, endTimestamp: 0 }) {
+ id
+ pool {
+ id
+ }
+ startTimestamp
+ endTimestamp
+ tickLower
+ tickUpper
+ liquidity
+ owner
+ }
+ directPast: directPositions(where: { owner_in: $owners, pool: $pool, endTimestamp_gt: $timestamp }) {
+ id
+ pool {
+ id
+ }
+ startTimestamp
+ endTimestamp
+ tickLower
+ tickUpper
+ liquidity
+ owner
+ }
+ }
+`;
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..6e6e2d8
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,72 @@
+import { Command } from 'commander';
+
+import { defaultContext } from './bot/context';
+import run from './bot/runner';
+import diff from './diff';
+import serve from './serve';
+
+const bot = new Command();
+
+bot.name('Merkl Dispute Bot').description('Bot safeguarding merkle root update for Merkl by Angle Labs').version('0.1');
+
+bot.command('serve').description('Runs the bot as an express server, exposing // route').action(serve);
+
+bot
+ .command('run')
+ .description('Runs the bot once')
+ .option('-c, --chain ', 'ChainId to run the bot on')
+ .option('-b, --block ', 'Block to run the bot on')
+ .action(async (str, options) => {
+ const {
+ _optionValues: { chain, block },
+ } = options;
+
+ const context = defaultContext(parseInt(chain), !!block ? parseInt(block) : undefined);
+
+ await run(context);
+ });
+
+bot
+ .command('watch')
+ .description('Runs the bot for every at a time interval')
+ .option('-c, --chain ', 'ChainId to run the bot on')
+ .option('-t, --time ', 'Time (in seconds) after which to retry running the bot')
+ .action(async (str, options) => {
+ const {
+ _optionValues: { chain, time },
+ } = options;
+
+ const runBot = async () => {
+ try {
+ const context = defaultContext(parseInt(chain));
+
+ await run(context);
+ } catch (err) {
+ console.error(err);
+ }
+ };
+
+ runBot();
+
+ setInterval(runBot, parseInt(time) * 1000);
+ });
+
+bot
+ .command('diff')
+ .description('Compares two timestamps and generate difference')
+ .option('-c, --chain ', 'ChainId to run the bot on')
+ .option('-f, --from ', 'Timestamp to compare with ')
+ .option('-t, --to ', 'Timestamp to compare with ')
+ .option('-g, --gist', 'Add if the output should be uploaded to a gist')
+ .action(async (str, options) => {
+ const {
+ _optionValues: { chain, from, to, gist },
+ } = options;
+
+ const context = defaultContext(parseInt(chain));
+ context.uploadDiffTable = gist;
+
+ await diff(context, from, to);
+ });
+
+bot.parse();
diff --git a/src/providers/ExponentialBackoffProvider.ts b/src/providers/ExponentialBackoffProvider.ts
new file mode 100644
index 0000000..af6e7be
--- /dev/null
+++ b/src/providers/ExponentialBackoffProvider.ts
@@ -0,0 +1,33 @@
+export type ExponentialFetchParams = {
+ retries: number;
+ delay: number;
+ multiplier: number;
+};
+
+export abstract class ExponentialBackoffProvider {
+ fetchParams: ExponentialFetchParams;
+
+ protected async retryWithExponentialBackoff(fn: (...params) => Promise, fetchParams: ExponentialFetchParams, ...args): Promise {
+ const { retries, delay, multiplier } = fetchParams;
+
+ try {
+ return await fn(...args);
+ } catch (err) {
+ if (retries === 0) throw err;
+
+ await new Promise((resolve) => setTimeout(resolve, delay));
+
+ const nextParams: ExponentialFetchParams = {
+ ...fetchParams,
+ delay: fetchParams.delay * multiplier,
+ retries: fetchParams.retries - 1,
+ };
+
+ return this.retryWithExponentialBackoff(fn, nextParams, ...args);
+ }
+ }
+
+ constructor(fetchParams: ExponentialFetchParams = { retries: 5, delay: 500, multiplier: 2 }) {
+ this.fetchParams = fetchParams;
+ }
+}
diff --git a/src/providers/blockNumberFromTimestamp.ts b/src/providers/blockNumberFromTimestamp.ts
new file mode 100644
index 0000000..4b377e4
--- /dev/null
+++ b/src/providers/blockNumberFromTimestamp.ts
@@ -0,0 +1,24 @@
+import { ChainId } from '@angleprotocol/sdk';
+import axios from 'axios';
+
+// TODO Switch to SDK
+export const chainApiUrls = {
+ [ChainId.ARBITRUM]: 'https://api.arbiscan.io',
+ [ChainId.MAINNET]: 'https://api.etherscan.io',
+ [ChainId.OPTIMISM]: 'https://api-optimistic.etherscan.io',
+ [ChainId.POLYGON]: 'https://api.polygonscan.com',
+ [ChainId.POLYGONZKEVM]: 'https://api-zkevm.polygonscan.com',
+ [ChainId.AVALANCHE]: 'https://api.snowtrace.io',
+ [ChainId.GNOSIS]: 'https://api.gnosisscan.io',
+ [ChainId.BSC]: 'https://api.bscscan.com',
+ [ChainId.CELO]: 'https://api.celoscan.io',
+ [ChainId.BASE]: 'https://api.basescan.org',
+};
+
+export default async function blockFromTimestamp(timestamp: number, chainId: number) {
+ const url = chainApiUrls[chainId];
+ const response = await axios.get(
+ url + `/api?module=block&action=getblocknobytime×tamp=${timestamp.toString()}&closest=before&apikey=YourApiKeyToken`
+ );
+ return response.data.result;
+}
diff --git a/src/providers/index.ts b/src/providers/index.ts
new file mode 100644
index 0000000..def6caf
--- /dev/null
+++ b/src/providers/index.ts
@@ -0,0 +1,11 @@
+import { ChainId } from '@angleprotocol/sdk';
+import { providers } from 'ethers';
+
+const NETWORKS: { [chainId: number]: string } = [];
+for (const c of Object.keys(ChainId)) {
+ try {
+ NETWORKS[c] = process.env[`PROVIDER_${c}`];
+ } catch {}
+}
+
+export const httpProvider = (network: keyof typeof NETWORKS) => new providers.StaticJsonRpcProvider(NETWORKS[network]);
diff --git a/src/providers/merkl-roots/GithubRootsProvider.ts b/src/providers/merkl-roots/GithubRootsProvider.ts
new file mode 100644
index 0000000..0bef026
--- /dev/null
+++ b/src/providers/merkl-roots/GithubRootsProvider.ts
@@ -0,0 +1,57 @@
+import { AggregatedRewardsType } from '@angleprotocol/sdk';
+import axios from 'axios';
+
+import { ExponentialFetchParams } from '../ExponentialBackoffProvider';
+import MerkleRootsProvider from './MerkleRootsProvider';
+
+export type MerklIndexType = { [merklRoot: string]: number };
+
+export default class GithubRootsProvider extends MerkleRootsProvider {
+ url: string;
+ merklIndex: MerklIndexType;
+ chainId: number;
+
+ constructor(url: string, chainId: number, fetchParams?: ExponentialFetchParams) {
+ super(fetchParams);
+ this.url = `${url}/${chainId}`;
+ }
+
+ async cacheMerklIndex(): Promise {
+ const indexUrl = `${this.url}/index.json`;
+ const res = await axios.get(indexUrl, {
+ timeout: 25_000,
+ });
+
+ this.merklIndex = res.data;
+ }
+
+ override tree = async (epoch: number) => {
+ const rewardsUrl = `${this.url}/backup/rewards_${epoch}.json`;
+
+ try {
+ const res = await axios.get(rewardsUrl, {
+ timeout: 25_000,
+ });
+ return res.data;
+ } catch (err) {
+ console.log('??', rewardsUrl, err);
+ }
+ };
+
+ override epoch = async (root: string) => {
+ if (!this.merklIndex) await this.cacheMerklIndex();
+
+ return this.merklIndex[root];
+ };
+
+ override epochFromTimestamp = async (timestamp: number): Promise => {
+ if (!this.merklIndex) await this.cacheMerklIndex();
+
+ let epoch = Math.floor(timestamp / 3600);
+
+ while (!Object.values(this.merklIndex).includes(epoch)) {
+ epoch -= 1;
+ }
+ return epoch;
+ };
+}
diff --git a/src/providers/merkl-roots/MerkleRootsProvider.ts b/src/providers/merkl-roots/MerkleRootsProvider.ts
new file mode 100644
index 0000000..1b8054a
--- /dev/null
+++ b/src/providers/merkl-roots/MerkleRootsProvider.ts
@@ -0,0 +1,21 @@
+import { AggregatedRewardsType } from '@angleprotocol/sdk';
+
+import { ExponentialBackoffProvider, ExponentialFetchParams } from '../ExponentialBackoffProvider';
+
+export default abstract class MerkleRootsProvider extends ExponentialBackoffProvider {
+ constructor(fetchParams: ExponentialFetchParams = { retries: 5, delay: 500, multiplier: 2 }) {
+ super(fetchParams);
+ }
+
+ abstract epoch(root: string): Promise;
+ abstract tree(epoch: number): Promise;
+ abstract epochFromTimestamp(timestamp: number): Promise;
+
+ async fetchEpochFor(root: string): Promise {
+ return this.retryWithExponentialBackoff(this.epoch, this.fetchParams, root);
+ }
+
+ async fetchTreeFor(epoch: number): Promise {
+ return this.retryWithExponentialBackoff(this.tree, this.fetchParams, epoch);
+ }
+}
diff --git a/src/providers/on-chain/OnChainProvider.ts b/src/providers/on-chain/OnChainProvider.ts
new file mode 100644
index 0000000..5694c38
--- /dev/null
+++ b/src/providers/on-chain/OnChainProvider.ts
@@ -0,0 +1,83 @@
+import { AMMType } from '@angleprotocol/sdk';
+import { ExtensiveDistributionParametersStructOutput } from '@angleprotocol/sdk/dist/constants/types/DistributionCreator';
+import { BigNumber, ContractReceipt, Overrides, Wallet } from 'ethers';
+
+import { HolderClaims, HolderDetail } from '../../types/holders';
+import { ExponentialBackoffProvider, ExponentialFetchParams } from '../ExponentialBackoffProvider';
+
+export type OnChainParams = {
+ disputeToken: string;
+ disputeAmount: BigNumber;
+ disputePeriod: number;
+ endOfDisputePeriod: number;
+ disputer: string;
+ endRoot: string;
+ startRoot: string;
+ currentRoot: string;
+};
+
+export default abstract class OnChainProvider extends ExponentialBackoffProvider {
+ fetchParams: ExponentialFetchParams;
+ distributor: string;
+ blockNumber: number | undefined;
+
+ constructor(fetchParams: ExponentialFetchParams = { retries: 5, delay: 500, multiplier: 2 }) {
+ super(fetchParams);
+ }
+
+ protected abstract onChainParams: () => Promise;
+ protected abstract timestampAt: (blockNumber: number) => Promise;
+ protected abstract activeDistributions: () => Promise;
+ protected abstract poolName: (pool: string, amm: AMMType) => Promise;
+ protected abstract claimed: (holderDetails: HolderDetail[]) => Promise;
+ protected abstract approve: (
+ keeper: Wallet,
+ disputeToken: string,
+ disputeAmount: BigNumber,
+ overrides: Overrides
+ ) => Promise;
+
+ protected abstract dispute: (keeper: Wallet, reason: string, overrides: Overrides) => Promise;
+ protected abstract mountBlock: () => Promise;
+ protected abstract approval: (address: string, token: string) => Promise;
+
+ setBlock(blockNumber: number) {
+ this.blockNumber = blockNumber;
+ }
+
+ async mountLastBlock() {
+ return this.retryWithExponentialBackoff(this.mountBlock, this.fetchParams);
+ }
+
+ async sendApproveTxn(keeper: Wallet, disputeToken: string, disputeAmount: BigNumber, overrides: Overrides) {
+ return this.retryWithExponentialBackoff(this.approve, this.fetchParams, keeper, disputeToken, disputeAmount, overrides);
+ }
+
+ async sendDisputeTxn(keeper: Wallet, reason: string, overrides: Overrides) {
+ return this.retryWithExponentialBackoff(this.dispute, this.fetchParams, keeper, reason, overrides);
+ }
+
+ async fetchClaimed(holderDetails: HolderDetail[]): Promise {
+ return this.retryWithExponentialBackoff(this.claimed, this.fetchParams, holderDetails);
+ }
+
+ async fetchPoolName(pool: string, amm: AMMType): Promise {
+ return this.retryWithExponentialBackoff(this.poolName, this.fetchParams, pool, amm);
+ }
+
+ async fetchApproval(address: string, token: string): Promise {
+ return this.retryWithExponentialBackoff(this.approval, this.fetchParams, address, token);
+ }
+
+ async fetchActiveDistributions(): Promise {
+ return this.retryWithExponentialBackoff(this.activeDistributions, this.fetchParams);
+ }
+
+ async fetchOnChainParams(): Promise {
+ return this.retryWithExponentialBackoff(this.onChainParams, this.fetchParams);
+ }
+
+ async fetchTimestampAt(blockNumber: number): Promise {
+ return this.retryWithExponentialBackoff(this.timestampAt, this.fetchParams, blockNumber);
+ }
+}
diff --git a/src/providers/on-chain/RpcProvider.ts b/src/providers/on-chain/RpcProvider.ts
new file mode 100644
index 0000000..94c6edf
--- /dev/null
+++ b/src/providers/on-chain/RpcProvider.ts
@@ -0,0 +1,212 @@
+import {
+ AMMAlgorithmMapping,
+ AMMAlgorithmType,
+ AMMType,
+ DistributionCreator__factory,
+ Distributor__factory,
+ Erc20__factory,
+ Multicall__factory,
+ PoolInterface,
+} from '@angleprotocol/sdk';
+import { Multicall3 } from '@angleprotocol/sdk/dist/constants/types/Multicall';
+import { BigNumber, Overrides, providers, Wallet } from 'ethers';
+
+import { HolderDetail } from '../../types/holders';
+import { batchMulticallCall, multicallContractCall } from '../../utils';
+import { ExponentialFetchParams } from '../ExponentialBackoffProvider';
+import OnChainProvider from './OnChainProvider';
+
+export default class RpcProvider extends OnChainProvider {
+ provider: providers.StaticJsonRpcProvider;
+ distributor: string;
+ distributorCreator: string;
+
+ constructor(url: string, distributor: string, distributorCreator: string, fetchParams?: ExponentialFetchParams) {
+ super(fetchParams);
+
+ this.provider = new providers.StaticJsonRpcProvider(url);
+ this.distributor = distributor;
+ this.distributorCreator = distributorCreator;
+ }
+
+ override approval = async (address: string, token: string) => {
+ return await Erc20__factory.connect(token, this.provider).allowance(address, this.distributor);
+ };
+
+ override approve = async (keeper: Wallet, disputeToken: string, disputeAmount: BigNumber, overrides: Overrides) => {
+ const txn = await Erc20__factory.connect(disputeToken, keeper.connect(this.provider)).approve(
+ this.distributor,
+ disputeAmount,
+ overrides
+ );
+
+ return await txn.wait();
+ };
+
+ override dispute = async (keeper: Wallet, reason: string, overrides: Overrides) => {
+ const distributorContract = Distributor__factory.connect(this.distributor, keeper.connect(this.provider));
+ const txn = await distributorContract.disputeTree(reason, overrides);
+
+ return await txn.wait();
+ };
+
+ override mountBlock = async (): Promise => {
+ const block = await this.provider.getBlockNumber();
+
+ this.blockNumber = block;
+ return block;
+ };
+
+ override timestampAt = async (blockNumber: number) => {
+ return (await this.provider.getBlock(blockNumber)).timestamp;
+ };
+
+ override activeDistributions = async () => {
+ const instance = DistributionCreator__factory.connect(this.distributorCreator, this.provider);
+
+ return instance.getActiveDistributions({ blockTag: this.blockNumber });
+ };
+
+ override poolName = async (pool: string, amm: AMMType) => {
+ const multicall = Multicall__factory.connect('0xcA11bde05977b3631167028862bE2a173976CA11', this.provider);
+ const poolInterface = PoolInterface(AMMAlgorithmMapping[amm]);
+ const erc20Interface = Erc20__factory.createInterface();
+
+ let calls = [
+ {
+ callData: poolInterface.encodeFunctionData('token0'),
+ target: pool,
+ allowFailure: false,
+ },
+ {
+ callData: poolInterface.encodeFunctionData('token1'),
+ target: pool,
+ allowFailure: false,
+ },
+ ...(AMMAlgorithmMapping[amm] === AMMAlgorithmType.UniswapV3
+ ? [
+ {
+ callData: poolInterface.encodeFunctionData('fee'),
+ target: pool,
+ allowFailure: false,
+ },
+ ]
+ : []),
+ ];
+ let res = await multicall.callStatic.aggregate3(calls, { blockTag: this.blockNumber });
+ let i = 0;
+ const token0 = poolInterface.decodeFunctionResult('token0', res[i++].returnData)[0];
+ const token1 = poolInterface.decodeFunctionResult('token1', res[i++].returnData)[0];
+ let fee;
+ if (AMMAlgorithmMapping[amm] === AMMAlgorithmType.UniswapV3) {
+ fee = poolInterface.decodeFunctionResult('fee', res[i].returnData)[0];
+ }
+ calls = [
+ {
+ callData: erc20Interface.encodeFunctionData('symbol'),
+ target: token0,
+ allowFailure: false,
+ },
+ {
+ callData: erc20Interface.encodeFunctionData('symbol'),
+ target: token1,
+ allowFailure: false,
+ },
+ ];
+ res = await multicall.callStatic.aggregate3(calls, { blockTag: this.blockNumber });
+ const token0Symbol = erc20Interface.decodeFunctionResult('symbol', res[0].returnData)[0];
+ const token1Symbol = erc20Interface.decodeFunctionResult('symbol', res[1].returnData)[0];
+
+ return `${AMMType[amm]} ${token0Symbol}-${token1Symbol}-${fee ?? ``}`;
+ };
+
+ override onChainParams = async () => {
+ const multicall = Multicall__factory.connect('0xcA11bde05977b3631167028862bE2a173976CA11', this.provider);
+ const distributor = Distributor__factory.createInterface();
+
+ const calls = [
+ {
+ callData: distributor.encodeFunctionData('disputeToken'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('disputeAmount'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('disputePeriod'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('endOfDisputePeriod'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('disputer'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('tree'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('lastTree'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ {
+ callData: distributor.encodeFunctionData('getMerkleRoot'),
+ target: this.distributor,
+ allowFailure: false,
+ },
+ ];
+
+ const result = await batchMulticallCall(multicallContractCall, multicall, { data: calls, blockNumber: this.blockNumber });
+ let i = 0;
+ return {
+ disputeToken: distributor.decodeFunctionResult('disputeToken', result[i++])[0],
+ disputeAmount: distributor.decodeFunctionResult('disputeAmount', result[i++])[0],
+ disputePeriod: distributor.decodeFunctionResult('disputePeriod', result[i++])[0],
+ endOfDisputePeriod: distributor.decodeFunctionResult('endOfDisputePeriod', result[i++])[0],
+ disputer: distributor.decodeFunctionResult('disputer', result[i++])[0],
+ endRoot: distributor.decodeFunctionResult('tree', result[i++])[0],
+ startRoot: distributor.decodeFunctionResult('lastTree', result[i++])[0],
+ currentRoot: distributor.decodeFunctionResult('getMerkleRoot', result[i])[0],
+ };
+ };
+
+ override claimed = async (holderDetails: HolderDetail[]) => {
+ const distributor = Distributor__factory.createInterface();
+ const multicall = Multicall__factory.connect('0xcA11bde05977b3631167028862bE2a173976CA11', this.provider);
+
+ const alreadyClaimed: { [address: string]: { [symbol: string]: string } } = {};
+ const calls: Multicall3.Call3Struct[] = [];
+
+ for (const d of holderDetails) {
+ if (!alreadyClaimed[d.holder]) alreadyClaimed[d.holder] = {};
+ if (!alreadyClaimed[d.holder][d.tokenAddress]) {
+ alreadyClaimed[d.holder][d.tokenAddress] = 'PENDING';
+ calls.push({
+ callData: distributor.encodeFunctionData('claimed', [d.holder, d.tokenAddress]),
+ target: this.distributor,
+ allowFailure: false,
+ });
+ }
+ }
+ const res = await batchMulticallCall(multicallContractCall, multicall, { data: calls, blockNumber: this.blockNumber });
+ let decodingIndex = 0;
+ for (const d of holderDetails) {
+ if (alreadyClaimed[d.holder][d.tokenAddress] === 'PENDING') {
+ alreadyClaimed[d.holder][d.tokenAddress] = distributor.decodeFunctionResult('claimed', res[decodingIndex++])[0];
+ }
+ }
+
+ return alreadyClaimed;
+ };
+}
diff --git a/src/serve.ts b/src/serve.ts
new file mode 100644
index 0000000..a21b61d
--- /dev/null
+++ b/src/serve.ts
@@ -0,0 +1,41 @@
+import 'dotenv/config';
+
+import { ChainId } from '@angleprotocol/sdk';
+import express, { Application } from 'express';
+
+import { defaultContext, DisputeContext } from './bot/context';
+import run from './bot/runner';
+import NETWORKS from './helpers/networks';
+import { getChainId } from './utils';
+
+export default function () {
+ const app: Application = express();
+
+ app.use(express.json());
+ app.use(express.urlencoded({ extended: true }));
+
+ const PORT = process.env.PORT || 5002;
+
+ app.get('/:chain?/:blockNumber?', async (req, res) => {
+ const { chain, blockNumber } = req.params;
+ const chainProvided = !!(chain && NETWORKS[chain]);
+ const blockProvided: boolean = blockNumber && blockNumber !== '';
+
+ console.log('chain', chain, chainProvided, NETWORKS[chain], 'block', blockProvided);
+
+ const chainId: ChainId = chainProvided ? (parseInt(chain) as ChainId) : getChainId();
+ const context: DisputeContext = defaultContext(chainId, blockProvided ? parseInt(blockNumber) : undefined);
+
+ try {
+ await run(context);
+ return res.status(200).send('OK');
+ } catch (err) {
+ return res.status(500).send('KO');
+ }
+ });
+
+ app.listen(PORT, () => {
+ console.log(`Dispute bot listening on port ${PORT}`);
+ console.log('Press Ctrl+C to quit.');
+ });
+}
diff --git a/src/types/bot.ts b/src/types/bot.ts
new file mode 100644
index 0000000..a21ecce
--- /dev/null
+++ b/src/types/bot.ts
@@ -0,0 +1,74 @@
+import { AggregatedRewardsType, ChainId } from '@angleprotocol/sdk';
+import { ContractReceipt, Wallet } from 'ethers';
+
+import { DisputeContext } from '../bot/context';
+import { OnChainParams } from '../providers/on-chain/OnChainProvider';
+import { HoldersReport } from './holders';
+
+export type StepError = {
+ code: BotError;
+ reason: string;
+ report: MerklReport;
+};
+
+export type StepExit = {
+ reason: string;
+ report: MerklReport;
+};
+
+export type StepSuccess = {
+ reason: string;
+ report: MerklReport;
+};
+
+export type DisputeReport = {
+ signer?: Wallet;
+ approveReceipt?: ContractReceipt;
+ disputeReceipt?: ContractReceipt;
+};
+
+export type MerklReport = {
+ startTime?: number;
+ blockNumber?: number;
+ startEpoch?: number;
+ startRoot?: string;
+ startTree?: AggregatedRewardsType;
+ endEpoch?: number;
+ endRoot?: string;
+ endTree?: AggregatedRewardsType;
+ params?: OnChainParams;
+ chainId?: ChainId;
+ holdersReport?: HoldersReport;
+ disputeReport?: DisputeReport;
+ diffTableUrl?: string;
+};
+
+export enum BotError {
+ None = -1,
+ OnChainFetch,
+ BlocktimeFetch,
+ EpochFetch,
+ TreeFetch,
+ TreeRoot,
+ NegativeDiff,
+ AlreadyClaimed,
+ KeeperCreate,
+ KeeperApprove,
+ KeeperDispute,
+}
+
+export type Exit = { err: false; exit: true; res: T };
+export type Success = { err: false; exit: false; res: S };
+export type Error = { err: true; exit: true; res: E };
+export type Result = Exit | Error | Success;
+
+export const Result = Object.freeze({
+ Success: (report: MerklReport): StepResult => ({ err: false, exit: false, res: { reason: '', report } }),
+ Exit: (exit: StepExit): StepResult => ({ err: false, exit: true, res: exit }),
+ Error: (err: StepError): StepResult => ({ err: true, exit: true, res: err }),
+});
+
+export type StepResult = Result;
+
+export type Resolver = (res: StepResult | PromiseLike) => void;
+export type Step = ({ onChainProvider, blockNumber }: DisputeContext, report: MerklReport) => Promise;
diff --git a/src/types/holders.ts b/src/types/holders.ts
new file mode 100644
index 0000000..2e5d70e
--- /dev/null
+++ b/src/types/holders.ts
@@ -0,0 +1,36 @@
+import { Int256 } from '@angleprotocol/sdk';
+
+export type HolderDetail = {
+ holder: string;
+ diff: number;
+ symbol: string;
+ poolName: string;
+ distribution: string;
+ percent?: number;
+ diffAverageBoost?: number;
+ decimals?: number;
+ tokenAddress?: string;
+ issueSpotted?: boolean;
+};
+
+export type HolderClaims = { [address: string]: { [symbol: string]: string } };
+
+export type DistributionChange = {
+ diff: number;
+ symbol: string;
+ poolName: string;
+ pool: any;
+ recipients: number;
+ ratePerEpoch: number;
+ epoch: number;
+};
+
+export type DistributionChanges = { [address: string]: DistributionChange };
+export type UnclaimedRewards = { [address: string]: { [symbol: string]: Int256 } };
+export type HoldersReport = {
+ details: HolderDetail[];
+ changePerDistrib: DistributionChanges;
+ unclaimed: UnclaimedRewards;
+ negativeDiffs: string[];
+ overclaimed?: string[];
+};
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..2cf697a
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,53 @@
+import { AMMAlgorithmType } from '@angleprotocol/sdk';
+
+export declare type PositionType = {
+ id: string;
+ endTimestamp: number;
+ owner: string;
+ startTimestamp: number;
+ tickLower: number;
+ tickUpper: number;
+ liquidity: string;
+};
+
+export type SwapType = {
+ amount0: string;
+ amount1: string;
+ amountUSD: string;
+ tick: string;
+ timestamp: string;
+ transaction: { blockNumber: string };
+} & (T extends AMMAlgorithmType.AlgebraV1_9 ? { price: string } : { sqrtPriceX96: string });
+
+export type Price = {
+ [token: string]: number;
+};
+
+export type AccumulatedRewards = {
+ Earned: number;
+ Token: string;
+ PoolName: string;
+ Origin: string;
+ Distribution: string;
+ Amm: number;
+ PoolAddress: string;
+};
+
+export type UserStats = Partial<{
+ lowerTick: number;
+ tick: number;
+ upperTick: number;
+ type: string;
+ amount0: number;
+ amount1: number;
+ liquidity: string;
+ inRange: boolean;
+ tvl: number;
+ earned: number;
+ propFee: number;
+ propAmount0: number;
+ propAmount1: number;
+ inducedAPR: number;
+}>;
+
+export * from './interfaces';
diff --git a/src/types/interfaces.ts b/src/types/interfaces.ts
new file mode 100644
index 0000000..2084147
--- /dev/null
+++ b/src/types/interfaces.ts
@@ -0,0 +1,12 @@
+import { AlgebraV19Pool__factory, AMMAlgorithmType, UniswapV3Pool__factory } from '@angleprotocol/sdk';
+import { Interface } from '@ethersproject/abi';
+
+export const PoolInterface = (ammType: AMMAlgorithmType): Interface => {
+ if (ammType === AMMAlgorithmType.AlgebraV1_9) {
+ return AlgebraV19Pool__factory.createInterface();
+ } else if (ammType === AMMAlgorithmType.UniswapV3) {
+ return UniswapV3Pool__factory.createInterface();
+ } else if (ammType === AMMAlgorithmType.BaseX) {
+ return;
+ } else throw new Error('Invalid AMM type');
+};
diff --git a/src/utils/discord.ts b/src/utils/discord.ts
new file mode 100644
index 0000000..61239b8
--- /dev/null
+++ b/src/utils/discord.ts
@@ -0,0 +1,79 @@
+import { ChainId } from '@angleprotocol/sdk';
+import { APIEmbedField, Client, EmbedBuilder, GatewayIntentBits, Partials, TextChannel } from 'discord.js';
+
+const colorBySeverity = {
+ info: 0x00bfff,
+ success: 0x00dd55,
+ warning: 0xffa500,
+ error: 0xff0000,
+};
+export type severity = 'info' | 'warning' | 'error' | 'success';
+
+const chainFooter = {
+ 137: { text: 'Polygon', iconURL: 'https://cdn.jsdelivr.net/gh/webThreeBuilder/CryptoLogos/logos/matic.png' },
+ 1: { text: 'Ethereum', iconURL: 'https://cdn.jsdelivr.net/gh/webThreeBuilder/CryptoLogos/logos/eth.png' },
+ 10: { text: 'Optimism', iconURL: 'https://cdn.jsdelivr.net/gh/webThreeBuilder/CryptoLogos/logos/10.png' },
+ 42161: { text: 'Arbitrum', iconURL: 'https://cdn.jsdelivr.net/gh/webThreeBuilder/CryptoLogos/logos/42161.png' },
+ 1101: { text: 'Polygon zvEVM', iconURL: 'https://cdn.jsdelivr.net/gh/webThreeBuilder/CryptoLogos/logos/matic.png' },
+ 8453: { text: 'Base', iconURL: 'https://icons.llamao.fi/icons/chains/rsz_base.jpg' },
+};
+
+const getChannel = (discordClient: Client, channelName: string) => {
+ return (discordClient.channels.cache as unknown as TextChannel[]).find((channel) => channel.name === channelName);
+};
+
+export async function sendDiscordNotification(params: {
+ title: string;
+ description: string;
+ fields: APIEmbedField[];
+ isAlert: boolean;
+ severity: severity;
+ key: string;
+ chain?: ChainId;
+}) {
+ return new Promise(async function (resolve, reject) {
+ try {
+ const discordClient = new Client({
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.DirectMessages],
+ partials: [Partials.Channel],
+ });
+
+ discordClient.login(process.env.DISCORD_TOKEN);
+
+ const env = process.env.ENV;
+ const logChannel = process.env.DISCORD_LOG_CHANNEL ?? 'dispute-bot-logs';
+ const alertChannel = process.env.DISCORD_LOG_CHANNEL ?? 'dispute-bot';
+
+ let channel: TextChannel;
+
+ discordClient.on('ready', async () => {
+ channel = getChannel(discordClient, !params.isAlert || env !== 'prod' ? logChannel : alertChannel);
+ if (!channel) {
+ console.log(params.key, '❌ discord channel not found');
+ return;
+ }
+
+ const exampleEmbed = new EmbedBuilder()
+ .setAuthor({
+ name: `Merkle Dispute Bot ${env !== 'prod' ? '[DEV]' : ''}`,
+ iconURL: 'https://merkl.angle.money/images/merkl-apple-touch-icon.png',
+ url: 'https://github.com/AngleProtocol/merkl-dispute',
+ })
+ .setColor(colorBySeverity[params.severity])
+ .setTitle(`${params.title}`)
+ .setDescription(params.description ?? 'nodesc')
+ .addFields(params.fields)
+ .setFooter(chainFooter[params.chain] ?? { text: `${params.chain}` });
+
+ await channel.send({ embeds: [exampleEmbed] });
+
+ discordClient.destroy();
+ resolve({});
+ });
+ resolve({});
+ } catch (e) {
+ console.log('merkl dispute bot', `❌ couldn't send summary to discord with reason: \n ${e}`);
+ reject();
+ }
+ });
+}
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 0000000..71bfe30
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,144 @@
+import 'dotenv/config';
+
+import { ChainId, EnvType, Multicall, withRetry } from '@angleprotocol/sdk';
+import { Multicall3 } from '@angleprotocol/sdk/dist/constants/types/Multicall';
+import { BytesLike, constants } from 'ethers';
+
+import { MAX_NUM_SUBCALLS } from '../constants';
+import { httpProvider } from '../providers';
+
+export function getEnv(): EnvType {
+ const value = process.env['ENV'] as EnvType;
+ if (!value) {
+ throw new Error(`❌ Missing environment variable ENV`);
+ }
+ return value;
+}
+
+export function getChainId(): ChainId {
+ const value = process.env['CHAINID'];
+ if (!value) {
+ throw new Error(`❌ Missing environment variable CHAINID`);
+ }
+ return parseInt(value) as ChainId;
+}
+
+export async function retryWithExponentialBackoff(fn: (...any) => Promise, retries = 5, delay = 500, ...args): Promise {
+ try {
+ const result = await fn(...args);
+ return result;
+ } catch (error) {
+ if (retries === 0) {
+ throw error;
+ }
+ await new Promise((resolve) => setTimeout(resolve, delay));
+ return retryWithExponentialBackoff(fn, retries - 1, delay * 2, ...args);
+ }
+}
+
+export async function multicallContractCall(
+ contract: Multicall,
+ args: { data: Multicall3.Call3Struct[]; blockNumber?: number; from: string }
+): Promise {
+ let result: BytesLike;
+ try {
+ // TO SIMULATE - USE CAUTIOUSLY AS IT USES CREDITS
+ // console.log(
+ // await callTenderly(
+ // {
+ // chainId: (await contract.provider.getNetwork()).chainId.toString(),
+ // data: contract.interface.encodeFunctionData('aggregate', [args.data]),
+ // from: !!args.from ? args.from : constants.AddressZero,
+ // saveSimulation: true,
+ // to: contract.address,
+ // value: '0',
+ // },
+ // undefined,
+ // true
+ // )
+ // );
+
+ result = await contract.provider.call(
+ {
+ data: contract.interface.encodeFunctionData('aggregate3', [
+ args.data.map((c) => {
+ return {
+ allowFailure: !!c.allowFailure,
+ callData: c.callData,
+ target: c.target,
+ };
+ }),
+ ]),
+ from: !!args.from ? args.from : constants.AddressZero,
+ to: contract.address,
+ },
+ !!args.blockNumber ? args.blockNumber : null
+ );
+ } catch {
+ throw new Error('❌ failed to decode multicall data');
+ }
+ return contract.interface.decodeFunctionResult('aggregate3', result)[0].map((r) => r?.returnData);
+}
+
+export async function batchMulticallCall(
+ func: (contract: Multicall, args: { data: Multicall3.Call3Struct[]; blockNumber?: number | string }) => Promise,
+ contract: Multicall,
+ args: { data: any[]; blockNumber?: number },
+ shouldRetry = true
+): Promise {
+ let fetchedData = [];
+ let callsLeft = args.data.length;
+ let lowerIdx = 0;
+ let upperIdx = Math.min(args.data.length, MAX_NUM_SUBCALLS);
+ const multicallBatch = [];
+ while (callsLeft !== 0) {
+ multicallBatch.push(
+ shouldRetry
+ ? withRetry(func, [
+ contract,
+ {
+ blockNumber: args.blockNumber,
+ data: args.data.slice(lowerIdx, upperIdx),
+ },
+ ])
+ : func(contract, args)
+ );
+ callsLeft -= upperIdx - lowerIdx;
+ lowerIdx = upperIdx;
+ upperIdx = Math.min(args.data.length, upperIdx + MAX_NUM_SUBCALLS);
+ }
+ /** Executing batched multicall */
+ const results = await Promise.allSettled(multicallBatch);
+ for (let k = 0; k < results.length; k++) {
+ const res = results[k];
+ if (res.status === 'fulfilled') {
+ fetchedData = fetchedData.concat(res.value);
+ }
+ }
+ return fetchedData;
+}
+
+/** @dev Any block between the timestamp and 1 min after is suitable */
+export async function getBlockAfterTimestamp(chainId: ChainId, timestamp: number): Promise {
+ const provider = httpProvider(chainId);
+ let lowerBound = 0;
+ let upperBound = await provider.getBlockNumber();
+
+ while (lowerBound <= upperBound) {
+ const mid = Math.floor((upperBound + lowerBound) / 2);
+ const block = await provider.getBlock(mid);
+
+ if (block.timestamp <= timestamp) {
+ lowerBound = mid + 1;
+ } else {
+ upperBound = mid - 1;
+ }
+
+ if (timestamp <= block.timestamp && timestamp + 60 >= block.timestamp) {
+ return block.number;
+ }
+ }
+
+ // Once the loop finishes, lowerBound points to the nearest block after the timestamp.
+ return (await provider.getBlock(lowerBound)).number;
+}
diff --git a/src/utils/merkl.ts b/src/utils/merkl.ts
new file mode 100644
index 0000000..9902b1f
--- /dev/null
+++ b/src/utils/merkl.ts
@@ -0,0 +1,14 @@
+import { utils } from 'ethers';
+
+export const log = (key: string, message: string) => {
+ !!key ? console.log(`>>> [${!!utils.isHexString(key) ? key.slice(2, 20) : key}]: ` + message) : console.log(`>>> []: ` + message);
+};
+
+export function linespace(start: number, end: number, card: number): number[] {
+ const arr = [];
+ const step = (end - start) / (card - 1);
+ for (let i = 0; i < card; i++) {
+ arr.push(start + step * i);
+ }
+ return arr;
+}
diff --git a/src/utils/report.ts b/src/utils/report.ts
new file mode 100644
index 0000000..353aa78
--- /dev/null
+++ b/src/utils/report.ts
@@ -0,0 +1,858 @@
+import {
+ AggregatedRewardsType,
+ ALMType,
+ AMMAlgorithmMapping,
+ AMMType,
+ ChainId,
+ DistributionCreator__factory,
+ Distributor__factory,
+ Erc20__factory,
+ formatNumber,
+ getAmountsForLiquidity,
+ getTickAtSqrtRatio,
+ Int256,
+ MerklAPIData,
+ MerklRewardDistributionType,
+ merklSubgraphAMMEndpoints,
+ MerklSupportedChainIdsType,
+ Multicall__factory,
+ NFTManagerAddress,
+ NonFungiblePositionManagerInterface,
+ PoolInterface,
+ PoolStateName,
+ registry,
+ SwapPriceField,
+ UnderlyingTreeType,
+} from '@angleprotocol/sdk';
+import dotenv from 'dotenv';
+import JSBI from 'jsbi';
+
+dotenv.config();
+
+import { ExtensiveDistributionParametersStructOutput } from '@angleprotocol/sdk/dist/constants/types/DistributionCreator';
+import { Multicall3 } from '@angleprotocol/sdk/dist/constants/types/Multicall';
+import { BN2Number } from '@angleprotocol/sdk/dist/utils';
+import axios from 'axios';
+import { BigNumber, BigNumberish, utils } from 'ethers';
+import { getAddress } from 'ethers/lib/utils';
+import request from 'graphql-request';
+
+import { ANGLE_API, GITHUB_URL, HOUR, MULTICALL_ADDRESS, YEAR } from '../constants';
+import { round } from '../helpers';
+import { positionsQuery } from '../helpers/queries';
+import { httpProvider } from '../providers';
+import { MerklIndexType } from '../providers/merkl-roots/GithubRootsProvider';
+import { AccumulatedRewards, PositionType, Price, UserStats } from '../types';
+import { getBlockAfterTimestamp } from '.';
+
+export const userParamsCheck = (user: string, pool: string, startTimestamp: number, endTimestamp: number): void => {
+ if (!getAddress(user)) throw new Error('Invalid user address');
+ if (startTimestamp >= endTimestamp) throw new Error('Invalid timestamps');
+ if (!!pool && !getAddress(pool)) throw new Error('Invalid pool address');
+};
+
+export const poolParamsCheck = (pool: string, startTimestamp: number, endTimestamp: number): void => {
+ if (startTimestamp >= endTimestamp) throw new Error('Invalid timestamps');
+ if (!!pool && !getAddress(pool)) throw new Error('Invalid pool address');
+};
+
+export const almCheck = (merklAPIData: MerklAPIData, pool: string, almAddress: string, almType: ALMType): void => {
+ const ALMname = ALMType[almType];
+ const poolApiData = merklAPIData?.pools?.[getAddress(pool)];
+ // Check that the almAddress is really linked to this pool
+ const filteredALM = poolApiData.almDetails.filter((alm) => alm.address === almAddress.toLowerCase());
+
+ // this would be problematic as we would not be able to distinguish between the two vaults APRs
+ if (filteredALM.length > 1) throw new Error(`Multiple ${ALMname} for ${getAddress(pool)}`);
+ if (filteredALM.length === 0 || Number(filteredALM[0].origin) !== almType) throw new Error('Invalid ALM address');
+};
+export const roundDownWhileKeyNotFound = (merklIndex: MerklIndexType, timestamp: number): number => {
+ let epoch = Math.floor(timestamp / HOUR);
+ while (!Object.values(merklIndex).includes(epoch)) {
+ epoch -= 1;
+ }
+ return epoch;
+};
+
+export const fetchAccumulatedRewards = async (chainId: number, epoch: number): Promise => {
+ return (
+ await axios.get(GITHUB_URL + `${chainId + `/backup/rewards_${epoch}.json`}`, {
+ timeout: 5000,
+ })
+ ).data;
+};
+
+export const poolName = (poolApiData: MerklAPIData['pools'][string]): string => {
+ return `${AMMType[poolApiData.amm]} ${poolApiData.tokenSymbol0}-${poolApiData.tokenSymbol1} ${poolApiData.poolFee + '%' ?? ``}`;
+};
+
+export const fetchReportData = async (
+ chainId: number
+): Promise<{ prices: Price; merklIndex: MerklIndexType; merklAPIData: MerklAPIData }> => {
+ const promises = [];
+
+ const prices = {};
+ promises.push(
+ axios.get<{ rate: number; token: string }[]>(ANGLE_API + `v1/prices`).then((res) => {
+ res.data.forEach((p) => (prices[p.token] = p.rate));
+ })
+ );
+
+ let merklIndex: MerklIndexType;
+ promises.push(
+ axios
+ .get(GITHUB_URL + `${chainId + `/index.json`}`, {
+ timeout: 5000,
+ })
+ .then((res) => {
+ merklIndex = res.data;
+ })
+ );
+
+ let merklAPIData: MerklAPIData;
+ promises.push(
+ axios
+ .get(ANGLE_API + `v1/merkl`, {
+ timeout: 5000,
+ })
+ .then((res) => {
+ merklAPIData = res.data;
+ })
+ );
+
+ await Promise.all(promises);
+
+ return { prices, merklIndex, merklAPIData };
+};
+
+export const fetchRewardJson = async (
+ chainId: ChainId,
+ merklIndex: MerklIndexType,
+ startTimestamp: number,
+ endTimestamp: number
+): Promise<{
+ startEpoch: number;
+ endEpoch: number;
+ startAccumulatedRewards: AggregatedRewardsType;
+ endAccumulatedRewards: AggregatedRewardsType;
+}> => {
+ const startEpoch = roundDownWhileKeyNotFound(merklIndex, startTimestamp);
+ const endEpoch = roundDownWhileKeyNotFound(merklIndex, endTimestamp);
+ let startAccumulatedRewards: AggregatedRewardsType, endAccumulatedRewards: AggregatedRewardsType;
+ await Promise.all([
+ fetchAccumulatedRewards(chainId, startEpoch).then((res) => (startAccumulatedRewards = res)),
+ fetchAccumulatedRewards(chainId, endEpoch).then((res) => (endAccumulatedRewards = res)),
+ ]);
+ return { startEpoch, endEpoch, startAccumulatedRewards, endAccumulatedRewards };
+};
+
+export const statsUserPool = async (
+ chainId: ChainId,
+ user: string,
+ pool: string,
+ startEpoch: number,
+ endEpoch: number,
+ accumulatedRewards: AccumulatedRewards[],
+ merklAPIData: MerklAPIData,
+ prices: Price,
+ countALM: boolean,
+ log = true
+): Promise<{ startStat: UserStats[]; endStat: UserStats[] }> => {
+ const merklAPIPoolData = merklAPIData?.pools?.[getAddress(pool)];
+ const poolRewards = accumulatedRewards.filter((a) => getAddress(a.PoolAddress) === getAddress(pool));
+ /*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ INTERFACES
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
+ const amm = merklAPIPoolData.amm;
+ const ammAlgo = AMMAlgorithmMapping[amm];
+
+ const Erc20Interface = Erc20__factory.createInterface();
+ const poolInterface = PoolInterface(ammAlgo);
+ const nftManagerInterface = NonFungiblePositionManagerInterface(ammAlgo);
+ const poolStateName = PoolStateName[ammAlgo];
+ const swapPriceField = SwapPriceField[ammAlgo];
+ const periodReward = poolRewards.reduce((prev, curr) => prev + curr.Earned * prices[curr.Token], 0);
+
+ if (log) {
+ console.log('\n//////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n');
+ console.log(`Now, let's break down rewards for the pool ${poolName(merklAPIPoolData)} (${pool}): \n`);
+ console.log(`Over the period of interest this address earned the following: \n`);
+ console.table(poolRewards, ['Earned', 'Token', 'Origin']);
+ console.log(
+ `At current prices, this is worth ~$${formatNumber(periodReward)}, which would make ~$${formatNumber(
+ (periodReward * YEAR) / (endEpoch * HOUR - startEpoch * HOUR)
+ )} over a year. \n`
+ );
+ }
+
+ const alms = merklAPIPoolData.almDetails;
+ const token0 = merklAPIPoolData.token0;
+ const token0Decimals = merklAPIPoolData.decimalToken0;
+ const token0Symbol = merklAPIPoolData.tokenSymbol0;
+ const token1 = merklAPIPoolData.token1;
+ const token1Decimals = merklAPIPoolData.decimalToken1;
+ const token1Symbol = merklAPIPoolData.tokenSymbol1;
+ const owners = countALM ? [user?.toLowerCase()].concat(alms.map((a) => a.address.toLowerCase())) : [user?.toLowerCase()];
+
+ const result = await request<
+ {
+ nft: PositionType[];
+ nftPast: PositionType[];
+ direct: PositionType[];
+ directPast: PositionType[];
+ },
+ any
+ >(merklSubgraphAMMEndpoints('prod')[chainId][amm], positionsQuery, {
+ owners: owners,
+ pool: pool?.toLowerCase(),
+ timestamp: startEpoch * HOUR,
+ });
+
+ const directPositions = result.direct.concat(result.directPast);
+ const nftPositions = result.nft.concat(result.nftPast);
+
+ const startBlockNumber = await getBlockAfterTimestamp(chainId, startEpoch * HOUR);
+ const endBlockNumber = await getBlockAfterTimestamp(chainId, endEpoch * HOUR);
+
+ const provider = httpProvider(chainId);
+ const multicall = Multicall__factory.connect(MULTICALL_ADDRESS, provider);
+ const calls: Multicall3.Call3Struct[] = [];
+
+ // 0 - Pool generic data
+ calls.push(
+ {
+ allowFailure: true,
+ callData: poolInterface.encodeFunctionData(poolStateName),
+ target: pool,
+ },
+ {
+ allowFailure: true,
+ callData: poolInterface.encodeFunctionData('liquidity'),
+ target: pool,
+ },
+ {
+ allowFailure: true,
+ callData: Erc20Interface.encodeFunctionData('balanceOf', [pool]),
+ target: token0,
+ },
+ {
+ allowFailure: true,
+ callData: Erc20Interface.encodeFunctionData('balanceOf', [pool]),
+ target: token1,
+ }
+ );
+
+ // 1 - User direct positions
+ for (const pos of directPositions.filter((p) => p.owner === user.toLowerCase())) {
+ calls.push({
+ allowFailure: true,
+ callData: poolInterface.encodeFunctionData('positions', [
+ utils.solidityKeccak256(['address', 'int24', 'int24'], [pos.owner, pos.tickLower, pos.tickUpper]),
+ ]),
+ target: pool,
+ });
+ }
+
+ // 2 - User NFT positions
+ for (const pos of nftPositions.filter((p) => p.owner === user.toLowerCase())) {
+ calls.push({
+ allowFailure: true,
+ callData: nftManagerInterface.encodeFunctionData('positions', [pos.id]),
+ target: NFTManagerAddress[chainId][amm],
+ });
+ }
+
+ if (countALM) {
+ // ALM data
+ for (const alm of alms) {
+ // 3 - ALM NFT positions
+ for (const pos of directPositions.filter((p) => p.owner === alm.address.toLowerCase())) {
+ calls.push({
+ allowFailure: true,
+ callData: poolInterface.encodeFunctionData('positions', [
+ utils.solidityKeccak256(['address', 'int24', 'int24'], [pos.owner, pos.tickLower, pos.tickUpper]),
+ ]),
+ target: pool,
+ });
+ }
+
+ // 4 - ALM NFT positions
+ for (const pos of nftPositions.filter((p) => p.owner === alm.address.toLowerCase())) {
+ calls.push({
+ allowFailure: true,
+ callData: nftManagerInterface.encodeFunctionData('positions', [pos.id]),
+ target: pool,
+ });
+ }
+
+ // 5 - Balance / Total Supply
+ calls.push(
+ {
+ allowFailure: true,
+ callData: Erc20Interface.encodeFunctionData('totalSupply'),
+ target: alm.address,
+ },
+ {
+ allowFailure: true,
+ callData: Erc20Interface.encodeFunctionData('balanceOf', [user]),
+ target: alm.address,
+ }
+ );
+ }
+ }
+
+ const analyzePoolState = async (blockNumber: number, log = true) => {
+ const stats = [] as UserStats[];
+
+ const res = await multicall.callStatic.aggregate3(calls, { blockTag: blockNumber });
+ let i = 0;
+ const sqrtPriceX96 = poolInterface.decodeFunctionResult(poolStateName, res[i++]?.returnData)[swapPriceField]?.toString();
+ const liquidityInPool = poolInterface.decodeFunctionResult('liquidity', res[i++]?.returnData)[0]?.toString();
+ const amount0InPool = BN2Number(Erc20Interface.decodeFunctionResult('balanceOf', res[i++]?.returnData)[0], token0Decimals);
+ const amount1InPool = BN2Number(Erc20Interface.decodeFunctionResult('balanceOf', res[i++]?.returnData)[0], token1Decimals);
+ const tvlInPool = amount0InPool * prices[token0Symbol] + amount1InPool * prices[token1Symbol];
+
+ const tick = getTickAtSqrtRatio(JSBI.BigInt(sqrtPriceX96));
+ const addPositionInArray = (pos: PositionType, type: string, liquidity: BigNumberish) => {
+ const [amount0, amount1] = getAmountsForLiquidity(
+ sqrtPriceX96,
+ Number(pos.tickLower),
+ Number(pos.tickUpper),
+ BigNumber.from(liquidity)
+ );
+ const inRange = Number(pos.tickLower) <= tick && tick < Number(pos.tickUpper);
+
+ const tvl = BN2Number(amount0, token0Decimals) * prices[token0Symbol] + BN2Number(amount1, token1Decimals) * prices[token1Symbol];
+ const positionRewards =
+ poolRewards.filter((p) => p.Origin === type)?.reduce((prev, curr) => prev + curr.Earned * prices[curr.Token], 0) ?? 0;
+
+ if (BN2Number(amount0, token0Decimals) > 0 || BN2Number(amount1, token1Decimals) > 0) {
+ stats.push({
+ lowerTick: pos.tickLower,
+ tick,
+ upperTick: pos.tickUpper,
+ type,
+ amount0: BN2Number(amount0, token0Decimals),
+ amount1: BN2Number(amount1, token1Decimals),
+ liquidity: liquidity?.toString(),
+ inRange,
+ tvl,
+ earned: positionRewards,
+ propFee: inRange ? round(Int256.from(liquidity, 0).mul(10000).div(liquidityInPool).toNumber() / 100, 2) : 0,
+ propAmount0: inRange ? round((BN2Number(amount0, token0Decimals) / amount0InPool) * 100, 2) : 0,
+ propAmount1: inRange ? round((BN2Number(amount1, token1Decimals) / amount1InPool) * 100, 2) : 0,
+ inducedAPR: round(((positionRewards * YEAR) / (endEpoch * HOUR - startEpoch * HOUR) / tvl) * 100, 3),
+ });
+ }
+ };
+
+ for (const pos of directPositions.filter((p) => p.owner === user.toLowerCase())) {
+ try {
+ const position = poolInterface.decodeFunctionResult('positions', res[i]?.returnData);
+ addPositionInArray(pos, AMMType[amm], position.liquidity);
+ } catch (e) {
+ console.error(e);
+ }
+ i++;
+ }
+
+ for (const pos of nftPositions.filter((p) => p.owner === user.toLowerCase())) {
+ try {
+ const position = nftManagerInterface.decodeFunctionResult('positions', res[i]?.returnData);
+ addPositionInArray(pos, AMMType[amm], position.liquidity);
+ } catch (e) {
+ console.error(e);
+ }
+ i++;
+ }
+
+ if (countALM) {
+ for (const alm of alms) {
+ try {
+ let j = i;
+ let amount0InAlm = 0;
+ let amount1InAlm = 0;
+ let liquidityInAlm = BigNumber.from(0);
+
+ for (const pos of directPositions.filter((p) => p.owner === alm.address.toLowerCase())) {
+ const position = poolInterface.decodeFunctionResult('positions', res[j++]?.returnData);
+ const [aux0, aux1] = getAmountsForLiquidity(
+ sqrtPriceX96,
+ Number(pos.tickLower),
+ Number(pos.tickUpper),
+ BigNumber.from(position.liquidity)
+ );
+ const inRange = Number(pos.tickLower) <= tick && tick < Number(pos.tickUpper);
+
+ amount0InAlm += BN2Number(aux0, token0Decimals);
+ amount1InAlm += BN2Number(aux1, token1Decimals);
+ if (inRange) liquidityInAlm = liquidityInAlm.add(position.liquidity);
+ }
+
+ // 4 - ALM NFT positions
+ for (const pos of nftPositions.filter((p) => p.owner === alm.address.toLowerCase())) {
+ const position = nftManagerInterface.decodeFunctionResult('positions', res[j++]?.returnData);
+ const [aux0, aux1] = getAmountsForLiquidity(
+ sqrtPriceX96,
+ Number(pos.tickLower),
+ Number(pos.tickUpper),
+ BigNumber.from(position.liquidity)
+ );
+ const inRange = Number(pos.tickLower) <= tick && tick < Number(pos.tickUpper);
+
+ amount0InAlm += BN2Number(aux0, token0Decimals);
+ amount1InAlm += BN2Number(aux1, token1Decimals);
+ if (inRange) liquidityInAlm = liquidityInAlm.add(position.liquidity);
+ }
+
+ // 5 - Balance / Total Supply
+ const supply = BN2Number(Erc20Interface.decodeFunctionResult('totalSupply', res[j++]?.returnData)[0]);
+ const balance = BN2Number(Erc20Interface.decodeFunctionResult('balanceOf', res[j++]?.returnData)[0]);
+ const proportion = balance / supply;
+
+ const userAmount0InAlm = proportion * amount0InAlm;
+ const userAmount1InAlm = proportion * amount1InAlm;
+
+ const type = ALMType[alm.origin];
+ const tvl = userAmount0InAlm * prices[token0Symbol] + userAmount1InAlm * prices[token1Symbol];
+ const positionRewards =
+ poolRewards.filter((p) => p.Origin === type)?.reduce((prev, curr) => prev + curr.Earned * prices[curr.Token], 0) ?? 0;
+
+ if (userAmount0InAlm !== 0 || userAmount1InAlm !== 0) {
+ stats.push({
+ type,
+ amount0: userAmount0InAlm,
+ amount1: userAmount1InAlm,
+ liquidity: liquidityInAlm
+ .mul(Math.round(proportion * 1e8))
+ .div(1e8)
+ .toString(),
+ tvl,
+ earned: positionRewards,
+ propFee: round((proportion * Int256.from(liquidityInAlm, 0).mul(10000).div(liquidityInPool).toNumber()) / 100, 2),
+ propAmount0: round((userAmount0InAlm / amount0InPool) * 100, 2),
+ propAmount1: round((userAmount1InAlm / amount1InPool) * 100, 2),
+ inducedAPR: round(((positionRewards * YEAR) / (endEpoch * HOUR - startEpoch * HOUR) / tvl) * 100, 3),
+ });
+ }
+ } catch (e) {
+ // console.error(e);
+ }
+ i =
+ i +
+ directPositions.filter((p) => p.owner === alm.address.toLowerCase())?.length +
+ nftPositions.filter((p) => p.owner === alm.address.toLowerCase())?.length +
+ 2;
+ }
+ }
+
+ if (log) {
+ console.log(`The TVL of the pool at block ${blockNumber} based on current prices was $${tvlInPool}`);
+ console.table(stats);
+ }
+ return stats;
+ };
+ if (log) console.log(`\nState of the pool at the beginning of the period (block ${startBlockNumber}): \n`);
+ const startStat = await analyzePoolState(startBlockNumber, log);
+
+ if (log) console.log(`\nState of the pool at the end of the period (block ${endBlockNumber}): \n`);
+ const endStat = await analyzePoolState(endBlockNumber, log);
+
+ return { startStat, endStat };
+};
+
+export function aggregatedStats(stats: UserStats[]): number {
+ const aggregatedStats = stats.reduce(
+ (curr: { tvl: number; normalisedEarned: number }, stat) => {
+ curr.tvl += stat.tvl;
+ curr.normalisedEarned += (stat.inducedAPR * stat.tvl) / 100;
+ return curr;
+ },
+ { tvl: 0, normalisedEarned: 0 }
+ );
+ return round((aggregatedStats.normalisedEarned / aggregatedStats.tvl) * 100, 3);
+}
+
+export const statsPoolRewardId = async (chainId: ChainId, pool: string, startEpoch: number, endEpoch: number, prices: Price) => {
+ const DistributionCreatorAddress = registry(chainId)?.Merkl?.DistributionCreator;
+
+ const provider = httpProvider(chainId);
+ const multicall = Multicall__factory.connect(MULTICALL_ADDRESS, provider);
+ const calls: Multicall3.Call3Struct[] = [];
+ const DistributionCreatorInterface = DistributionCreator__factory.createInterface();
+
+ // 0 - Pool generic data
+ calls.push({
+ allowFailure: true,
+ callData: DistributionCreatorInterface.encodeFunctionData('getDistributionsBetweenEpochs', [startEpoch * HOUR, endEpoch * HOUR]),
+ target: DistributionCreatorAddress,
+ });
+
+ const result = await multicall.callStatic.aggregate3(calls);
+
+ let i = 0;
+ const rewards = DistributionCreatorInterface.decodeFunctionResult(
+ 'getDistributionsBetweenEpochs',
+ result[i++]?.returnData
+ )?.[0] as ExtensiveDistributionParametersStructOutput[];
+ const filteredRewards = rewards.filter((rewards) => rewards.base.uniV3Pool.toLowerCase() === pool.toLowerCase());
+
+ const rewardsTokenAmount = filteredRewards.reduce(
+ (curr: { [token: string]: { tokenAddress: string; tokenDecimal: number; amount: number; dollarAmount: number } }, reward) => {
+ if (!curr['totalIncentives']) curr['totalIncentives'] = { tokenAddress: '', tokenDecimal: 0, amount: 0, dollarAmount: 0 };
+ const normalizer =
+ (Math.min(endEpoch, reward.base.epochStart / HOUR + reward.base.numEpoch) - Math.max(startEpoch, reward.base.epochStart / HOUR)) /
+ reward.base.numEpoch;
+ const amount = BN2Number(reward.base.amount, reward.rewardTokenDecimals) * normalizer;
+ const dollarAmount = amount * (prices[reward.rewardTokenSymbol] ?? 0);
+
+ if (!curr[reward.rewardTokenSymbol])
+ curr[reward.rewardTokenSymbol] = {
+ tokenAddress: reward.base.rewardToken,
+ tokenDecimal: reward.rewardTokenDecimals,
+ amount: amount,
+ dollarAmount: dollarAmount,
+ };
+ else {
+ curr[reward.rewardTokenSymbol].amount += amount;
+ curr[reward.rewardTokenSymbol].dollarAmount += dollarAmount;
+ }
+ curr['totalIncentives'].dollarAmount += dollarAmount;
+ return curr;
+ },
+ {} as { [token: string]: { tokenAddress: string; tokenDecimal: number; amount: number; dollarAmount: number } }
+ );
+
+ const distributions =
+ !!rewards &&
+ rewards.map((reward) => {
+ return {
+ base: {
+ additionalData: reward['base'].additionalData,
+ amount: reward['base'].amount,
+ boostedReward: reward['base'].boostedReward,
+ boostingAddress: reward['base'].boostingAddress,
+ epochStart: reward['base'].epochStart,
+ isOutOfRangeIncentivized: reward['base'].isOutOfRangeIncentivized,
+ numEpoch: reward['base'].numEpoch,
+ positionWrappers: reward['base'].positionWrappers,
+ propFees: reward['base'].propFees,
+ propToken0: reward['base'].propToken0,
+ propToken1: reward['base'].propToken1,
+ rewardId: reward['base'].rewardId,
+ rewardToken: reward['base'].rewardToken,
+ uniV3Pool: reward['base'].uniV3Pool,
+ wrapperTypes: reward['base'].wrapperTypes,
+ },
+ poolFee: reward.poolFee,
+ rewardTokenDecimals: reward.rewardTokenDecimals,
+ rewardTokenSymbol: reward.rewardTokenSymbol,
+ token0: {
+ add: reward['token0'].add,
+ decimals: reward['token0'].decimals,
+ poolBalance: reward['token0'].poolBalance,
+ symbol: reward['token0'].symbol,
+ },
+ token1: {
+ add: reward['token1'].add,
+ decimals: reward['token1'].decimals,
+ poolBalance: reward['token1'].poolBalance,
+ symbol: reward['token1'].symbol,
+ },
+ } as ExtensiveDistributionParametersStructOutput;
+ });
+ const distributionFiltered = distributions.filter((distribution) => distribution.base.uniV3Pool.toLowerCase() === pool.toLowerCase());
+
+ return { rewardsTokenAmount, distributionFiltered, distributions };
+};
+
+export const rewardsBreakdownPool = async (
+ pool: string,
+ startAccumulatedRewards: AggregatedRewardsType,
+ endAccumulatedRewards: AggregatedRewardsType
+) => {
+ /*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ INTERFACES
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
+
+ const filteredStartAccumulatedRewards = Object.keys(startAccumulatedRewards.rewards)
+ .filter((rewardId) => startAccumulatedRewards.rewards[rewardId].pool.toLowerCase() === pool.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: startAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ const filteredEndAccumulatedRewards = Object.keys(endAccumulatedRewards.rewards)
+ .filter((rewardId) => endAccumulatedRewards.rewards[rewardId].pool.toLowerCase() === pool.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: endAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ let holders = [];
+ const diffRewards = {} as UnderlyingTreeType;
+ const rewardsOriginBreakdown = {} as { [origin: string]: number };
+ Object.keys(filteredEndAccumulatedRewards).map((rewardId) => {
+ diffRewards[rewardId] = {} as MerklRewardDistributionType;
+ diffRewards[rewardId].holders = {};
+ const decimals = filteredEndAccumulatedRewards[rewardId].tokenDecimals;
+
+ Object.keys(filteredEndAccumulatedRewards[rewardId].holders).map((user) => {
+ const newAmount = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const oldAmount = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const newBreakdown = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+ const oldBreakdown = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+
+ if (newAmount !== oldAmount) {
+ const userInfo = {
+ amount: BN2Number(BigNumber.from(newAmount ?? 0).sub(oldAmount ?? 0), decimals).toString(),
+ breakdown: {} as { [origin: string]: number },
+ averageBoost: 0,
+ };
+
+ for (const reason of Object.keys(newBreakdown)) {
+ const earned = Int256.from(BigNumber.from(newBreakdown?.[reason] ?? 0).sub(oldBreakdown?.[reason] ?? 0), decimals).toNumber();
+ userInfo.breakdown[reason] = earned;
+ if (!rewardsOriginBreakdown[reason]) rewardsOriginBreakdown[reason] = 0;
+ rewardsOriginBreakdown[reason] += earned;
+ }
+
+ diffRewards[rewardId].holders[user] = userInfo;
+ }
+ });
+ if (Object.keys(diffRewards[rewardId].holders).length === 0) delete diffRewards[rewardId];
+ if (diffRewards[rewardId]) holders.push(...Object.keys(diffRewards[rewardId].holders));
+ });
+ holders = [...new Set(holders)];
+
+ return { diffRewards, rewardsOriginBreakdown, holders };
+};
+
+export const getReceiverToken = async (token: string, endAccumulatedRewards: AggregatedRewardsType) => {
+ const filteredEndAccumulatedRewards = Object.keys(endAccumulatedRewards.rewards)
+ .filter((rewardId) => endAccumulatedRewards.rewards[rewardId].token.toLowerCase() === token.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: endAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ let holders = [];
+ Object.keys(filteredEndAccumulatedRewards).map((rewardId) => {
+ holders.push(...Object.keys(filteredEndAccumulatedRewards[rewardId].holders));
+ });
+ holders = [...new Set(holders)];
+
+ return holders;
+};
+
+export const rewardsClaimed = async (
+ chainId: MerklSupportedChainIdsType,
+ pool: string,
+ tokenAddress: string,
+ tokenDecimals: number,
+ holders: string[],
+ startEpoch: number,
+ endEpoch: number,
+ startAccumulatedRewards: AggregatedRewardsType,
+ endAccumulatedRewards: AggregatedRewardsType
+) => {
+ /*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ INTERFACES
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
+ const distributorAddress = registry(chainId)?.Merkl?.Distributor;
+
+ const provider = httpProvider(chainId);
+ const multicall = Multicall__factory.connect(MULTICALL_ADDRESS, provider);
+ const calls: Multicall3.Call3Struct[] = [];
+ const DistributorInterface = Distributor__factory.createInterface();
+
+ const startBlockNumber = await getBlockAfterTimestamp(chainId, startEpoch * HOUR);
+ const endBlockNumber = await getBlockAfterTimestamp(chainId, endEpoch * HOUR);
+
+ // 1 - Check all on chain claimed rewards for the period
+ holders.map((holder) =>
+ calls.push({
+ allowFailure: true,
+ callData: DistributorInterface.encodeFunctionData('claimed', [holder, tokenAddress]),
+ target: distributorAddress,
+ })
+ );
+
+ const claimed = {} as { [holder: string]: number };
+
+ let result = await multicall.callStatic.aggregate3(calls, { blockTag: endBlockNumber });
+ holders.map(
+ (holder, i) =>
+ (claimed[holder] = BN2Number(DistributorInterface.decodeFunctionResult('claimed', result[i]?.returnData)?.[0], tokenDecimals))
+ );
+
+ result = await multicall.callStatic.aggregate3(calls, { blockTag: startBlockNumber });
+ holders.map(
+ (holder, i) =>
+ (claimed[holder] -= BN2Number(DistributorInterface.decodeFunctionResult('claimed', result[i]?.returnData)?.[0], tokenDecimals))
+ );
+
+ // 2 - Compute total claimable on the token for each users
+ const breakdownUserClaimable = {} as {
+ [holder: string]: { totalClaimable: { [breakdown: string]: number }; specificClaimable: { [breakdown: string]: number } };
+ };
+ // First filter them by token reward
+ const filteredStartAccumulatedRewards = Object.keys(startAccumulatedRewards.rewards)
+ .filter((rewardId) => startAccumulatedRewards.rewards[rewardId].token.toLowerCase() === tokenAddress.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: startAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ const filteredEndAccumulatedRewards = Object.keys(endAccumulatedRewards.rewards)
+ .filter((rewardId) => endAccumulatedRewards.rewards[rewardId].token.toLowerCase() === tokenAddress.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: endAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ Object.keys(filteredEndAccumulatedRewards).map((rewardId) => {
+ const rewardPool = filteredEndAccumulatedRewards[rewardId].pool;
+ const decimals = filteredEndAccumulatedRewards[rewardId].tokenDecimals;
+ Object.keys(filteredEndAccumulatedRewards[rewardId].holders).map((user) => {
+ if (holders.includes(user)) {
+ const newAmount = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const oldAmount = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const newBreakdown = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+ const oldBreakdown = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+
+ if (newAmount !== oldAmount) {
+ if (!breakdownUserClaimable[user]) breakdownUserClaimable[user] = { totalClaimable: {}, specificClaimable: {} };
+ const totalEarned = BN2Number(BigNumber.from(newAmount ?? 0).sub(oldAmount ?? 0), decimals);
+ if (!breakdownUserClaimable[user].totalClaimable['Total']) breakdownUserClaimable[user].totalClaimable['Total'] = 0;
+ breakdownUserClaimable[user].totalClaimable['Total'] += totalEarned;
+
+ if (pool.toLowerCase() === rewardPool.toLowerCase()) {
+ if (!breakdownUserClaimable[user].specificClaimable['Total']) breakdownUserClaimable[user].specificClaimable['Total'] = 0;
+ breakdownUserClaimable[user].specificClaimable['Total'] += totalEarned;
+ }
+
+ for (const reason of Object.keys(newBreakdown)) {
+ const earned = Int256.from(BigNumber.from(newBreakdown?.[reason] ?? 0).sub(oldBreakdown?.[reason] ?? 0), decimals).toNumber();
+ if (!breakdownUserClaimable[user].totalClaimable[reason]) breakdownUserClaimable[user].totalClaimable[reason] = 0;
+ breakdownUserClaimable[user].totalClaimable[reason] += earned;
+ if (pool.toLowerCase() === rewardPool.toLowerCase()) {
+ if (!breakdownUserClaimable[user].specificClaimable[reason]) breakdownUserClaimable[user].specificClaimable[reason] = 0;
+ breakdownUserClaimable[user].specificClaimable[reason] += earned;
+ }
+ }
+ }
+ }
+ });
+ });
+
+ // 3 Compute proportionnaly what the users have claimed
+ const breakdownUserClaimed = {} as {
+ [holder: string]: { [breakdown: string]: string };
+ };
+
+ Object.keys(breakdownUserClaimable).map((user) => {
+ breakdownUserClaimed[user] = {};
+ for (const origin of Object.keys(breakdownUserClaimable[user].totalClaimable)) {
+ const percentClaimed = breakdownUserClaimable[user].specificClaimable[origin] / breakdownUserClaimable[user].totalClaimable[origin];
+ breakdownUserClaimed[user][origin] =
+ breakdownUserClaimable[user].totalClaimable[origin] == 0 ? `${0}` : `${percentClaimed * claimed[user]} (${percentClaimed * 100} %)`;
+ }
+ });
+
+ return breakdownUserClaimed;
+};
+
+export const rewardsUnclaimed = async (
+ chainId: MerklSupportedChainIdsType,
+ tokenAddress: string,
+ tokenDecimals: number,
+ holders: string[],
+ startEpoch: number,
+ endEpoch: number,
+ startAccumulatedRewards: AggregatedRewardsType,
+ endAccumulatedRewards: AggregatedRewardsType
+) => {
+ /*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ INTERFACES
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
+ const distributorAddress = registry(chainId)?.Merkl?.Distributor;
+
+ const provider = httpProvider(chainId);
+ const multicall = Multicall__factory.connect(MULTICALL_ADDRESS, provider);
+ const calls: Multicall3.Call3Struct[] = [];
+ const DistributorInterface = Distributor__factory.createInterface();
+
+ const startBlockNumber = await getBlockAfterTimestamp(chainId, startEpoch * HOUR);
+ const endBlockNumber = await getBlockAfterTimestamp(chainId, endEpoch * HOUR);
+
+ // 1 - Check all on chain claimed rewards for the period
+ holders.map((holder) =>
+ calls.push({
+ allowFailure: true,
+ callData: DistributorInterface.encodeFunctionData('claimed', [holder, tokenAddress]),
+ target: distributorAddress,
+ })
+ );
+
+ const claimed = {} as { [holder: string]: number };
+
+ let result = await multicall.callStatic.aggregate3(calls, { blockTag: endBlockNumber });
+ holders.map(
+ (holder, i) =>
+ (claimed[holder] = BN2Number(DistributorInterface.decodeFunctionResult('claimed', result[i]?.returnData)?.[0], tokenDecimals))
+ );
+
+ result = await multicall.callStatic.aggregate3(calls, { blockTag: startBlockNumber });
+ holders.map(
+ (holder, i) =>
+ (claimed[holder] -= BN2Number(DistributorInterface.decodeFunctionResult('claimed', result[i]?.returnData)?.[0], tokenDecimals))
+ );
+
+ // First filter them by token reward
+ const filteredStartAccumulatedRewards = Object.keys(startAccumulatedRewards.rewards)
+ .filter((rewardId) => startAccumulatedRewards.rewards[rewardId].token.toLowerCase() === tokenAddress.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: startAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ const filteredEndAccumulatedRewards = Object.keys(endAccumulatedRewards.rewards)
+ .filter((rewardId) => endAccumulatedRewards.rewards[rewardId].token.toLowerCase() === tokenAddress.toLowerCase())
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: endAccumulatedRewards.rewards[key] });
+ }, {} as AggregatedRewardsType['rewards']);
+
+ const rewardsInfoClaim = {} as { [reason: string]: { claimable: number; claimed: number } };
+ if (!rewardsInfoClaim['Total'])
+ rewardsInfoClaim['Total'] = {
+ claimable: 0,
+ claimed: 0,
+ };
+ holders.map((holder) => {
+ rewardsInfoClaim['Total'].claimed += claimed[holder];
+ });
+ Object.keys(filteredEndAccumulatedRewards).map((rewardId) => {
+ const decimals = filteredEndAccumulatedRewards[rewardId].tokenDecimals;
+ Object.keys(filteredEndAccumulatedRewards[rewardId].holders).map((user) => {
+ if (holders.includes(user)) {
+ const newAmount = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const oldAmount = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.amount;
+ const newBreakdown = filteredEndAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+ const oldBreakdown = filteredStartAccumulatedRewards[rewardId]?.holders?.[user]?.breakdown;
+
+ if (newAmount !== oldAmount) {
+ const totalEarned = BN2Number(BigNumber.from(newAmount ?? 0).sub(oldAmount ?? 0), decimals);
+ if (!rewardsInfoClaim['Total']) rewardsInfoClaim['Total'] = { claimable: 0, claimed: 0 };
+ rewardsInfoClaim['Total'].claimable += totalEarned;
+
+ for (const reason of Object.keys(newBreakdown)) {
+ const earned = Int256.from(BigNumber.from(newBreakdown?.[reason] ?? 0).sub(oldBreakdown?.[reason] ?? 0), decimals).toNumber();
+ if (!rewardsInfoClaim[reason])
+ rewardsInfoClaim[reason] = {
+ claimable: 0,
+ claimed: 0,
+ };
+ rewardsInfoClaim[reason].claimable += earned;
+ }
+ }
+ }
+ });
+ });
+
+ return rewardsInfoClaim;
+};
diff --git a/src/utils/uniV3.ts b/src/utils/uniV3.ts
new file mode 100644
index 0000000..c54f6c7
--- /dev/null
+++ b/src/utils/uniV3.ts
@@ -0,0 +1,243 @@
+import { BigNumber, ethers } from 'ethers';
+import JSBI from 'jsbi';
+import invariant from 'tiny-invariant';
+
+/**
+ * The minimum tick that can be used on any pool.
+ */
+export const MIN_TICK = -887272;
+/**
+ * The maximum tick that can be used on any pool.
+ */
+export const MAX_TICK: number = -MIN_TICK;
+
+/**
+ * The sqrt ratio corresponding to the minimum tick that could be used on any pool.
+ */
+const MIN_SQRT_RATIO: JSBI = JSBI.BigInt('4295128739');
+/**
+ * The sqrt ratio corresponding to the maximum tick that could be used on any pool.
+ */
+const MAX_SQRT_RATIO: JSBI = JSBI.BigInt('1461446703485210103287273052203988822378723970342');
+
+function mulShift(val: JSBI, mulBy: string): JSBI {
+ return JSBI.signedRightShift(JSBI.multiply(val, JSBI.BigInt(mulBy)), JSBI.BigInt(128));
+}
+const Q32 = JSBI.exponentiate(JSBI.BigInt(2), JSBI.BigInt(32));
+const Q96 = JSBI.exponentiate(JSBI.BigInt(2), JSBI.BigInt(96));
+const MaxUint256 = JSBI.BigInt(ethers.constants.MaxUint256?.toString());
+const ZERO = JSBI.BigInt(0);
+const ONE = JSBI.BigInt(1);
+
+/**
+ * Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick
+ * @param tick the tick for which to compute the sqrt ratio
+ */
+export function getSqrtRatioAtTick(tick: number): JSBI {
+ invariant(tick >= MIN_TICK && tick <= MAX_TICK && Number.isInteger(tick), 'TICK');
+ const absTick: number = tick < 0 ? tick * -1 : tick;
+
+ let ratio: JSBI =
+ (absTick & 0x1) != 0 ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') : JSBI.BigInt('0x100000000000000000000000000000000');
+ if ((absTick & 0x2) != 0) ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a');
+ if ((absTick & 0x4) != 0) ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc');
+ if ((absTick & 0x8) != 0) ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0');
+ if ((absTick & 0x10) != 0) ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644');
+ if ((absTick & 0x20) != 0) ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0');
+ if ((absTick & 0x40) != 0) ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861');
+ if ((absTick & 0x80) != 0) ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053');
+ if ((absTick & 0x100) != 0) ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4');
+ if ((absTick & 0x200) != 0) ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54');
+ if ((absTick & 0x400) != 0) ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3');
+ if ((absTick & 0x800) != 0) ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9');
+ if ((absTick & 0x1000) != 0) ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825');
+ if ((absTick & 0x2000) != 0) ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5');
+ if ((absTick & 0x4000) != 0) ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7');
+ if ((absTick & 0x8000) != 0) ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6');
+ if ((absTick & 0x10000) != 0) ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9');
+ if ((absTick & 0x20000) != 0) ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604');
+ if ((absTick & 0x40000) != 0) ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98');
+ if ((absTick & 0x80000) != 0) ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2');
+
+ if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio);
+
+ // back to Q96
+ return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) ? JSBI.add(JSBI.divide(ratio, Q32), ONE) : JSBI.divide(ratio, Q32);
+}
+
+const TWO = JSBI.BigInt(2);
+const POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow: number): [number, JSBI] => [pow, JSBI.exponentiate(TWO, JSBI.BigInt(pow))]);
+function mostSignificantBit(x: JSBI): number {
+ invariant(JSBI.greaterThan(x, ZERO), 'ZERO');
+ invariant(JSBI.lessThanOrEqual(x, MaxUint256), 'MAX');
+
+ let msb = 0;
+ for (const [power, min] of POWERS_OF_2) {
+ if (JSBI.greaterThanOrEqual(x, min)) {
+ x = JSBI.signedRightShift(x, JSBI.BigInt(power));
+ msb += power;
+ }
+ }
+ return msb;
+}
+
+/**
+ * Returns the tick corresponding to a given sqrt ratio, s.t. #getSqrtRatioAtTick(tick) <= sqrtRatioX96
+ * and #getSqrtRatioAtTick(tick + 1) > sqrtRatioX96
+ * @param sqrtRatioX96 the sqrt ratio as a Q64.96 for which to compute the tick
+ */
+export function getTickAtSqrtRatio(sqrtRatioX96: JSBI): number {
+ invariant(JSBI.greaterThanOrEqual(sqrtRatioX96, MIN_SQRT_RATIO) && JSBI.lessThan(sqrtRatioX96, MAX_SQRT_RATIO), 'SQRT_RATIO');
+
+ const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32));
+
+ const msb = mostSignificantBit(sqrtRatioX128);
+
+ let r: JSBI;
+ if (JSBI.greaterThanOrEqual(JSBI.BigInt(msb), JSBI.BigInt(128))) {
+ r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127));
+ } else {
+ r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb));
+ }
+
+ let log_2: JSBI = JSBI.leftShift(JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)), JSBI.BigInt(64));
+
+ for (let i = 0; i < 14; i++) {
+ r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127));
+ const f = JSBI.signedRightShift(r, JSBI.BigInt(128));
+ log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i)));
+ r = JSBI.signedRightShift(r, f);
+ }
+
+ const log_sqrt10001 = JSBI.multiply(log_2, JSBI.BigInt('255738958999603826347141'));
+
+ const tickLow = JSBI.toNumber(
+ JSBI.signedRightShift(JSBI.subtract(log_sqrt10001, JSBI.BigInt('3402992956809132418596140100660247210')), JSBI.BigInt(128))
+ );
+ const tickHigh = JSBI.toNumber(
+ JSBI.signedRightShift(JSBI.add(log_sqrt10001, JSBI.BigInt('291339464771989622907027621153398088495')), JSBI.BigInt(128))
+ );
+
+ return tickLow === tickHigh ? tickLow : JSBI.lessThanOrEqual(getSqrtRatioAtTick(tickHigh), sqrtRatioX96) ? tickHigh : tickLow;
+}
+
+export const getAmount0ForLiquidity = (lowerTick: number, upperTick: number, liquidity: BigNumber): BigNumber => {
+ const sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ const sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+
+ return _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
+};
+
+const _getAmount0ForLiquidity = (sqrtRatioAX96: JSBI, sqrtRatioBX96: JSBI, liquidity: BigNumber): BigNumber => {
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ let JSBIRes = JSBI.multiply(JSBI.BigInt(liquidity?.shl(96).toString()), JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96));
+ JSBIRes = JSBI.divide(JSBIRes, sqrtRatioBX96);
+ JSBIRes = JSBI.divide(JSBIRes, sqrtRatioAX96);
+
+ const res = BigNumber.from(JSBIRes?.toString());
+ return res;
+};
+
+export const getAmount1ForLiquidity = (lowerTick: number, upperTick: number, liquidity: BigNumber): BigNumber => {
+ const sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ const sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+
+ return _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
+};
+
+const _getAmount1ForLiquidity = (sqrtRatioAX96: JSBI, sqrtRatioBX96: JSBI, liquidity: BigNumber): BigNumber => {
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ let JSBIRes = JSBI.multiply(JSBI.BigInt(liquidity?.toString()), JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96));
+ JSBIRes = JSBI.divide(JSBIRes, Q96);
+
+ const res = BigNumber.from(JSBIRes?.toString());
+ return res;
+};
+
+export const getAmountsForLiquidity = (sqrtRatioX96String: string, lowerTick: number, upperTick: number, liquidity: BigNumber) => {
+ let sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ let sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+ const sqrtRatioX96 = JSBI.BigInt(sqrtRatioX96String?.toString());
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ let amount0 = BigNumber.from(0);
+ let amount1 = BigNumber.from(0);
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioX96)) {
+ amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
+ } else if (JSBI.greaterThan(sqrtRatioBX96, sqrtRatioX96)) {
+ amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);
+ amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);
+ } else {
+ amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
+ }
+ return [amount0, amount1];
+};
+
+export const getLiquidityForAmount0 = (lowerTick: number, upperTick: number, amount0: BigNumber): BigNumber => {
+ let sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ let sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ const intermediate = JSBI.divide(JSBI.multiply(sqrtRatioAX96, sqrtRatioBX96), Q96);
+ let JSBIRes = JSBI.multiply(JSBI.BigInt(amount0?.toString()), intermediate);
+ JSBIRes = JSBI.divide(JSBIRes, JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96));
+
+ return BigNumber.from(JSBIRes?.toString());
+};
+
+export const getLiquidityForAmount1 = (lowerTick: number, upperTick: number, amount1: BigNumber): BigNumber => {
+ let sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ let sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ let JSBIRes = JSBI.multiply(JSBI.BigInt(amount1?.toString()), Q96);
+ JSBIRes = JSBI.divide(JSBIRes, JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96));
+
+ return BigNumber.from(JSBIRes?.toString());
+};
+
+export const getLiquidityForAmounts = (
+ tick: number,
+ lowerTick: number,
+ upperTick: number,
+ amount0: BigNumber,
+ amount1: BigNumber
+): BigNumber => {
+ let sqrtRatioAX96 = getSqrtRatioAtTick(lowerTick);
+ let sqrtRatioBX96 = getSqrtRatioAtTick(upperTick);
+ const sqrtRatioX96 = getSqrtRatioAtTick(tick);
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
+ sqrtRatioAX96 = sqrtRatioBX96;
+ sqrtRatioBX96 = sqrtRatioAX96;
+ }
+
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioX96)) {
+ return getLiquidityForAmount0(lowerTick, upperTick, amount0);
+ } else if (JSBI.greaterThan(sqrtRatioBX96, sqrtRatioX96)) {
+ const liquidity0 = getLiquidityForAmount0(tick, upperTick, amount0);
+ const liquidity1 = getLiquidityForAmount1(lowerTick, tick, amount1);
+
+ return liquidity0?.gt(liquidity1) ? liquidity1 : liquidity0;
+ } else {
+ return getLiquidityForAmount1(lowerTick, upperTick, amount1);
+ }
+};
diff --git a/tests/helpers/ManualChainProvider.ts b/tests/helpers/ManualChainProvider.ts
new file mode 100644
index 0000000..e24c9f3
--- /dev/null
+++ b/tests/helpers/ManualChainProvider.ts
@@ -0,0 +1,42 @@
+import { ExtensiveDistributionParametersStructOutput } from '@angleprotocol/sdk/dist/constants/types/DistributionCreator';
+import { BigNumber, ContractReceipt } from 'ethers';
+
+import OnChainProvider, { OnChainParams } from '../../src/providers/on-chain/OnChainProvider';
+import { HolderClaims } from '../../src/types/holders';
+
+export default class ManualChainProvider extends OnChainProvider {
+ claimedCall: () => HolderClaims;
+ activeDistributionCall: () => ExtensiveDistributionParametersStructOutput[];
+ poolNameCall: () => string;
+
+ constructor(
+ activeDistributionCall: () => ExtensiveDistributionParametersStructOutput[],
+ claimedCall: () => HolderClaims,
+ poolNameCall: () => string
+ ) {
+ super({ retries: 1, delay: 1, multiplier: 1 });
+ this.activeDistributionCall = activeDistributionCall;
+ this.claimedCall = claimedCall;
+ this.poolNameCall = poolNameCall;
+ }
+
+ override activeDistributions = async () => {
+ return this?.activeDistributionCall();
+ };
+
+ override claimed = async () => {
+ return this?.claimedCall();
+ };
+
+ override poolName = async () => {
+ return this.poolNameCall();
+ };
+
+ override onChainParams = async () => new Promise((_, reject) => reject());
+ override timestampAt = async () => new Promise((_, reject) => reject());
+ override approve = async () => new Promise((_, reject) => reject());
+ override dispute = async () => new Promise((_, reject) => reject());
+ override approval = async () => new Promise((_, reject) => reject());
+
+ override mountBlock = async () => new Promise((_, reject) => reject());
+}
diff --git a/tests/helpers/ManualMerkleRootsProvider.ts b/tests/helpers/ManualMerkleRootsProvider.ts
new file mode 100644
index 0000000..b3962d1
--- /dev/null
+++ b/tests/helpers/ManualMerkleRootsProvider.ts
@@ -0,0 +1,13 @@
+import { AggregatedRewardsType } from '@angleprotocol/sdk';
+
+import MerkleRootsProvider from '../../src/providers/merkl-roots/MerkleRootsProvider';
+
+export default class ManualMerkleRootsProvider extends MerkleRootsProvider {
+ constructor() {
+ super({ retries: 1, delay: 1, multiplier: 1 });
+ }
+
+ override epoch = async () => new Promise((_, reject) => reject());
+ override tree = async () => new Promise((_, reject) => reject());
+ override epochFromTimestamp = async () => new Promise((_, reject) => reject());
+}
diff --git a/tests/helpers/testData.ts b/tests/helpers/testData.ts
new file mode 100644
index 0000000..4565309
--- /dev/null
+++ b/tests/helpers/testData.ts
@@ -0,0 +1,88 @@
+import { AggregatedRewardsType, AMMType } from '@angleprotocol/sdk';
+import {
+ DistributionParametersStructOutput,
+ ExtensiveDistributionParametersStructOutput,
+ UniswapTokenDataStructOutput,
+} from '@angleprotocol/sdk/dist/constants/types/DistributionCreator';
+import { BigNumber } from 'ethers';
+
+import { HolderClaims } from '../../src/types/holders';
+
+export const createTree = (amount: string) => {
+ const defaultTree: AggregatedRewardsType = {
+ rewards: {
+ pesos: {
+ amm: AMMType.UniswapV3,
+ ammAlgo: 'UniswapV3',
+ boostedAddress: '0xbac10c87B134742D15dA0F8db7Ee252Ce7318534',
+ boostedReward: 1,
+ holders: {
+ '0xcaca6fE7DCD4BbA6053640Bf883bCA19d6d0eB82': {
+ amount,
+ averageBoost: 0,
+ },
+ },
+ lastUpdateEpoch: 1,
+ pool: 'PESOS-STERLING',
+ tokenSymbol: 'REWARDS',
+ tokenDecimals: 18,
+ token: '0xbac10c87B134742D15dA0F8db7Ee252Ce7318534',
+ totalAmount: '0',
+ },
+ },
+ updateTimestamp: 1,
+ lastUpdateEpoch: 0,
+ merklRoot: 'root',
+ };
+
+ return { ...defaultTree };
+};
+
+export const createActiveDistribution = () => {
+ const distribution: ExtensiveDistributionParametersStructOutput = {
+ base: {
+ rewardId: 'string',
+ uniV3Pool: 'string',
+ rewardToken: 'string',
+ amount: BigNumber.from(0),
+ positionWrappers: ['string'],
+ wrapperTypes: [0],
+ propToken0: 0,
+ propToken1: 0,
+ propFees: 0,
+ epochStart: 0,
+ numEpoch: 0,
+ isOutOfRangeIncentivized: 0,
+ boostedReward: 0,
+ boostingAddress: 'string',
+ additionalData: 'string',
+ } as DistributionParametersStructOutput,
+ poolFee: 1,
+ token0: {
+ add: 'string',
+ decimals: 18,
+ symbol: 'PESOS',
+ poolBalance: BigNumber.from(0),
+ } as UniswapTokenDataStructOutput,
+ token1: {
+ add: 'string',
+ decimals: 18,
+ symbol: 'PESOS',
+ poolBalance: BigNumber.from(0),
+ } as UniswapTokenDataStructOutput,
+ rewardTokenSymbol: 'REWARDS',
+ rewardTokenDecimals: 18,
+ } as ExtensiveDistributionParametersStructOutput;
+
+ return [distribution];
+};
+
+export const createClaims = (amount: string) => {
+ const claims: HolderClaims = {
+ '0xcaca6fE7DCD4BbA6053640Bf883bCA19d6d0eB82': {
+ '0xbac10c87B134742D15dA0F8db7Ee252Ce7318534': amount,
+ },
+ };
+
+ return claims;
+};
diff --git a/tests/history.test.ts b/tests/history.test.ts
new file mode 100644
index 0000000..c8b6246
--- /dev/null
+++ b/tests/history.test.ts
@@ -0,0 +1,38 @@
+import { ChainId, NETWORK_LABELS } from '@angleprotocol/sdk';
+import { expect } from 'chai';
+import { describe, it } from 'node:test';
+
+import { defaultContext, DisputeContext } from '../src/bot/context';
+import run, { runSteps } from '../src/bot/runner';
+import { BotError } from '../src/types/bot';
+
+type ProblematicBlock = {
+ chainId: number;
+ blockNumber: number;
+ errorCode?: number;
+};
+
+const tryAtBlock = async ({ chainId, blockNumber, errorCode }: ProblematicBlock) => {
+ const testContext: DisputeContext = defaultContext(chainId, blockNumber);
+ testContext.logger = undefined;
+ const result = await runSteps(testContext);
+ const testForError = !!errorCode;
+
+ console.log(`reason on ${NETWORK_LABELS[chainId]} at block ${blockNumber}:`, result.res.reason);
+
+ expect(result.err).to.equal(testForError);
+ testForError && result.err && expect(result.res.code).to.equal(errorCode);
+};
+
+describe('Known cases of past disputes', async function () {
+ it('Should output same errors cases from Merkl history', async function () {
+ const problematicBlocks: ProblematicBlock[] = [
+ { chainId: ChainId.MAINNET, blockNumber: 17812800, errorCode: BotError.NegativeDiff },
+ { chainId: ChainId.MAINNET, blockNumber: 18013500, errorCode: BotError.AlreadyClaimed }, // Aug 28 - Start of already claimed problem
+ { chainId: ChainId.MAINNET, blockNumber: 18052100, errorCode: BotError.AlreadyClaimed }, // Sep 2 - Still spreading incorrect claims...
+ { chainId: ChainId.MAINNET, blockNumber: 18059300, errorCode: undefined }, // Sep 4 - Rewards spread enough to cover anomaly
+ ];
+
+ await Promise.all(problematicBlocks.map(tryAtBlock));
+ });
+});
diff --git a/tests/holderDiffs.test.ts b/tests/holderDiffs.test.ts
new file mode 100644
index 0000000..2400a62
--- /dev/null
+++ b/tests/holderDiffs.test.ts
@@ -0,0 +1,60 @@
+import { assert, expect } from 'chai';
+import { describe, it } from 'node:test';
+
+import { DisputeContext } from '../src/bot/context';
+import { checkHolderValidity } from '../src/bot/runner';
+import ConsoleLogger from '../src/helpers/logger/ConsoleLogger';
+import { BotError, MerklReport, Resolver, StepResult } from '../src/types/bot';
+import ManualChainProvider from './helpers/ManualChainProvider';
+import ManualMerkleRootsProvider from './helpers/ManualMerkleRootsProvider';
+import { createActiveDistribution, createClaims, createTree } from './helpers/testData';
+
+describe('Errors in the differences between two trees', async function () {
+ it('Should catch on holder having a negative diff', async function () {
+ const testReport: MerklReport = {
+ startTree: createTree('1000000000000000000000'),
+ endTree: createTree('999999999999999999999'),
+ };
+
+ const testContext: DisputeContext = {
+ chainId: 1,
+ blockNumber: 0,
+ logger: new ConsoleLogger(),
+ onChainProvider: new ManualChainProvider(
+ createActiveDistribution,
+ () => createClaims('0'),
+ () => 'PESOS-STERLING'
+ ),
+ merkleRootsProvider: new ManualMerkleRootsProvider(),
+ };
+
+ const report = await checkHolderValidity(testContext, testReport);
+
+ expect(report.err).to.equal(true);
+ report.err && expect(report.res.code).to.equal(BotError.NegativeDiff);
+ });
+
+ it('Should not catch a negative diff if none', async function () {
+ const testReport: MerklReport = {
+ startTree: createTree('1000000000000000000000'),
+ endTree: createTree('1000000000000000000001'),
+ };
+
+ const testContext: DisputeContext = {
+ chainId: 1,
+ blockNumber: 0,
+ logger: new ConsoleLogger(),
+ onChainProvider: new ManualChainProvider(
+ createActiveDistribution,
+ () => createClaims('1000'),
+ () => 'PESOS-STERLING'
+ ),
+ merkleRootsProvider: new ManualMerkleRootsProvider(),
+ };
+
+
+ const report = await checkHolderValidity(testContext, testReport);
+
+ expect(report.err).to.equal(false);
+ });
+});
diff --git a/tests/overclaims.test.ts b/tests/overclaims.test.ts
new file mode 100644
index 0000000..45007c7
--- /dev/null
+++ b/tests/overclaims.test.ts
@@ -0,0 +1,64 @@
+import { expect } from 'chai';
+import { describe, it } from 'node:test';
+
+import { DisputeContext } from '../src/bot/context';
+import { checkHolderValidity, checkOverclaimedRewards } from '../src/bot/runner';
+import { validateHolders } from '../src/bot/validity';
+import ConsoleLogger from '../src/helpers/logger/ConsoleLogger';
+import { BotError, MerklReport, Resolver, StepResult } from '../src/types/bot';
+import ManualChainProvider from './helpers/ManualChainProvider';
+import ManualMerkleRootsProvider from './helpers/ManualMerkleRootsProvider';
+import { createActiveDistribution, createClaims, createTree } from './helpers/testData';
+
+describe('Overclaim detections', async function () {
+ it('Should catch on holder having overclaimed', async function () {
+ const testReport: MerklReport = {
+ startTree: createTree('1000000000000000000000'),
+ endTree: createTree('1000000000000000000001'),
+ };
+
+ const testContext: DisputeContext = {
+ chainId: 1,
+ blockNumber: 0,
+ logger: new ConsoleLogger(),
+ onChainProvider: new ManualChainProvider(
+ createActiveDistribution,
+ () => createClaims('1001000000000000000000'),
+ () => 'PESOS-STERLING'
+ ),
+ merkleRootsProvider: new ManualMerkleRootsProvider(),
+ };
+
+ const holdersReport = await checkHolderValidity(testContext, testReport);
+ const report = await checkOverclaimedRewards(testContext, holdersReport.res.report);
+
+ expect(report.err).to.equal(true);
+ report.err && expect(report.res.code).to.equal(BotError.AlreadyClaimed);
+ });
+
+ it('Should not catch on holder not having overclaimed', async function () {
+ const testReport: MerklReport = {
+ startTree: createTree('1000000000000000000000'),
+ endTree: createTree('1000000000000000000001'),
+ };
+
+ const testContext: DisputeContext = {
+ chainId: 1,
+ blockNumber: 0,
+ logger: new ConsoleLogger(),
+ onChainProvider: new ManualChainProvider(
+ createActiveDistribution,
+ () => createClaims('1000000000000000000002'),
+ () => 'PESOS-STERLING'
+ ),
+ merkleRootsProvider: new ManualMerkleRootsProvider(),
+ };
+
+ const holdersReport = await validateHolders(testContext.onChainProvider, testReport.startTree, testReport.endTree);
+ testReport.holdersReport = holdersReport;
+
+ const report = await checkOverclaimedRewards(testContext, testReport);
+ console.log(report);
+ expect(report.err).to.equal(false);
+ });
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..f854a08
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es2020",
+ "module": "commonjs",
+ "strict": false,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "sourceMap": true,
+ "outDir": "build"
+ },
+ "include": ["src"]
+}
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..0bb3c41
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4099 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@angleprotocol/sdk@^3.0.118":
+ version "3.0.118"
+ resolved "https://registry.yarnpkg.com/@angleprotocol/sdk/-/sdk-3.0.118.tgz#63dd9726502606fbe46c155b319d97dd5ca0f802"
+ integrity sha512-jb0OtjOtJ28WglPZOYClHWxKxZ96brvssw2jGvQjvoz0bQWSYq5pfj2sax7Aa8S7cTXHJbEou3hyj6u4m53yUA==
+ dependencies:
+ "@typechain/ethers-v5" "^10.0.0"
+ "@types/lodash" "^4.14.180"
+ ethers "^5.6.4"
+ graphql "^15.7.1"
+ graphql-request "^3.6.1"
+ jsbi "^4.3.0"
+ keccak256 "^1.0.6"
+ lodash "^4.17.21"
+ merkletreejs "^0.3.10"
+ tiny-invariant "^1.1.0"
+ typechain "^8.0.0"
+
+"@babel/parser@^7.20.15":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.5.tgz#721fd042f3ce1896238cf1b341c77eb7dee7dbea"
+ integrity sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==
+
+"@cspotcode/source-map-support@^0.8.0":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
+ integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
+ dependencies:
+ "@jridgewell/trace-mapping" "0.3.9"
+
+"@discordjs/builders@^1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@discordjs/builders/-/builders-1.6.3.tgz#994b4fe57e77b47096f74bb5a1f664870a930a43"
+ integrity sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==
+ dependencies:
+ "@discordjs/formatters" "^0.3.1"
+ "@discordjs/util" "^0.3.1"
+ "@sapphire/shapeshift" "^3.8.2"
+ discord-api-types "^0.37.41"
+ fast-deep-equal "^3.1.3"
+ ts-mixer "^6.0.3"
+ tslib "^2.5.0"
+
+"@discordjs/collection@^1.5.1":
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-1.5.1.tgz#bc7ca557838dc29247bf19860426637f103bc383"
+ integrity sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==
+
+"@discordjs/formatters@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@discordjs/formatters/-/formatters-0.3.1.tgz#81393cf25e6e3223361061629752ea727475e842"
+ integrity sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==
+ dependencies:
+ discord-api-types "^0.37.41"
+
+"@discordjs/rest@^1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@discordjs/rest/-/rest-1.7.1.tgz#eeef0e71a37c95fa27962129729b2aa9de8e3752"
+ integrity sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==
+ dependencies:
+ "@discordjs/collection" "^1.5.1"
+ "@discordjs/util" "^0.3.0"
+ "@sapphire/async-queue" "^1.5.0"
+ "@sapphire/snowflake" "^3.4.2"
+ discord-api-types "^0.37.41"
+ file-type "^18.3.0"
+ tslib "^2.5.0"
+ undici "^5.22.0"
+
+"@discordjs/util@^0.3.0", "@discordjs/util@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@discordjs/util/-/util-0.3.1.tgz#4e8737e1dcff7e9f5eccc3116fb44755b65b1e97"
+ integrity sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==
+
+"@discordjs/ws@^0.8.3":
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/@discordjs/ws/-/ws-0.8.3.tgz#77db8d563b731a2198c1b40f63b1ef8d230504f7"
+ integrity sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==
+ dependencies:
+ "@discordjs/collection" "^1.5.1"
+ "@discordjs/rest" "^1.7.1"
+ "@discordjs/util" "^0.3.1"
+ "@sapphire/async-queue" "^1.5.0"
+ "@types/ws" "^8.5.4"
+ "@vladfrangu/async_event_emitter" "^2.2.1"
+ discord-api-types "^0.37.41"
+ tslib "^2.5.0"
+ ws "^8.13.0"
+
+"@eslint-community/eslint-utils@^4.2.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.4.0":
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884"
+ integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==
+
+"@eslint/eslintrc@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331"
+ integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^9.5.2"
+ globals "^13.19.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/js@8.43.0":
+ version "8.43.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.43.0.tgz#559ca3d9ddbd6bf907ad524320a0d14b85586af0"
+ integrity sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==
+
+"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449"
+ integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==
+ dependencies:
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/hash" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+
+"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef"
+ integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==
+ dependencies:
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/networks" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+ "@ethersproject/web" "^5.7.0"
+
+"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2"
+ integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==
+ dependencies:
+ "@ethersproject/abstract-provider" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+
+"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37"
+ integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==
+ dependencies:
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/rlp" "^5.7.0"
+
+"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c"
+ integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+
+"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b"
+ integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+
+"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2"
+ integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ bn.js "^5.2.1"
+
+"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d"
+ integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==
+ dependencies:
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e"
+ integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==
+ dependencies:
+ "@ethersproject/bignumber" "^5.7.0"
+
+"@ethersproject/contracts@5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e"
+ integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==
+ dependencies:
+ "@ethersproject/abi" "^5.7.0"
+ "@ethersproject/abstract-provider" "^5.7.0"
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+
+"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7"
+ integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==
+ dependencies:
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/base64" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+
+"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf"
+ integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==
+ dependencies:
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/basex" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/pbkdf2" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/sha2" "^5.7.0"
+ "@ethersproject/signing-key" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+ "@ethersproject/wordlists" "^5.7.0"
+
+"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360"
+ integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==
+ dependencies:
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/hdnode" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/pbkdf2" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/random" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+ aes-js "3.0.0"
+ scrypt-js "3.0.1"
+
+"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a"
+ integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ js-sha3 "0.8.0"
+
+"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892"
+ integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==
+
+"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0":
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6"
+ integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==
+ dependencies:
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102"
+ integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/sha2" "^5.7.0"
+
+"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30"
+ integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==
+ dependencies:
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/providers@5.7.2":
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb"
+ integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==
+ dependencies:
+ "@ethersproject/abstract-provider" "^5.7.0"
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/base64" "^5.7.0"
+ "@ethersproject/basex" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/hash" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/networks" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/random" "^5.7.0"
+ "@ethersproject/rlp" "^5.7.0"
+ "@ethersproject/sha2" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+ "@ethersproject/web" "^5.7.0"
+ bech32 "1.1.4"
+ ws "7.4.6"
+
+"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c"
+ integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304"
+ integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb"
+ integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ hash.js "1.1.7"
+
+"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3"
+ integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ bn.js "^5.2.1"
+ elliptic "6.5.4"
+ hash.js "1.1.7"
+
+"@ethersproject/solidity@5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8"
+ integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==
+ dependencies:
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/sha2" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+
+"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2"
+ integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b"
+ integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==
+ dependencies:
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/rlp" "^5.7.0"
+ "@ethersproject/signing-key" "^5.7.0"
+
+"@ethersproject/units@5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1"
+ integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==
+ dependencies:
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/constants" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+
+"@ethersproject/wallet@5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d"
+ integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==
+ dependencies:
+ "@ethersproject/abstract-provider" "^5.7.0"
+ "@ethersproject/abstract-signer" "^5.7.0"
+ "@ethersproject/address" "^5.7.0"
+ "@ethersproject/bignumber" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/hash" "^5.7.0"
+ "@ethersproject/hdnode" "^5.7.0"
+ "@ethersproject/json-wallets" "^5.7.0"
+ "@ethersproject/keccak256" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/random" "^5.7.0"
+ "@ethersproject/signing-key" "^5.7.0"
+ "@ethersproject/transactions" "^5.7.0"
+ "@ethersproject/wordlists" "^5.7.0"
+
+"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0":
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae"
+ integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==
+ dependencies:
+ "@ethersproject/base64" "^5.7.0"
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+
+"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0":
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5"
+ integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==
+ dependencies:
+ "@ethersproject/bytes" "^5.7.0"
+ "@ethersproject/hash" "^5.7.0"
+ "@ethersproject/logger" "^5.7.0"
+ "@ethersproject/properties" "^5.7.0"
+ "@ethersproject/strings" "^5.7.0"
+
+"@google-cloud/secret-manager@^4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@google-cloud/secret-manager/-/secret-manager-4.2.2.tgz#4c0e7a169e91d3f6f27d31252e9065c85d8fe802"
+ integrity sha512-76yXN21ahrZMJKjs+gNoVWrSmioxqF2A2jKyDxRRq0DjSfoLHXb8POipjsTMErc1R1S7J7LToK2iLsi8lJyZqw==
+ dependencies:
+ google-gax "^3.5.8"
+
+"@graphql-typed-document-node/core@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
+ integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
+
+"@grpc/grpc-js@~1.8.0":
+ version "1.8.16"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.16.tgz#9a1b93703c065fde20b90d854126aadb89f4f0bd"
+ integrity sha512-Nvlq4V7XQmdRVDGgecR8ZPPCeY+uH1LhzbC+QxklwAahpQlq8YLsiOQgfkub9FiakRiohaDy361xqlTLkq9EHw==
+ dependencies:
+ "@grpc/proto-loader" "^0.7.0"
+ "@types/node" ">=12.12.47"
+
+"@grpc/proto-loader@^0.7.0":
+ version "0.7.7"
+ resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.7.tgz#d33677a77eea8407f7c66e2abd97589b60eb4b21"
+ integrity sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==
+ dependencies:
+ "@types/long" "^4.0.1"
+ lodash.camelcase "^4.3.0"
+ long "^4.0.0"
+ protobufjs "^7.0.0"
+ yargs "^17.7.2"
+
+"@humanwhocodes/config-array@^0.11.10":
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
+ integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
+ dependencies:
+ "@humanwhocodes/object-schema" "^1.2.1"
+ debug "^4.1.1"
+ minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^1.2.1":
+ 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==
+
+"@jridgewell/resolve-uri@^3.0.3":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/sourcemap-codec@^1.4.10":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@0.3.9":
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
+ integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.0.3"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@jsdoc/salty@^0.2.1":
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/@jsdoc/salty/-/salty-0.2.5.tgz#1b2fa5bb8c66485b536d86eee877c263d322f692"
+ integrity sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==
+ dependencies:
+ lodash "^4.17.21"
+
+"@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", "@nodelib/fs.walk@^1.2.8":
+ 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"
+
+"@octokit/auth-token@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db"
+ integrity sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==
+
+"@octokit/core@^4.2.1":
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.4.tgz#d8769ec2b43ff37cc3ea89ec4681a20ba58ef907"
+ integrity sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==
+ dependencies:
+ "@octokit/auth-token" "^3.0.0"
+ "@octokit/graphql" "^5.0.0"
+ "@octokit/request" "^6.0.0"
+ "@octokit/request-error" "^3.0.0"
+ "@octokit/types" "^9.0.0"
+ before-after-hook "^2.2.0"
+ universal-user-agent "^6.0.0"
+
+"@octokit/endpoint@^7.0.0":
+ version "7.0.6"
+ resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.6.tgz#791f65d3937555141fb6c08f91d618a7d645f1e2"
+ integrity sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==
+ dependencies:
+ "@octokit/types" "^9.0.0"
+ is-plain-object "^5.0.0"
+ universal-user-agent "^6.0.0"
+
+"@octokit/graphql@^5.0.0":
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.6.tgz#9eac411ac4353ccc5d3fca7d76736e6888c5d248"
+ integrity sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==
+ dependencies:
+ "@octokit/request" "^6.0.0"
+ "@octokit/types" "^9.0.0"
+ universal-user-agent "^6.0.0"
+
+"@octokit/openapi-types@^18.0.0":
+ version "18.0.0"
+ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.0.0.tgz#f43d765b3c7533fd6fb88f3f25df079c24fccf69"
+ integrity sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==
+
+"@octokit/plugin-paginate-rest@^6.1.2":
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz#f86456a7a1fe9e58fec6385a85cf1b34072341f8"
+ integrity sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==
+ dependencies:
+ "@octokit/tsconfig" "^1.0.2"
+ "@octokit/types" "^9.2.3"
+
+"@octokit/plugin-request-log@^1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
+ integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
+
+"@octokit/plugin-rest-endpoint-methods@^7.1.2":
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz#37a84b171a6cb6658816c82c4082ac3512021797"
+ integrity sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==
+ dependencies:
+ "@octokit/types" "^10.0.0"
+
+"@octokit/request-error@^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69"
+ integrity sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==
+ dependencies:
+ "@octokit/types" "^9.0.0"
+ deprecation "^2.0.0"
+ once "^1.4.0"
+
+"@octokit/request@^6.0.0":
+ version "6.2.8"
+ resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.8.tgz#aaf480b32ab2b210e9dadd8271d187c93171d8eb"
+ integrity sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==
+ dependencies:
+ "@octokit/endpoint" "^7.0.0"
+ "@octokit/request-error" "^3.0.0"
+ "@octokit/types" "^9.0.0"
+ is-plain-object "^5.0.0"
+ node-fetch "^2.6.7"
+ universal-user-agent "^6.0.0"
+
+"@octokit/rest@19.0.13":
+ version "19.0.13"
+ resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.13.tgz#e799393264edc6d3c67eeda9e5bd7832dcf974e4"
+ integrity sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==
+ dependencies:
+ "@octokit/core" "^4.2.1"
+ "@octokit/plugin-paginate-rest" "^6.1.2"
+ "@octokit/plugin-request-log" "^1.0.4"
+ "@octokit/plugin-rest-endpoint-methods" "^7.1.2"
+
+"@octokit/tsconfig@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@octokit/tsconfig/-/tsconfig-1.0.2.tgz#59b024d6f3c0ed82f00d08ead5b3750469125af7"
+ integrity sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==
+
+"@octokit/types@^10.0.0":
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-10.0.0.tgz#7ee19c464ea4ada306c43f1a45d444000f419a4a"
+ integrity sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==
+ dependencies:
+ "@octokit/openapi-types" "^18.0.0"
+
+"@octokit/types@^9.0.0", "@octokit/types@^9.2.3":
+ version "9.3.2"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5"
+ integrity sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==
+ dependencies:
+ "@octokit/openapi-types" "^18.0.0"
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+ integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+ integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+ integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+ integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
+
+"@protobufjs/fetch@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+ integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.1"
+ "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+ integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/inquire@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+ integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
+
+"@protobufjs/path@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+ integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+ integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+ integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+
+"@sapphire/async-queue@^1.5.0":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@sapphire/async-queue/-/async-queue-1.5.0.tgz#2f255a3f186635c4fb5a2381e375d3dfbc5312d8"
+ integrity sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==
+
+"@sapphire/shapeshift@^3.8.2":
+ version "3.9.2"
+ resolved "https://registry.yarnpkg.com/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz#a9c12cd51e1bc467619bb56df804450dd14871ac"
+ integrity sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ lodash "^4.17.21"
+
+"@sapphire/snowflake@^3.4.2":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.5.1.tgz#254521c188b49e8b2d4cc048b475fb2b38737fec"
+ integrity sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==
+
+"@tokenizer/token@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
+ integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
+
+"@tsconfig/node10@^1.0.7":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
+ integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
+
+"@tsconfig/node12@^1.0.7":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
+ integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
+
+"@tsconfig/node14@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
+ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
+
+"@tsconfig/node16@^1.0.2":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
+ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
+
+"@typechain/ethers-v5@^10.0.0":
+ version "10.2.1"
+ resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz#50241e6957683281ecfa03fb5a6724d8a3ce2391"
+ integrity sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==
+ dependencies:
+ lodash "^4.17.15"
+ ts-essentials "^7.0.1"
+
+"@types/bn.js@^5.1.0":
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682"
+ integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==
+ dependencies:
+ "@types/node" "*"
+
+"@types/body-parser@*":
+ version "1.19.2"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
+ integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==
+ dependencies:
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/chai@^4.3.6":
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.6.tgz#7b489e8baf393d5dd1266fb203ddd4ea941259e6"
+ integrity sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==
+
+"@types/connect@*":
+ version "3.4.35"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
+ integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/express-serve-static-core@^4.17.33":
+ version "4.17.35"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f"
+ integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express@^4.17.13":
+ version "4.17.17"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4"
+ integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.33"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/glob@*":
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.1.0.tgz#b63e70155391b0584dce44e7ea25190bbc38f2fc"
+ integrity sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==
+ dependencies:
+ "@types/minimatch" "^5.1.2"
+ "@types/node" "*"
+
+"@types/graceful-fs@^4.1.5":
+ version "4.1.6"
+ resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae"
+ integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==
+ dependencies:
+ "@types/node" "*"
+
+"@types/http-errors@*":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65"
+ integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==
+
+"@types/json-schema@^7.0.9":
+ version "7.0.12"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
+ integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
+
+"@types/linkify-it@*":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9"
+ integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==
+
+"@types/lodash@^4.14.180":
+ version "4.14.195"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632"
+ integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==
+
+"@types/long@^4.0.0", "@types/long@^4.0.1":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
+ integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
+
+"@types/markdown-it@^12.2.3":
+ version "12.2.3"
+ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51"
+ integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==
+ dependencies:
+ "@types/linkify-it" "*"
+ "@types/mdurl" "*"
+
+"@types/mdurl@*":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9"
+ integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==
+
+"@types/mime@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
+ integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
+
+"@types/mime@^1":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
+ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
+
+"@types/minimatch@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
+
+"@types/mocha@^10.0.1":
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
+ integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==
+
+"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
+ version "20.3.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.2.tgz#fa6a90f2600e052a03c18b8cb3fd83dd4e599898"
+ integrity sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==
+
+"@types/node@^16.9.6":
+ version "16.18.37"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.37.tgz#a1f8728e4dc30163deb41e9b7aba65d0c2d4eda1"
+ integrity sha512-ql+4dw4PlPFBP495k8JzUX/oMNRI2Ei4PrMHgj8oT4VhGlYUzF4EYr0qk2fW+XBVGIrq8Zzk13m4cvyXZuv4pA==
+
+"@types/pbkdf2@^3.0.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1"
+ integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/prettier@^2.1.1":
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f"
+ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==
+
+"@types/qs@*":
+ version "6.9.7"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
+ integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
+
+"@types/range-parser@*":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
+ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
+
+"@types/rimraf@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8"
+ integrity sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==
+ dependencies:
+ "@types/glob" "*"
+ "@types/node" "*"
+
+"@types/secp256k1@^4.0.1":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c"
+ integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==
+ dependencies:
+ "@types/node" "*"
+
+"@types/semver@^7.3.12":
+ version "7.5.0"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
+ integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
+
+"@types/send@*":
+ version "0.17.1"
+ resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301"
+ integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==
+ dependencies:
+ "@types/mime" "^1"
+ "@types/node" "*"
+
+"@types/serve-static@*":
+ version "1.15.2"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a"
+ integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==
+ dependencies:
+ "@types/http-errors" "*"
+ "@types/mime" "*"
+ "@types/node" "*"
+
+"@types/ws@^8.5.4":
+ version "8.5.5"
+ resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
+ integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==
+ dependencies:
+ "@types/node" "*"
+
+"@typescript-eslint/eslint-plugin@^5.2.0":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.1.tgz#81382d6ecb92b8dda70e91f9035611cb2fecd1c3"
+ integrity sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==
+ dependencies:
+ "@eslint-community/regexpp" "^4.4.0"
+ "@typescript-eslint/scope-manager" "5.60.1"
+ "@typescript-eslint/type-utils" "5.60.1"
+ "@typescript-eslint/utils" "5.60.1"
+ debug "^4.3.4"
+ grapheme-splitter "^1.0.4"
+ ignore "^5.2.0"
+ natural-compare-lite "^1.4.0"
+ semver "^7.3.7"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/parser@^5.2.0":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.60.1.tgz#0f2f58209c0862a73e3d5a56099abfdfa21d0fd3"
+ integrity sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.60.1"
+ "@typescript-eslint/types" "5.60.1"
+ "@typescript-eslint/typescript-estree" "5.60.1"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.60.1.tgz#35abdb47f500c68c08f2f2b4f22c7c79472854bb"
+ integrity sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ==
+ dependencies:
+ "@typescript-eslint/types" "5.60.1"
+ "@typescript-eslint/visitor-keys" "5.60.1"
+
+"@typescript-eslint/type-utils@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.60.1.tgz#17770540e98d65ab4730c7aac618003f702893f4"
+ integrity sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "5.60.1"
+ "@typescript-eslint/utils" "5.60.1"
+ debug "^4.3.4"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/types@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.60.1.tgz#a17473910f6b8d388ea83c9d7051af89c4eb7561"
+ integrity sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg==
+
+"@typescript-eslint/typescript-estree@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.1.tgz#8c71824b7165b64d5ebd7aa42968899525959834"
+ integrity sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==
+ dependencies:
+ "@typescript-eslint/types" "5.60.1"
+ "@typescript-eslint/visitor-keys" "5.60.1"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ semver "^7.3.7"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/utils@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.60.1.tgz#6861ebedbefba1ac85482d2bdef6f2ff1eb65b80"
+ integrity sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@types/json-schema" "^7.0.9"
+ "@types/semver" "^7.3.12"
+ "@typescript-eslint/scope-manager" "5.60.1"
+ "@typescript-eslint/types" "5.60.1"
+ "@typescript-eslint/typescript-estree" "5.60.1"
+ eslint-scope "^5.1.1"
+ semver "^7.3.7"
+
+"@typescript-eslint/visitor-keys@5.60.1":
+ version "5.60.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.1.tgz#19a877358bf96318ec35d90bfe6bd1445cce9434"
+ integrity sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw==
+ dependencies:
+ "@typescript-eslint/types" "5.60.1"
+ eslint-visitor-keys "^3.3.0"
+
+"@vladfrangu/async_event_emitter@^2.2.1":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz#84c5a3f8d648842cec5cc649b88df599af32ed88"
+ integrity sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+abort-controller@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
+ integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
+ dependencies:
+ event-target-shim "^5.0.0"
+
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-jsx@^5.3.2:
+ 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@^8.4.1, acorn@^8.8.0:
+ version "8.9.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59"
+ integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
+
+aes-js@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d"
+ integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==
+
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
+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"
+
+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.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ 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@^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-back@^3.0.1, array-back@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
+ integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+
+array-back@^4.0.1, array-back@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e"
+ integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+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==
+
+arrify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
+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==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
+ integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
+ dependencies:
+ follow-redirects "^1.14.9"
+ form-data "^4.0.0"
+
+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==
+
+base-x@^3.0.2:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
+ integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+base64-js@^1.3.0, base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+bech32@1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9"
+ integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==
+
+before-after-hook@^2.2.0:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
+ integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==
+
+bignumber.js@^9.0.0, bignumber.js@^9.0.1:
+ version "9.1.1"
+ resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6"
+ integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==
+
+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==
+
+blakejs@^1.1.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814"
+ integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==
+
+bluebird@^3.7.2:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
+ integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
+
+bn.js@4.11.6:
+ version "4.11.6"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+ integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==
+
+bn.js@^4.11.9:
+ 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.1.2, bn.js@^5.2.0, bn.js@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
+ integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
+
+body-parser@1.20.1:
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
+ integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.1"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+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"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.2, 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"
+
+brorand@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+ integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
+
+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==
+
+browserify-aes@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+ integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
+ dependencies:
+ buffer-xor "^1.0.3"
+ cipher-base "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.3"
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+bs58@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
+ integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==
+ dependencies:
+ base-x "^3.0.2"
+
+bs58check@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
+ integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==
+ dependencies:
+ bs58 "^4.0.0"
+ create-hash "^1.1.0"
+ safe-buffer "^5.1.2"
+
+buffer-equal-constant-time@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+ integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
+
+buffer-reverse@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60"
+ integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==
+
+buffer-xor@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+ integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==
+
+buffer@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
+ integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.2.1"
+
+busboy@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
+ integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
+ dependencies:
+ streamsearch "^1.1.0"
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.0:
+ 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==
+
+catharsis@^0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121"
+ integrity sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==
+ dependencies:
+ lodash "^4.17.15"
+
+chai@^4.3.8:
+ version "4.3.8"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.8.tgz#40c59718ad6928da6629c70496fe990b2bb5b17c"
+ integrity sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==
+ dependencies:
+ assertion-error "^1.1.0"
+ check-error "^1.0.2"
+ deep-eql "^4.1.2"
+ get-func-name "^2.0.0"
+ loupe "^2.3.1"
+ pathval "^1.1.1"
+ type-detect "^4.0.5"
+
+chalk@^2.4.2:
+ 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 sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
+
+chokidar@3.5.3, chokidar@^3.5.2:
+ 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"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+ integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+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"
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ 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 sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+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"
+
+command-line-args@^5.1.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e"
+ integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==
+ dependencies:
+ array-back "^3.1.0"
+ find-replace "^3.0.0"
+ lodash.camelcase "^4.3.0"
+ typical "^4.0.0"
+
+command-line-usage@^6.1.0:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957"
+ integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==
+ dependencies:
+ array-back "^4.0.2"
+ chalk "^2.4.2"
+ table-layout "^1.0.2"
+ typical "^5.2.0"
+
+commander@^11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67"
+ integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
+ dependencies:
+ cipher-base "^1.0.1"
+ inherits "^2.0.1"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
+ sha.js "^2.4.0"
+
+create-hmac@^1.1.4, create-hmac@^1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
+ dependencies:
+ cipher-base "^1.0.3"
+ create-hash "^1.1.0"
+ inherits "^2.0.1"
+ ripemd160 "^2.0.0"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+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-fetch@^3.0.6:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c"
+ integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==
+ dependencies:
+ node-fetch "^2.6.11"
+
+cross-fetch@^3.1.5:
+ version "3.1.8"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
+ integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
+ dependencies:
+ node-fetch "^2.6.12"
+
+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"
+
+crypto-js@^3.1.9-1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b"
+ integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==
+
+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@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+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@^4.1.2:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d"
+ integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==
+ dependencies:
+ type-detect "^4.0.0"
+
+deep-extend@~0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deep-is@^0.1.3, 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==
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+deprecation@^2.0.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
+ integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+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"
+
+discord-api-types@^0.37.41:
+ version "0.37.49"
+ resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.49.tgz#b3d4502a7b18dfac07cceadd4e4de7a95211948a"
+ integrity sha512-a2vvjgmE/1cPtXOuOh5zHlLe+qheu0uO625K+FyZVFomoCmpV1xNpadC48S98K30CnQ4/XJyFGnOZLXxAyBbCQ==
+
+discord.js@^14.7.1:
+ version "14.11.0"
+ resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-14.11.0.tgz#6529d49f30d10fc5a9ff8e6796661aa998769afe"
+ integrity sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==
+ dependencies:
+ "@discordjs/builders" "^1.6.3"
+ "@discordjs/collection" "^1.5.1"
+ "@discordjs/formatters" "^0.3.1"
+ "@discordjs/rest" "^1.7.1"
+ "@discordjs/util" "^0.3.1"
+ "@discordjs/ws" "^0.8.3"
+ "@sapphire/snowflake" "^3.4.2"
+ "@types/ws" "^8.5.4"
+ discord-api-types "^0.37.41"
+ fast-deep-equal "^3.1.3"
+ lodash.snakecase "^4.1.1"
+ tslib "^2.5.0"
+ undici "^5.22.0"
+ ws "^8.13.0"
+
+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"
+
+dotenv@^16.0.1:
+ version "16.3.1"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
+ integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
+
+duplexify@^4.0.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0"
+ integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==
+ dependencies:
+ end-of-stream "^1.4.1"
+ inherits "^2.0.3"
+ readable-stream "^3.1.1"
+ stream-shift "^1.0.0"
+
+ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
+ integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+elliptic@6.5.4, elliptic@^6.5.4:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
+ integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
+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==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+end-of-stream@^1.4.1:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+entities@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
+ integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+
+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-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
+escodegen@^1.13.0:
+ version "1.14.3"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
+ integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
+ dependencies:
+ esprima "^4.0.1"
+ estraverse "^4.2.0"
+ esutils "^2.0.2"
+ optionator "^0.8.1"
+ optionalDependencies:
+ source-map "~0.6.1"
+
+eslint-config-prettier@^8.3.0:
+ version "8.8.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348"
+ integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
+
+eslint-plugin-prettier@^4.0.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
+ integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
+ dependencies:
+ prettier-linter-helpers "^1.0.0"
+
+eslint-plugin-simple-import-sort@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8"
+ integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==
+
+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-scope@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
+ integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
+ integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
+
+eslint@^8.1.0:
+ version "8.43.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.43.0.tgz#3e8c6066a57097adfd9d390b8fc93075f257a094"
+ integrity sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.4.0"
+ "@eslint/eslintrc" "^2.0.3"
+ "@eslint/js" "8.43.0"
+ "@humanwhocodes/config-array" "^0.11.10"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
+ ajv "^6.10.0"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.3.2"
+ doctrine "^3.0.0"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^7.2.0"
+ eslint-visitor-keys "^3.4.1"
+ espree "^9.5.2"
+ esquery "^1.4.2"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ globals "^13.19.0"
+ graphemer "^1.4.0"
+ ignore "^5.2.0"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
+ js-yaml "^4.1.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.1"
+ strip-ansi "^6.0.1"
+ strip-json-comments "^3.1.0"
+ text-table "^0.2.0"
+
+espree@^9.0.0, espree@^9.5.2:
+ version "9.5.2"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b"
+ integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==
+ dependencies:
+ acorn "^8.8.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^3.4.1"
+
+esprima@^4.0.1:
+ 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.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
+ 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, estraverse@^4.2.0:
+ 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==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+ethereum-bloom-filters@^1.0.6:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a"
+ integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==
+ dependencies:
+ js-sha3 "^0.8.0"
+
+ethereum-cryptography@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191"
+ integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==
+ dependencies:
+ "@types/pbkdf2" "^3.0.0"
+ "@types/secp256k1" "^4.0.1"
+ blakejs "^1.1.0"
+ browserify-aes "^1.2.0"
+ bs58check "^2.1.2"
+ create-hash "^1.2.0"
+ create-hmac "^1.1.7"
+ hash.js "^1.1.7"
+ keccak "^3.0.0"
+ pbkdf2 "^3.0.17"
+ randombytes "^2.1.0"
+ safe-buffer "^5.1.2"
+ scrypt-js "^3.0.0"
+ secp256k1 "^4.0.1"
+ setimmediate "^1.0.5"
+
+ethereumjs-util@^7.1.0:
+ version "7.1.5"
+ resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181"
+ integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==
+ dependencies:
+ "@types/bn.js" "^5.1.0"
+ bn.js "^5.1.2"
+ create-hash "^1.1.2"
+ ethereum-cryptography "^0.1.3"
+ rlp "^2.2.4"
+
+ethers@^5.6.4, ethers@^5.7.2:
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e"
+ integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==
+ dependencies:
+ "@ethersproject/abi" "5.7.0"
+ "@ethersproject/abstract-provider" "5.7.0"
+ "@ethersproject/abstract-signer" "5.7.0"
+ "@ethersproject/address" "5.7.0"
+ "@ethersproject/base64" "5.7.0"
+ "@ethersproject/basex" "5.7.0"
+ "@ethersproject/bignumber" "5.7.0"
+ "@ethersproject/bytes" "5.7.0"
+ "@ethersproject/constants" "5.7.0"
+ "@ethersproject/contracts" "5.7.0"
+ "@ethersproject/hash" "5.7.0"
+ "@ethersproject/hdnode" "5.7.0"
+ "@ethersproject/json-wallets" "5.7.0"
+ "@ethersproject/keccak256" "5.7.0"
+ "@ethersproject/logger" "5.7.0"
+ "@ethersproject/networks" "5.7.1"
+ "@ethersproject/pbkdf2" "5.7.0"
+ "@ethersproject/properties" "5.7.0"
+ "@ethersproject/providers" "5.7.2"
+ "@ethersproject/random" "5.7.0"
+ "@ethersproject/rlp" "5.7.0"
+ "@ethersproject/sha2" "5.7.0"
+ "@ethersproject/signing-key" "5.7.0"
+ "@ethersproject/solidity" "5.7.0"
+ "@ethersproject/strings" "5.7.0"
+ "@ethersproject/transactions" "5.7.0"
+ "@ethersproject/units" "5.7.0"
+ "@ethersproject/wallet" "5.7.0"
+ "@ethersproject/web" "5.7.1"
+ "@ethersproject/wordlists" "5.7.0"
+
+ethjs-unit@0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699"
+ integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==
+ dependencies:
+ bn.js "4.11.6"
+ number-to-bn "1.7.0"
+
+event-target-shim@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
+ integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
+
+evp_bytestokey@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
+ integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
+ dependencies:
+ md5.js "^1.3.4"
+ safe-buffer "^5.1.1"
+
+express@^4.18.1:
+ version "4.18.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
+ integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.1"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.5.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.2.0"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.7"
+ qs "6.11.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.18.0"
+ serve-static "1.15.0"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+extend@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+extract-files@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a"
+ integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==
+
+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-diff@^1.1.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
+ integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
+
+fast-glob@^3.2.9:
+ version "3.2.12"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
+ integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+ 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, fast-levenshtein@~2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fast-text-encoding@^1.0.0, fast-text-encoding@^1.0.3:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867"
+ integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==
+
+fastq@^1.6.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
+ integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+ 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"
+
+file-type@^18.3.0:
+ version "18.5.0"
+ resolved "https://registry.yarnpkg.com/file-type/-/file-type-18.5.0.tgz#604a001ba0d32577d4c3fa420ee104d656b914d2"
+ integrity sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==
+ dependencies:
+ readable-web-to-node-stream "^3.0.2"
+ strtok3 "^7.0.0"
+ token-types "^5.0.1"
+
+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"
+
+finalhandler@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+ integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+find-replace@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
+ integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
+ dependencies:
+ array-back "^3.0.1"
+
+find-up@5.0.0, 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"
+
+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.7"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
+ integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
+
+follow-redirects@^1.14.9:
+ version "1.15.2"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+ integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+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"
+
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+fs-extra@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+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==
+
+gaxios@^5.0.0, gaxios@^5.0.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-5.1.2.tgz#5c93e0dc94796e8b92e9ca5c22090d2840e8b8c7"
+ integrity sha512-mPyw3qQq6qoHWTe27CrzhSj7XYKVStTGrpP92a91FfogBWOd9BMW8GT5yS5WhEYGw02AgB1fVQVSAO+JKiQP0w==
+ dependencies:
+ extend "^3.0.2"
+ https-proxy-agent "^5.0.0"
+ is-stream "^2.0.0"
+ node-fetch "^2.6.9"
+
+gcp-metadata@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-5.2.0.tgz#b4772e9c5976241f5d3e69c4f446c906d25506ec"
+ integrity sha512-aFhhvvNycky2QyhG+dcfEdHBF0FRbYcf39s6WNHUDysKSrbJ5vuFbjydxBcmewtXeV248GP8dWT3ByPNxsyHCw==
+ dependencies:
+ gaxios "^5.0.0"
+ json-bigint "^1.0.0"
+
+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 sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
+
+get-intrinsic@^1.0.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
+ integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+
+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-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob@7.1.7:
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
+ 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"
+
+glob@7.2.0:
+ 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"
+
+glob@^7.1.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^8.0.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
+ integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^5.0.1"
+ once "^1.3.0"
+
+globals@^13.19.0:
+ version "13.20.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
+ integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
+ dependencies:
+ type-fest "^0.20.2"
+
+globby@^11.1.0:
+ 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"
+
+google-auth-library@^8.0.2:
+ version "8.8.0"
+ resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-8.8.0.tgz#2e17494431cef56b571420d483a4debff6c481cd"
+ integrity sha512-0iJn7IDqObDG5Tu9Tn2WemmJ31ksEa96IyK0J0OZCpTh6CrC6FrattwKX87h3qKVuprCJpdOGKc1Xi8V0kMh8Q==
+ dependencies:
+ arrify "^2.0.0"
+ base64-js "^1.3.0"
+ ecdsa-sig-formatter "^1.0.11"
+ fast-text-encoding "^1.0.0"
+ gaxios "^5.0.0"
+ gcp-metadata "^5.2.0"
+ gtoken "^6.1.0"
+ jws "^4.0.0"
+ lru-cache "^6.0.0"
+
+google-gax@^3.5.8:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-3.6.0.tgz#0f4ae350159737fe0aa289815c0d92838b19f6af"
+ integrity sha512-2fyb61vWxUonHiArRNJQmE4tx5oY1ni8VPo08fzII409vDSCWG7apDX4qNOQ2GXXT82gLBn3d3P1Dydh7pWjyw==
+ dependencies:
+ "@grpc/grpc-js" "~1.8.0"
+ "@grpc/proto-loader" "^0.7.0"
+ "@types/long" "^4.0.0"
+ "@types/rimraf" "^3.0.2"
+ abort-controller "^3.0.0"
+ duplexify "^4.0.0"
+ fast-text-encoding "^1.0.3"
+ google-auth-library "^8.0.2"
+ is-stream-ended "^0.1.4"
+ node-fetch "^2.6.1"
+ object-hash "^3.0.0"
+ proto3-json-serializer "^1.0.0"
+ protobufjs "7.2.3"
+ protobufjs-cli "1.1.1"
+ retry-request "^5.0.0"
+
+google-p12-pem@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-4.0.1.tgz#82841798253c65b7dc2a4e5fe9df141db670172a"
+ integrity sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==
+ dependencies:
+ node-forge "^1.3.1"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+grapheme-splitter@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
+ integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
+
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+graphql-request@^3.6.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.7.0.tgz#c7406e537084f8b9788541e3e6704340ca13055b"
+ integrity sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ==
+ dependencies:
+ cross-fetch "^3.0.6"
+ extract-files "^9.0.0"
+ form-data "^3.0.0"
+
+graphql-request@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f"
+ integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==
+ dependencies:
+ "@graphql-typed-document-node/core" "^3.2.0"
+ cross-fetch "^3.1.5"
+
+graphql@^15.7.1:
+ version "15.8.0"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38"
+ integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==
+
+gtoken@^6.1.0:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-6.1.2.tgz#aeb7bdb019ff4c3ba3ac100bbe7b6e74dce0e8bc"
+ integrity sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==
+ dependencies:
+ gaxios "^5.0.1"
+ google-p12-pem "^4.0.0"
+ jws "^4.0.0"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+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-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+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"
+
+hash-base@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
+ integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
+ dependencies:
+ inherits "^2.0.4"
+ readable-stream "^3.6.0"
+ safe-buffer "^5.2.0"
+
+hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+ integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.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==
+
+hmac-drbg@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+ignore-by-default@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
+ integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
+
+ignore@^5.2.0:
+ version "5.2.4"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
+ integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
+
+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 sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+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-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+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-hex-prefixed@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554"
+ integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==
+
+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-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+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-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-stream-ended@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda"
+ integrity sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==
+
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+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==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+js-sha3@0.8.0, js-sha3@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
+js-yaml@4.1.0, 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"
+
+js2xmlparser@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.2.tgz#2a1fdf01e90585ef2ae872a01bc169c6a8d5e60a"
+ integrity sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==
+ dependencies:
+ xmlcreate "^2.0.4"
+
+jsbi@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-4.3.0.tgz#b54ee074fb6fcbc00619559305c8f7e912b04741"
+ integrity sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==
+
+jsdoc@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-4.0.2.tgz#a1273beba964cf433ddf7a70c23fd02c3c60296e"
+ integrity sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==
+ dependencies:
+ "@babel/parser" "^7.20.15"
+ "@jsdoc/salty" "^0.2.1"
+ "@types/markdown-it" "^12.2.3"
+ bluebird "^3.7.2"
+ catharsis "^0.9.0"
+ escape-string-regexp "^2.0.0"
+ js2xmlparser "^4.0.2"
+ klaw "^3.0.0"
+ markdown-it "^12.3.2"
+ markdown-it-anchor "^8.4.1"
+ marked "^4.0.10"
+ mkdirp "^1.0.4"
+ requizzle "^0.2.3"
+ strip-json-comments "^3.1.0"
+ underscore "~1.13.2"
+
+json-bigint@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1"
+ integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==
+ dependencies:
+ bignumber.js "^9.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-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 sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jwa@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
+ integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jws@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
+ integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
+ dependencies:
+ jwa "^2.0.0"
+ safe-buffer "^5.0.1"
+
+keccak256@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/keccak256/-/keccak256-1.0.6.tgz#dd32fb771558fed51ce4e45a035ae7515573da58"
+ integrity sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==
+ dependencies:
+ bn.js "^5.2.0"
+ buffer "^6.0.3"
+ keccak "^3.0.2"
+
+keccak@^3.0.0, keccak@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276"
+ integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==
+ dependencies:
+ node-addon-api "^2.0.0"
+ node-gyp-build "^4.2.0"
+ readable-stream "^3.6.0"
+
+klaw@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146"
+ integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==
+ dependencies:
+ graceful-fs "^4.1.9"
+
+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"
+
+levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+linkify-it@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"
+ integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==
+ dependencies:
+ uc.micro "^1.0.1"
+
+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.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+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.snakecase@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
+ integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==
+
+lodash@^4.17.15, lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+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"
+
+long@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
+ integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
+
+long@^5.0.0:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
+ integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
+
+loupe@^2.3.1:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53"
+ integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==
+ 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==
+
+markdown-it-anchor@^8.4.1:
+ version "8.6.7"
+ resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634"
+ integrity sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==
+
+markdown-it@^12.3.2:
+ version "12.3.2"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90"
+ integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==
+ dependencies:
+ argparse "^2.0.1"
+ entities "~2.1.0"
+ linkify-it "^3.0.1"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.5"
+
+marked@^4.0.10:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3"
+ integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==
+
+md5.js@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+ integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
+mdurl@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
+ integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
+
+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==
+
+merkletreejs@^0.3.10:
+ version "0.3.10"
+ resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.3.10.tgz#b9abdfc5e3aadaf9eb8b0a35c4b87aea33f5d4b7"
+ integrity sha512-lin42tKfRdkW+6iE5pjtQ9BnH+1Hk3sJ5Fn9hUUSjcXRcJbSISHgPCfYvMNEXiNqZPhz/TyRPEV30qgnujsQ7A==
+ dependencies:
+ bignumber.js "^9.0.1"
+ buffer-reverse "^1.0.1"
+ crypto-js "^3.1.9-1"
+ treeify "^1.1.0"
+ web3-utils "^1.3.4"
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+ integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+ integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
+
+minimatch@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
+ integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^5.0.1:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+ integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimist@^1.2.0:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+mocha@^10.2.0:
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
+ integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==
+ dependencies:
+ ansi-colors "4.1.1"
+ browser-stdout "1.3.1"
+ chokidar "3.5.3"
+ debug "4.3.4"
+ diff "5.0.0"
+ escape-string-regexp "4.0.0"
+ find-up "5.0.0"
+ glob "7.2.0"
+ he "1.2.0"
+ js-yaml "4.1.0"
+ log-symbols "4.1.0"
+ minimatch "5.0.1"
+ ms "2.1.3"
+ nanoid "3.3.3"
+ serialize-javascript "6.0.0"
+ strip-json-comments "3.1.1"
+ supports-color "8.1.1"
+ workerpool "6.2.1"
+ yargs "16.2.0"
+ yargs-parser "20.2.4"
+ yargs-unparser "2.0.0"
+
+moment@^2.29.4:
+ version "2.29.4"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+ integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+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.3.3:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
+ integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
+
+natural-compare-lite@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
+ integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+node-addon-api@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
+ integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
+
+node-fetch@^2.6.1, node-fetch@^2.6.11, node-fetch@^2.6.9:
+ version "2.6.11"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
+ integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-fetch@^2.6.12:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-fetch@^2.6.7:
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba"
+ integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-forge@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
+ integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
+
+node-gyp-build@^4.2.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055"
+ integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==
+
+nodemon@^2.0.22:
+ version "2.0.22"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258"
+ integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==
+ dependencies:
+ chokidar "^3.5.2"
+ debug "^3.2.7"
+ ignore-by-default "^1.0.1"
+ minimatch "^3.1.2"
+ pstree.remy "^1.1.8"
+ semver "^5.7.1"
+ simple-update-notifier "^1.0.7"
+ supports-color "^5.5.0"
+ touch "^3.1.0"
+ undefsafe "^2.0.5"
+
+nopt@~1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
+ integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
+ dependencies:
+ abbrev "1"
+
+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==
+
+number-to-bn@1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0"
+ integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==
+ dependencies:
+ bn.js "4.11.6"
+ strip-hex-prefix "1.0.0"
+
+object-hash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+object-inspect@^1.9.0:
+ version "1.12.3"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
+ integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+optionator@^0.8.1:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+ integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.6"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ word-wrap "~1.2.3"
+
+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@^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@^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"
+
+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"
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+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 sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+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-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
+
+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==
+
+pbkdf2@^3.0.17:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075"
+ integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==
+ dependencies:
+ create-hash "^1.1.2"
+ create-hmac "^1.1.4"
+ ripemd160 "^2.0.1"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+peek-readable@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
+ integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ 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==
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
+
+prettier-linter-helpers@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
+ dependencies:
+ fast-diff "^1.1.2"
+
+prettier@^2.3.1, prettier@^2.4.1:
+ version "2.8.8"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+ integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+
+proto3-json-serializer@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz#1b5703152b6ce811c5cdcc6468032caf53521331"
+ integrity sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==
+ dependencies:
+ protobufjs "^7.0.0"
+
+protobufjs-cli@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz#f531201b1c8c7772066aa822bf9a08318b24a704"
+ integrity sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==
+ dependencies:
+ chalk "^4.0.0"
+ escodegen "^1.13.0"
+ espree "^9.0.0"
+ estraverse "^5.1.0"
+ glob "^8.0.0"
+ jsdoc "^4.0.0"
+ minimist "^1.2.0"
+ semver "^7.1.2"
+ tmp "^0.2.1"
+ uglify-js "^3.7.7"
+
+protobufjs@7.2.3, protobufjs@^7.0.0:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2"
+ integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.2"
+ "@protobufjs/base64" "^1.1.2"
+ "@protobufjs/codegen" "^2.0.4"
+ "@protobufjs/eventemitter" "^1.1.0"
+ "@protobufjs/fetch" "^1.1.0"
+ "@protobufjs/float" "^1.0.2"
+ "@protobufjs/inquire" "^1.1.0"
+ "@protobufjs/path" "^1.1.2"
+ "@protobufjs/pool" "^1.1.0"
+ "@protobufjs/utf8" "^1.1.0"
+ "@types/node" ">=13.7.0"
+ long "^5.0.0"
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+pstree.remy@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
+ integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
+
+punycode@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
+ integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
+
+qs@6.11.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+ integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ dependencies:
+ side-channel "^1.0.4"
+
+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"
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+ integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+readable-stream@^3.1.1, readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+readable-web-to-node-stream@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb"
+ integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==
+ dependencies:
+ readable-stream "^3.6.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"
+
+reduce-flatten@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27"
+ integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+requizzle@^0.2.3:
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.4.tgz#319eb658b28c370f0c20f968fa8ceab98c13d27c"
+ integrity sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==
+ dependencies:
+ lodash "^4.17.21"
+
+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==
+
+retry-request@^5.0.0:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-5.0.2.tgz#143d85f90c755af407fcc46b7166a4ba520e44da"
+ integrity sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==
+ dependencies:
+ debug "^4.1.1"
+ extend "^3.0.2"
+
+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.0, 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"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+ integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+
+rlp@^2.2.4:
+ version "2.2.7"
+ resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf"
+ integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==
+ dependencies:
+ bn.js "^5.2.0"
+
+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"
+
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.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==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+scrypt-js@3.0.1, scrypt-js@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312"
+ integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==
+
+secp256k1@^4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303"
+ integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==
+ dependencies:
+ elliptic "^6.5.4"
+ node-addon-api "^2.0.0"
+ node-gyp-build "^4.2.0"
+
+semver@^5.7.1:
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@^7.1.2, semver@^7.3.7:
+ version "7.5.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
+ integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
+ dependencies:
+ lru-cache "^6.0.0"
+
+semver@~7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
+ integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
+
+send@0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+ integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+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"
+
+serve-static@1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+ integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.18.0"
+
+setimmediate@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+ integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+ version "2.4.11"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+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"
+
+simple-update-notifier@^1.0.7:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82"
+ integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==
+ dependencies:
+ semver "~7.0.0"
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+stream-shift@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
+ integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
+
+streamsearch@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
+ integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+
+string-format@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b"
+ integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==
+
+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_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+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-hex-prefix@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f"
+ integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==
+ dependencies:
+ is-hex-prefixed "1.0.0"
+
+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==
+
+strtok3@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5"
+ integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==
+ dependencies:
+ "@tokenizer/token" "^0.3.0"
+ peek-readable "^5.0.0"
+
+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, supports-color@^5.5.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"
+
+table-layout@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04"
+ integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==
+ dependencies:
+ array-back "^4.0.1"
+ deep-extend "~0.6.0"
+ typical "^5.2.0"
+ wordwrapjs "^4.0.0"
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+tiny-invariant@^1.1.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
+ integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
+
+tmp@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
+ integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
+ dependencies:
+ rimraf "^3.0.0"
+
+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"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+token-types@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4"
+ integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==
+ dependencies:
+ "@tokenizer/token" "^0.3.0"
+ ieee754 "^1.2.1"
+
+touch@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
+ integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
+ dependencies:
+ nopt "~1.0.10"
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+treeify@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
+ integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==
+
+ts-command-line-args@^2.2.0:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0"
+ integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==
+ dependencies:
+ chalk "^4.1.0"
+ command-line-args "^5.1.1"
+ command-line-usage "^6.1.0"
+ string-format "^2.0.0"
+
+ts-essentials@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38"
+ integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==
+
+ts-mixer@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/ts-mixer/-/ts-mixer-6.0.3.tgz#69bd50f406ff39daa369885b16c77a6194c7cae6"
+ integrity sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==
+
+ts-node@^10.4.0:
+ version "10.9.1"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
+ integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
+ dependencies:
+ "@cspotcode/source-map-support" "^0.8.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"
+ v8-compile-cache-lib "^3.0.1"
+ yn "3.1.1"
+
+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.5.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3"
+ integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==
+
+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"
+
+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-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
+ dependencies:
+ prelude-ls "~1.1.2"
+
+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-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typechain@^8.0.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.2.0.tgz#bd4fc8f111d4405e36858bae6f744604617b60f3"
+ integrity sha512-tZqhqjxJ9xAS/Lh32jccTjMkpx7sTdUVVHAy5Bf0TIer5QFNYXotiX74oCvoVYjyxUKDK3MXHtMFzMyD3kE+jg==
+ dependencies:
+ "@types/prettier" "^2.1.1"
+ debug "^4.3.1"
+ fs-extra "^7.0.0"
+ glob "7.1.7"
+ js-sha3 "^0.8.0"
+ lodash "^4.17.15"
+ mkdirp "^1.0.4"
+ prettier "^2.3.1"
+ ts-command-line-args "^2.2.0"
+ ts-essentials "^7.0.1"
+
+typescript@^4.4.4:
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+ integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+
+typical@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
+ integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+
+typical@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"
+ integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==
+
+uc.micro@^1.0.1, uc.micro@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
+ integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
+
+uglify-js@^3.7.7:
+ version "3.17.4"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
+ integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
+
+undefsafe@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
+ integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
+
+underscore@~1.13.2:
+ version "1.13.6"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441"
+ integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==
+
+undici@^5.22.0:
+ version "5.22.1"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b"
+ integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==
+ dependencies:
+ busboy "^1.6.0"
+
+universal-user-agent@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
+ integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+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"
+
+utf8@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
+ integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
+
+util-deprecate@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+v8-compile-cache-lib@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
+ integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+web3-utils@^1.3.4:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578"
+ integrity sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==
+ dependencies:
+ bn.js "^5.2.1"
+ ethereum-bloom-filters "^1.0.6"
+ ethereumjs-util "^7.1.0"
+ ethjs-unit "0.1.6"
+ number-to-bn "1.7.0"
+ randombytes "^2.1.0"
+ utf8 "3.0.0"
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+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, 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==
+
+wordwrapjs@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f"
+ integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==
+ dependencies:
+ reduce-flatten "^2.0.0"
+ typical "^5.2.0"
+
+workerpool@6.2.1:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
+ integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
+
+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 sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+ws@7.4.6:
+ version "7.4.6"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
+ integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
+
+ws@^8.13.0:
+ version "8.13.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
+ integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+
+xmlcreate@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.4.tgz#0c5ab0f99cdd02a81065fa9cd8f8ae87624889be"
+ integrity sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==
+
+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==
+
+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-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+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"
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+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==