diff --git a/.crowdin.yml b/.crowdin.yml
new file mode 100644
index 00000000..7ca0abf5
--- /dev/null
+++ b/.crowdin.yml
@@ -0,0 +1,5 @@
+pull_request_title: 'chore(l10n): update translations from Crowdin'
+files:
+ - source: /locales/base.json
+ translation: /locales/%two_letters_code%.json
+ type: i18next_json
diff --git a/.eslintrc.js b/.eslintrc.js
index 6b9328ce..db25d84a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,6 +6,10 @@ module.exports = {
rules: {
// Maybe move it to @valora/eslint-config-typescript?
'jest/valid-title': ['error', { ignoreTypeOfDescribeName: true }],
+ 'jest/expect-expect': [
+ 'error',
+ { assertFunctionNames: ['expect*', 'request.**.expect'] },
+ ],
},
ignorePatterns: ['tsconfig.json'],
}
diff --git a/.gcloudignore b/.gcloudignore
new file mode 100644
index 00000000..5a616cba
--- /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_modules
+#!include:.gitignore
diff --git a/.github/workflows/semantic-pr.yaml b/.github/workflows/semantic-pr.yaml
index 320ecc5d..2e08f44f 100644
--- a/.github/workflows/semantic-pr.yaml
+++ b/.github/workflows/semantic-pr.yaml
@@ -13,6 +13,6 @@ jobs:
name: Semantic PR title
runs-on: ubuntu-latest
steps:
- - uses: amannn/action-semantic-pull-request@v5
+ - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml
index c25e5490..3c6d26ac 100644
--- a/.github/workflows/workflow.yaml
+++ b/.github/workflows/workflow.yaml
@@ -19,16 +19,16 @@ jobs:
name: Check for .sh
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- run: "echo '*** Do not write .sh scripts! ***'; ! find . -type f -name '*.sh' | grep ."
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-node@v3
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
- node-version: '18'
+ node-version-file: 'package.json'
check-latest: true
- run: yarn
- run: yarn typecheck
@@ -37,47 +37,64 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest
+ env:
+ NETWORK_ID_TO_RPC_URL: ${{ secrets.NETWORK_ID_TO_RPC_URL }}
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-node@v3
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
- node-version: '18'
+ node-version-file: 'package.json'
check-latest: true
- run: yarn
- run: yarn test:ci
- # - name: Upload Coverage Report
- # uses: actions/upload-artifact@v3
- # with:
- # path: coverage/lcov-report
- # - name: 'Upload coverage to Codecov'
- # uses: codecov/codecov-action@v3
- publish:
- name: Publish to NPM
+ - name: Upload Coverage Report
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ path: coverage/lcov-report
+ - name: 'Upload coverage to Codecov'
+ uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0
+ deploy-staging:
+ name: Deploy staging
+ if: github.ref == 'refs/heads/main'
+ needs:
+ - lint
+ - test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8
+ with:
+ project_id: celo-mobile-alfajores
+ credentials_json: ${{ secrets.ALFAJORES_SERVICE_ACCOUNT_KEY }}
+ - uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4
+ with:
+ install_components: 'beta'
+ - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
+ with:
+ node-version-file: 'package.json'
+ check-latest: true
+ - run: yarn
+ - run: yarn deploy:staging:http hooks-api
+ deploy-production:
+ name: Deploy production
if: github.ref == 'refs/heads/main'
needs:
- - check-for-sh
- lint
- test
+ - deploy-staging
runs-on: ubuntu-latest
steps:
- # actions/checkout MUST come before auth
- - uses: actions/checkout@v3
- - id: auth
- uses: google-github-actions/auth@v1
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8
with:
+ project_id: celo-mobile-mainnet
credentials_json: ${{ secrets.MAINNET_SERVICE_ACCOUNT_KEY }}
- - id: google-secrets
- uses: google-github-actions/get-secretmanager-secrets@v1
+ - uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4
with:
- secrets: |-
- NPM_TOKEN:celo-mobile-mainnet/NPM_TOKEN
- - uses: actions/setup-node@v3
+ install_components: 'beta'
+ - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
- node-version: '18'
+ node-version-file: 'package.json'
check-latest: true
- run: yarn
- - run: yarn build
- - run: yarn release
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- NPM_TOKEN: ${{ steps.google-secrets.outputs.NPM_TOKEN }}
+ - run: yarn deploy:production:http hooks-api
diff --git a/.prettierignore b/.prettierignore
index 48b5d1e5..5ea86cf5 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -6,3 +6,8 @@ dist
# Ignore generated files
src/apps/ubeswap/data/farms.json
+
+# Ignore Crowdin generated files (often they are written with no final newline)
+locales/*.json
+# Except for the base lang which is maintained by hand
+!locales/base.json
diff --git a/README.md b/README.md
index 1df86256..1b0de400 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,15 @@
-# Valora Hooks
+# Divvi Hooks
-Valora Hooks allows developers to extend Valora's functionality by writing short programs called "hooks". These hooks are called in response to certain in-app or blockchain events and are used to provide Valora with additional information and features.
+[](https://github.com/divvi-xyz/hooks/blob/main/LICENSE)
+[](https://github.com/divvi-xyz/hooks/actions/workflows/workflow.yaml?query=branch%3Amain)
+[](https://codecov.io/gh/divvi-xyz/hooks)
+[](https://github.com/divvi-xyz/hooks#contributing)
-Check out the [Valora Hooks documentation](https://docs.staging.valora.xyz/hooks/overview) for more information.
+Divvi Hooks allows developers to extend an app's functionality (_e.g._, the Valora wallet) by writing short programs called "hooks". These hooks are called in response to certain in-app or blockchain events and are used to provide the application with additional information and features.
-Currently, this repository contains position pricing hooks.
+Check out the [Hooks documentation](https://docs.divvi.xyz/hooks/) for more information.
-> :warning: It is an experimental feature and is not fully supported yet.
+Currently, this repository contains position pricing and shortcut hooks.
## Developing Hooks
@@ -19,12 +22,16 @@ To develop hooks, you will need to have Node.js installed on your computer.
### Position Pricing
-See the [documentation](docs/position-pricing-hooks.md) for developing position pricing hooks.
+See the [documentation](docs/types/position.md) for developing position pricing hooks.
+
+### Shortcuts
+
+See the [documentation](docs/types/shortcut.md) for developing shortcut hooks.
## Contributing
-Do you have ideas for more types of hooks that would be useful for Valora users?
-Please reach out to us on [Discord](https://discord.com/invite/J5XMtMkwC4).
+Do you have ideas for more types of hooks that would be useful for users?
+Please reach out to us on [Discord](https://discord.com/invite/EaxZDhMuDn).
diff --git a/docs/assets/live-preview.mp4 b/docs/assets/live-preview.mp4
new file mode 100644
index 00000000..81c72e68
Binary files /dev/null and b/docs/assets/live-preview.mp4 differ
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..a08c143b
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,64 @@
+---
+sidebar_position: 1
+---
+
+# Extend Divvi apps using Hooks
+
+> If you want to start coding, check out the [Live
+> Preview](live-preview) and the [example application](https://github.com/divvi-xyz/hooks/blob/master/src/apps/example)
+> with hook implementations.
+
+Divvi Hooks is a system that allows developers to extend apps (_e.g._, the Valora wallet and other Divvi apps) by
+writing short programs called "hooks". Divvi apps will call hooks in
+response to certain in-app or blockchain events and use the results
+from hooks to extend the apps' functionality.
+
+Divvi Hooks is currently an experimental feature. We are
+developing the Divvi Hooks system incrementally based on feedback
+from developers. Eventually we hope developers will be able to publish
+hooks that users can enable or disable at will.
+
+## Example: position pricing
+
+Users often hold asset-like positions with dapps that are specific to
+the dapp implementation. For example, DeFi dapps
+implement yield farms with smart contracts specific to the dapp and
+these contracts track each users' state in the yield farm, like
+liquidity and unclaimed rewards. A developer can implement a Divvi
+hook to detect these types of positions and price them. If a user is
+yield farming they will see their yield farm positions directly in
+the app.
+
+## Developing a hook
+
+A developer can write a short TypeScript program that handles a
+specific hook type. A user's Divvi wallet passes information to the
+hook, the hook executes in an isolated environment and returns a
+result, and the app uses the results to extend its default behavior.
+
+Currently all hooks need to be approved by a Valora engineer before
+being available to users in the app. Please contact us if
+you're interested in developing a hook and haven't chatted with us
+yet.
+
+## Hook types
+
+Divvi supports or is working on support for the types of hooks we
+list below:
+
+- Position pricing: show a custom contract position in a Divvi app
+- Name resolution: map an arbitrary identifier or name to a wallet address
+- Shortcut (coming soon): complete simple dapp (or inter-dapp) actions
+ within a Divvi app
+
+We plan on adding support for more hook types. If you have a request
+please reach out on Discord.
+
+## Contact
+
+`#hooks-dev` on Divvi's discord.
+
+## Related work
+
+- https://docs.metamask.io/snaps/
+- https://zapper.xyz/
diff --git a/docs/live-preview.md b/docs/live-preview.md
new file mode 100644
index 00000000..c410b555
--- /dev/null
+++ b/docs/live-preview.md
@@ -0,0 +1,27 @@
+# Live Preview
+
+Hooks in development can be easily tested in a Divvi app using the live preview feature.
+
+
+
+## Steps
+
+1. Run `yarn start` to start the development server.
+2. Open the app (_e.g._, the Valora wallet or another Divvi app) on your phone and go to the QR scanner screen.
+3. Scan the QR code displayed in the terminal.
+
+## Additional Information
+
+While in preview mode, changes to your hooks will reload the development server automatically.
+You may need to pull down to refresh the screen in the app to see the changes.
+
+The app shows a banner at the top of the screen when in preview mode. The color of the banner changes based on the fetch status for hooks.
+
+- grey -> idle/loading
+- green -> success
+- red -> error
+
+> [!IMPORTANT]
+> Check the terminal for errors in the development server if you see a red banner, and make sure your phone and computer are on the same network.
diff --git a/docs/platform.md b/docs/platform.md
new file mode 100644
index 00000000..b8d2471d
--- /dev/null
+++ b/docs/platform.md
@@ -0,0 +1,46 @@
+---
+sidebar_position: 2
+---
+
+# Divvi Hooks Platform
+
+## Developing a hook
+
+Developers must implement hooks in TypeScript and integrate them with
+one of the existing per-hook type GitHub repositories.
+
+We hope to make hooks easy to develop but also want to easily iterate
+on the Divvi Hooks Platform for developing and deploying hooks. For
+now we require all deployed hook code to be located in Divvi GitHub
+repositories so we can help improve and maintain them (e.g., when
+we implement breaking changes to the platform), but in the future we
+expect to impose fewer requirements on how hooks are developed.
+
+## Execution environment
+
+Each hook executes in a Node.js 20 environment. Currently we
+implement this as a [Google Cloud
+Function](https://cloud.google.com/functions/docs/concepts/execution-environment), which has several important implications:
+
+- statelessness: your hook cannot store data locally (_e.g._, in memory)
+- timeout: the app will timeout waiting for a hook to execute
+- background: the app destroys the hook environment after it returns so
+ it's not possible to continue computation in the hook after
+ returning a result
+
+Eventually every hook will execute in a sandboxed JavaScript
+environment (like [Secure ECMAScript
+(SES)](https://github.com/endojs/endo/tree/master/packages/ses), which
+MetaMask Snaps use) and we encourage hook developers to have that
+high-level model in mind when developing their hooks and avoid
+depending on Google Cloud Function specific attributes (_e.g._, reading
+the reserved environment variable `K_SERVICE`)
+
+## Deploying a hook to a Divvi app
+
+To deploy your hook you must:
+
+1. submit a PR to the appropriate GitHub repository and work with a
+ Valora engineer to merge your PR; and
+2. confirm with a Valora engineer that they added your hook to the
+ list of enabled hooks.
diff --git a/docs/types/_category_.yml b/docs/types/_category_.yml
new file mode 100644
index 00000000..ac7fc157
--- /dev/null
+++ b/docs/types/_category_.yml
@@ -0,0 +1 @@
+label: 'Hook Types'
diff --git a/docs/types/name-resolution.md b/docs/types/name-resolution.md
new file mode 100644
index 00000000..00860d3a
--- /dev/null
+++ b/docs/types/name-resolution.md
@@ -0,0 +1,10 @@
+# Name Resolution Hooks
+
+A user's Divvi wallet invokes name resolution hooks when the user
+types a recipient for sending funds to. Each name resolution hook
+returns a list of addresses matching the recipient. Divvi apps enable
+name resolution hooks for
+[SocialConnect](https://github.com/celo-org/SocialConnect),
+[Nomspace](https://nom.space/) (a.k.a., ".nom"), and [Masa Finance's
+Prosperity Passport](https://app.prosperity.global/) (a.k.a.,
+".celo") by default.
diff --git a/docs/position-pricing-hooks.md b/docs/types/position.md
similarity index 61%
rename from docs/position-pricing-hooks.md
rename to docs/types/position.md
index 4a62b95d..a0c9311e 100644
--- a/docs/position-pricing-hooks.md
+++ b/docs/types/position.md
@@ -1,15 +1,21 @@
+---
+sidebar_position: 1
+---
+
# Position Pricing Hooks
-A user's Valora wallet invokes position hooks when determining the types, quantity, and value of assets a user owns. If a position hook detects a user owns one or more positions, it provides information about the positions for Valora to show to the user.
+> The [example position hook](https://github.com/divvi-xyz/hooks/blob/master/src/apps/example/positions.ts) is an easy way to get started.
+
+A user's Divvi wallet invokes position hooks when determining the types, quantity, and value of assets a user owns. If a position hook detects a user owns one or more positions, it provides information about the positions for the app to show to the user.
## Principle
-A position pricing hook's main job is to return user owned positions and to break them down into underlying base tokens. The pricing of base tokens is done separately and not needed by hooks authors.
+A position pricing hook's main job is to return user owned positions and to break them down into underlying base tokens. The pricing of base tokens is done separately and is not needed by hooks authors.
Terms:
- **Base Tokens**: base assets which have a token to represent them (ERC20, ERC721, etc). Examples: CELO, cUSD, cEUR, UBE, MOO, etc.
-- **App Tokens**: tokens which represent more complex positions within a dapp, like liquidity pool (LP) tokens, or staked position.
+- **App Tokens**: tokens which represent more complex positions within a dapp, like liquidity pool (LP) tokens, or staked positions.
- **Contract Positions**: things that are not represented by a token (example: locked CELO, farming positions, claimable tokens).
For example, a position hook detects that a user owns a position in a liquidity pool. It then provides information about the pool's assets and the user's share of the pool's assets.
@@ -17,47 +23,47 @@ For example, a position hook detects that a user owns a position in a liquidity
- The liquidity pool is an app token.
- The pool's assets are base tokens.
-From the information provided by the hook, Valora can show the user the value of their position in the pool.
+From the information provided by the hook, the Divvi app can show the user the value of their position in the pool.
## Developing a Position Pricing Hook
### Structure
-Hooks are organized by application. For instance Ubeswap hooks are located in [`https://github.com/valora-inc/hooks/tree/main/src/apps/ubeswap`](https://github.com/valora-inc/hooks/tree/main/src/apps/ubeswap).
+Hooks are organized by application. For instance Ubeswap hooks are located in [`https://github.com/divvi-xyz/hooks/tree/main/src/apps/ubeswap`](https://github.com/divvi-xyz/hooks/tree/main/src/apps/ubeswap).
-Position pricing hooks must implement the [`PositionsHook`](https://github.com/valora-inc/hooks/blob/main/src/types/positions.ts) TypeScript interface.
+Position pricing hooks must implement the [`PositionsHook`](https://github.com/divvi-xyz/hooks/blob/main/src/types/positions.ts) TypeScript interface.
### Creating a Position Pricing Hook
-To create a position pricing hook for your application named `MyApp`, you will need to create a new folder with the name `my-app` in `src/apps` and add a `plugin.ts` file. The file should export an object with the following properties:
+To create a position pricing hook for your application named `MyApp`, you will need to create a new folder with the name `my-app` in `src/apps` and add a `positions.ts` file. The file should export an object with the following properties:
```ts
-import { AppPlugin } from '../../plugin'
+import { PositionsHook } from '../../types/positions'
-const plugin: AppPlugin = {
+const hook: PositionsHook = {
getInfo() {
return { name: 'MyDapp' }
},
- async getPositionDefinitions(network, address) {
+ async getPositionDefinitions({ network, address, t }) {
// TODO: implement
},
}
-export default plugin
+export default hook
```
### Implementing `getPositionDefinitions`
-The `getPositionDefinitions` function is called by Valora to get the positions owned by a user.
+The `getPositionDefinitions` function is called by Divvi apps to get the positions owned by a user.
It receives the following arguments:
- `network`: the network for which the positions should be returned.
- `address`: the address of the user for which the positions should be returned.
-It should return an array of [`PositionDefinition`](https://github.com/valora-inc/hooks/blob/main/src/plugin.ts) objects.
+It should return an array of [`PositionDefinition`](https://github.com/divvi-xyz/hooks/blob/main/src/types/positions.ts) objects.
-The `PositionDefinition` is either a `AppTokenPositionDefinition` or a `ContractPositionDefinition`, representing an app token or a contract position respectively.
+The `PositionDefinition` is either an `AppTokenPositionDefinition` or a `ContractPositionDefinition`, representing an app token or a contract position respectively.
#### App Token Position Definition
@@ -69,14 +75,14 @@ TODO
Here's a simplified example of a `getPositionDefinitions` implementation for representing locked CELO owned by a user.
-Please take a look at the [full implementation](https://github.com/valora-inc/hooks/blob/main/src/apps/locked-celo/plugin.ts) for more details.
+Please take a look at the [full implementation](https://github.com/divvi-xyz/hooks/blob/main/src/apps/locked-celo/positions.ts) for more details.
```ts
-const plugin: AppPlugin = {
+const hook: PositionsHook = {
getInfo() {
return { name: 'MyDapp' }
},
- async getPositionDefinitions(network, address) {
+ async getPositionDefinitions({ network, address, t }) {
// [...] more code here not shown for brevity
const positions: PositionDefinition[] = [
{
@@ -111,11 +117,13 @@ Here you can see that it contains the following properties:
This is how it fulfills the job of a position pricing hook, by declaratively defining the position with its underlying base tokens.
-This is all that is needed for Valora to show the user the value of their locked CELO.
+This is all that is needed for Divvi apps to show the user the value of their locked CELO.
### Testing a Position Pricing Hook
-To test your position pricing hook, you can call it with the `getPositions` script.
+The [hooks live preview](../live-preview.md) mode in a Divvi app is the easiest way to test your position hook while developing it.
+
+Alternatively, you can use the `getPositions` script via the command line.
```sh
yarn getPositions --network --address --apps [,]
@@ -126,3 +134,9 @@ Example for locked-celo:
```sh
yarn getPositions --network celo --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d --apps locked-celo
```
+
+You can get additional logs about how positions are resolved by the runtime by setting the `LOG_LEVEL` environment variable to `debug`.
+
+```sh
+LOG_LEVEL=debug yarn getPositions --network celo --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d --apps locked-celo
+```
diff --git a/docs/types/shortcut.md b/docs/types/shortcut.md
new file mode 100644
index 00000000..059a0ce3
--- /dev/null
+++ b/docs/types/shortcut.md
@@ -0,0 +1,166 @@
+---
+sidebar_position: 2
+---
+
+# Shortcut Hooks
+
+A user's Divvi wallet invokes shortcut hooks when determining asset or dapp related calls-to-action for the user. For example, when a user opens a Divvi app's homescreen. A shortcut hook returns a human readable summary of available actions (_e.g._, "Claim your 1 cUSD earnings") and if the user chooses to act on them, a set of blockchain or in-app transactions will be executed by the app with the user's consent.
+
+> **Note**
+> The UI/UX for shortcut hooks in Divvi apps is currently focused on "earn" and "claim rewards" use cases and requires a [position pricing hook](position.md) to be implemented as well. We plan to expand them to other use cases in the future (shortcuts with custom inputs, not linked to positions, or across dapps).
+
+## Developing a Shortcut Hook
+
+### Structure
+
+Hooks are organized by application. For instance GoodDollar hooks are located in [`https://github.com/divvi-xyz/hooks/tree/main/src/apps/gooddollar`](https://github.com/divvi-xyz/hooks/tree/main/src/apps/gooddollar).
+
+Shortcut hooks must implement the [`ShortcutsHook`](https://github.com/divvi-xyz/hooks/blob/main/src/types/shortcuts.ts) TypeScript interface.
+
+### Creating a Shortcut Hook
+
+To create a shortcut hook for your application named `MyApp`, you will need to create a new folder with the name `my-app` in `src/apps` and add a `shortcuts.ts` file. The file should export an object with the following properties:
+
+```ts
+import { ShortcutsHook } from '../../types/shortcuts'
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions() {
+ // TODO: implement
+ },
+}
+
+export default hook
+```
+
+### Implementing `getShortcutDefinitions`
+
+The `getShortcutDefinitions` function is called by a Divvi app to get the list of shortcuts.
+
+It should return an array of [`ShortcutDefinition`](https://github.com/divvi-xyz/hooks/blob/main/src/types/shortcuts.ts) objects.
+
+#### GoodDollar Example
+
+Here's a simplified example of a `getShortcutDefinitions` implementation for claiming GoodDollar rewards.
+
+Please take a look at the [full implementation](https://github.com/divvi-xyz/hooks/blob/main/src/apps/gooddollar/shortcuts.ts) for more details.
+
+```ts
+const hook: ShortcutsHook = {
+ getShortcutDefinitions() {
+ return [
+ {
+ id: 'claim-reward',
+ name: 'Claim',
+ description: 'Claim daily UBI rewards',
+ networks: ['celo'],
+ category: 'claim',
+ async onTrigger(network, address, positionAddress) {
+ // This isn't strictly needed, but will help while we're developing shortcuts
+ const { request } = await client.simulateContract({
+ address: positionAddress as Address, // This is the ubi contract address
+ abi: ubiSchemeAbi,
+ functionName: 'claim',
+ account: address as Address,
+ })
+
+ const data = encodeFunctionData({
+ abi: request.abi,
+ args: request.args,
+ functionName: request.functionName,
+ })
+
+ return [
+ {
+ network,
+ from: address,
+ to: positionAddress,
+ data,
+ },
+ ]
+ },
+ },
+ ]
+ },
+}
+```
+
+Here you can see that it contains the following properties:
+
+- `id`: the unique identifier for the shortcut
+- `name`: the title of the button used to trigger the shortcut
+- `description`: the description of the shortcut
+- `networks`: the networks the shortcut is available on
+- `category`: the category of the shortcut
+- `onTrigger`: the function that is called when the shortcut is triggered
+
+Once the shortcut is defined, the Divvi app needs to know when to show it to the user, by linking it to an existing [position](position.md).
+
+This is done by adding the `availableShortcutIds` property to the position definition and setting the `category` to `claimable` for the appropriate token(s).
+
+This way the Divvi app will be able to determine that the position has claimable token(s) and what shortcut to call to claim them.
+
+```ts
+const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ // Setting the `category` to `claimable` to indicate that the token can be claimed
+ tokens: [{ address: G$_ADDRESS, network, category: 'claimable' }],
+ // Setting the `availableShortcutIds` to the shortcut id defined above
+ availableShortcutIds: ['claim-reward'],
+ // [...] more properties omitted for brevity
+}
+```
+
+Once this all done, the Divvi app will show the GoodDollar shortcut in the rewards screen, with the available reward amount, and the button to claim it.
+
+### Testing a Shortcut Hook
+
+The [hooks live preview](../live-preview.md) mode in a Divvi app is the easiest way to test your shortcut hook while developing it.
+
+Alternatively, you can use the following scripts via the command line.
+
+#### List shortcuts
+
+To see your shortcut hook, you can use the `getShortcuts` script.
+
+```sh
+yarn getShortcuts --apps [,]
+```
+
+Example for GoodDollar:
+
+```sh
+yarn getShortcuts --apps gooddollar
+```
+
+#### List positions with linked shortcuts
+
+To see positions linked to your shortcut hook, you can use with the `getPositions` script.
+
+```sh
+yarn getPositions --network --address --apps [,]
+```
+
+Example for GoodDollar:
+
+```sh
+yarn getPositions --network celo --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d --apps gooddollar
+```
+
+#### Trigger shortcuts
+
+To test triggering your shortcut hook, you can use the `triggerShortcut` script.
+
+```sh
+yarn triggerShortcut --network --address --app --shortcut --positionAddress
+```
+
+This will return the transactions that would be executed by the Divvi app, after approval by the user.
+
+You can also optionally pass the `--mnemonic` and `--derivationPath` (defaults to the Celo derivation path: `m/44'/52752'/0'/0/0`) options to actually sign and send the returned transaction(s).
+
+Example for GoodDollar:
+
+```sh
+yarn triggerShortcut --network celo --address 0x11489ae0761343c3b03c630a63b00fa025bc4eea --app gooddollar --shortcut claim-reward --positionAddress 0x43d72Ff17701B2DA814620735C39C620Ce0ea4A1
+```
diff --git a/jest.config.js b/jest.config.js
index 8e5ff7e0..f4074b68 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -5,7 +5,7 @@ module.exports = {
coveragePathIgnorePatterns: ['/node_modules/'],
coverageThreshold: {
global: {
- lines: 90,
+ lines: 87,
},
},
}
diff --git a/jest.e2e.config.js b/jest.e2e.config.js
index 29246859..095a09d6 100644
--- a/jest.e2e.config.js
+++ b/jest.e2e.config.js
@@ -1,14 +1,17 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
+require('ts-node/register') // allows us to use typescript for setup script
+require('./scripts/loadProductionEnvVars.ts')
module.exports = {
displayName: 'e2e',
testMatch: ['**/__tests__/**/e2e/**/*.[tj]s?(x)', '**/?(*.)+(e2e).[tj]s?(x)'],
testPathIgnorePatterns: ['dist'],
moduleFileExtensions: ['ts', 'js', 'json'],
- // Allow absolute imports from the tsconfig baseUrl
moduleDirectories: ['node_modules', ''],
+ // Allow absolute imports from the tsconfig baseUrl
transform: {
'^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
},
- setupFiles: ['/jest.e2e.setup.js'],
+ setupFiles: ['/scripts/loadProductionEnvVars.ts'],
+ setupFilesAfterEnv: ['/jest.e2e.setup.js'],
}
diff --git a/jest.unit.config.js b/jest.unit.config.js
index 868b9ea6..13776514 100644
--- a/jest.unit.config.js
+++ b/jest.unit.config.js
@@ -13,5 +13,5 @@ module.exports = {
transform: {
'^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
},
- setupFiles: ['/jest.unit.setup.js'],
+ setupFilesAfterEnv: ['/jest.unit.setup.js'],
}
diff --git a/jest.unit.setup.js b/jest.unit.setup.js
index 4aa0ac6f..f16584b1 100644
--- a/jest.unit.setup.js
+++ b/jest.unit.setup.js
@@ -1 +1,18 @@
// Add jest global setup
+
+const { server } = require('./test/server')
+
+beforeAll(() =>
+ server.listen({
+ // Disable all network requests unless explicitly mocked in MSW
+ // This makes sure we don't accidentally make network requests (except for localhost)
+ onUnhandledRequest: ({ method, url }) => {
+ if (url.hostname !== '127.0.0.1') {
+ // If this throws for a unit test, you need to mock the request
+ throw new Error(`Unhandled ${method} request to ${url}`)
+ }
+ },
+ }),
+)
+afterEach(() => server.resetHandlers())
+afterAll(() => server.close())
diff --git a/locales/base.json b/locales/base.json
new file mode 100644
index 00000000..227107ac
--- /dev/null
+++ b/locales/base.json
@@ -0,0 +1,46 @@
+{
+ "yieldRates": {
+ "earningsApy": "Earnings APY",
+ "earningsApr": "Earnings APR"
+ },
+ "earningItems": { "rewards": "Rewards", "earnings": "Earnings" },
+ "beefyRisks": {
+ "Categry-Beefy": "Beefy",
+ "Categry-Asset": "Asset",
+ "Categry-Platform": "Platform",
+ "Complexity-Low-Titl": "Low-complexity strategy",
+ "Complexity-Mid-Titl": "Medium-complexity strategy",
+ "Complexity-Hi-Titl": "High-complexity strategy",
+ "Testd-Battle-Titl": "Strategy is battle tested",
+ "Testd-New-Titl": "Strategy is new",
+ "Testd-Experimtl-Titl": "Strategy is experimental",
+ "IL-None-Titl": "Very low or zero expected IL",
+ "IL-Low-Titl": "Low expected IL",
+ "IL-High-Titl": "High expected IL",
+ "IL-AlgoStable-Titl": "Algorithmic stable, polarized IL risk",
+ "OverCollatAlgoStable-Titl": "Overcollateralized algorithmic stablecoin",
+ "PartialCollatAlgoStable-Titl": "Partially-collateralized algorithmic stablecoin",
+ "Liquidt-High-Titl": "High asset liquidity",
+ "Liquidt-Low-Titl": "Low asset liquidity",
+ "MktCap-Large-Titl": "High market-capitalization, lower volatility asset",
+ "MktCap-Mid-Titl": "Medium market-capitalization, average volatility asset",
+ "MktCap-Small-Titl": "Small market-capitalization, high volatility asset",
+ "MktCap-Micro-Titl": "Micro market-capitalization, extreme volatility asset",
+ "Concentrated-Titl": "Asset supply concentrated",
+ "Platfrm-Establshd-Titl": "Platform with known track record",
+ "Platfrm-New-Titl": "Platform with little or no track record",
+ "Platfrm-AuditNo-Titl": "No established audit",
+ "Platfrm-Audit-Titl": "Platform audited by trusted reviewer",
+ "Platfrm-Verified-Titl": "Project contracts are verified",
+ "Platfrm-VerifiedNo-Titl": "Project contracts non-public (unverified)",
+ "Platfrm-Timelock-Titl": "Dangerous functions timelocked",
+ "Platfrm-TimelockShort-Titl": "Dangerous functions timelocked with short delay",
+ "Platfrm-TimelockNo-Titl": "Dangerous function not timelocked"
+ },
+ "walletconnect": {
+ "stakedWct": {
+ "title": "Staking",
+ "description": "{{amount}} WCT locked until {{date}}"
+ }
+ }
+}
diff --git a/locales/de.json b/locales/de.json
new file mode 100644
index 00000000..cdbae4bc
--- /dev/null
+++ b/locales/de.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Verdienst-APY",
+ "earningsApr": "Verdienst-APR"
+ },
+ "earningItems": {
+ "rewards": "Rewards",
+ "earnings": "Verdienst"
+ }
+}
\ No newline at end of file
diff --git a/locales/en.json b/locales/en.json
new file mode 100644
index 00000000..574f3037
--- /dev/null
+++ b/locales/en.json
@@ -0,0 +1,11 @@
+{
+ "yieldRates": {
+ "earningsApy": "Earnings APY",
+ "earningsApr": "Earnings APR",
+ "netApyWithAverage": "APY ({{numDays}} day average)"
+ },
+ "earningItems": {
+ "rewards": "Rewards",
+ "earnings": "Earnings"
+ }
+}
\ No newline at end of file
diff --git a/locales/es.json b/locales/es.json
new file mode 100644
index 00000000..2dd4d593
--- /dev/null
+++ b/locales/es.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Rendimiento anual",
+ "earningsApr": "Rendimiento anual"
+ },
+ "earningItems": {
+ "rewards": "Recompensas",
+ "earnings": "Ganancias"
+ }
+}
\ No newline at end of file
diff --git a/locales/fr.json b/locales/fr.json
new file mode 100644
index 00000000..e6f7de6b
--- /dev/null
+++ b/locales/fr.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Gains APY",
+ "earningsApr": "Gains APR"
+ },
+ "earningItems": {
+ "rewards": "Récompenses",
+ "earnings": "Gains"
+ }
+}
\ No newline at end of file
diff --git a/locales/it.json b/locales/it.json
new file mode 100644
index 00000000..c42447ad
--- /dev/null
+++ b/locales/it.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Guadagni APY",
+ "earningsApr": "Guadagni APR"
+ },
+ "earningItems": {
+ "rewards": "Ricompense",
+ "earnings": "Guadagni"
+ }
+}
\ No newline at end of file
diff --git a/locales/pl.json b/locales/pl.json
new file mode 100644
index 00000000..4ff263e7
--- /dev/null
+++ b/locales/pl.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Zarobki APY",
+ "earningsApr": "Zarobki APR"
+ },
+ "earningItems": {
+ "rewards": "Nagrody",
+ "earnings": "Zarobki"
+ }
+}
\ No newline at end of file
diff --git a/locales/pt.json b/locales/pt.json
new file mode 100644
index 00000000..187e37c4
--- /dev/null
+++ b/locales/pt.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Ganhos de APY",
+ "earningsApr": "Ganhos de APR"
+ },
+ "earningItems": {
+ "rewards": "Prêmios",
+ "earnings": "Ganhos"
+ }
+}
\ No newline at end of file
diff --git a/locales/ru.json b/locales/ru.json
new file mode 100644
index 00000000..74d42226
--- /dev/null
+++ b/locales/ru.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Годовой доход в процентах",
+ "earningsApr": "Годовая процентная ставка дохода"
+ },
+ "earningItems": {
+ "rewards": "Вознаграждения",
+ "earnings": "Доход"
+ }
+}
\ No newline at end of file
diff --git a/locales/th.json b/locales/th.json
new file mode 100644
index 00000000..9b230a9b
--- /dev/null
+++ b/locales/th.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "รายได้ APY",
+ "earningsApr": "รายได้ APR"
+ },
+ "earningItems": {
+ "rewards": "ผลตอบแทน",
+ "earnings": "รายได้"
+ }
+}
\ No newline at end of file
diff --git a/locales/tr.json b/locales/tr.json
new file mode 100644
index 00000000..4faf16d5
--- /dev/null
+++ b/locales/tr.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Kazanç APY'si",
+ "earningsApr": "Kazanç APR'si"
+ },
+ "earningItems": {
+ "rewards": "Ödüller",
+ "earnings": "Kazançlar"
+ }
+}
\ No newline at end of file
diff --git a/locales/uk.json b/locales/uk.json
new file mode 100644
index 00000000..6192dabc
--- /dev/null
+++ b/locales/uk.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Прибуток APY",
+ "earningsApr": "Прибуток APR"
+ },
+ "earningItems": {
+ "rewards": "Винагорода",
+ "earnings": "Прибуток"
+ }
+}
\ No newline at end of file
diff --git a/locales/vi.json b/locales/vi.json
new file mode 100644
index 00000000..abeb6f68
--- /dev/null
+++ b/locales/vi.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "Tỷ suất lợi nhuận hằng năm (APY) từ thu nhập",
+ "earningsApr": "Phần trăm lãi suất hằng năm (APR) từ thu nhập"
+ },
+ "earningItems": {
+ "rewards": "Tiền thưởng",
+ "earnings": "Thu nhập"
+ }
+}
\ No newline at end of file
diff --git a/locales/zh.json b/locales/zh.json
new file mode 100644
index 00000000..799120e8
--- /dev/null
+++ b/locales/zh.json
@@ -0,0 +1,10 @@
+{
+ "yieldRates": {
+ "earningsApy": "年化收益率",
+ "earningsApr": "年化百分比率"
+ },
+ "earningItems": {
+ "rewards": "奖励",
+ "earnings": "收益"
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 8166c9f6..08dea3a4 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,14 @@
{
- "name": "@valora/plugins",
+ "name": "@divvi/hooks",
"version": "0.0.0-semantic-release",
- "main": "dist/index.js",
- "typings": "dist/index.d.ts",
- "repository": "https://github.com/valora-inc/plugins.git",
+ "main": "dist/api/index.js",
+ "typings": "dist/api/index.d.ts",
+ "repository": "https://github.com/divvi-xyz/hooks.git",
"author": "Valora Inc",
"license": "Apache-2.0",
+ "private": true,
"engines": {
- "node": "^18"
+ "node": "^20"
},
"files": [
"dist"
@@ -15,6 +16,7 @@
"scripts": {
"build": "tsc",
"build:scripts": "tsc --project scripts/tsconfig.json",
+ "gcp-build": "yarn build",
"typecheck": "yarn build && yarn build:scripts",
"lint": "eslint --ext=.tsx,.ts,.json src/ scripts/",
"lint:fix": "yarn lint --fix",
@@ -28,33 +30,62 @@
"getPositions": "ts-node ./scripts/getPositions.ts",
"getShortcuts": "ts-node ./scripts/getShortcuts.ts",
"triggerShortcut": "ts-node ./scripts/triggerShortcut.ts",
- "release": "semantic-release"
+ "start": "ts-node ./scripts/start.ts",
+ "deploy:staging": "gcloud beta functions deploy --gen2 --concurrency=80 --cpu 1 --memory=256MB --project=celo-mobile-alfajores --region=us-central1 --runtime=nodejs20 --env-vars-file=src/api/staging.yaml --update-labels \"valora-repo=hooks,commit-sha=$(git rev-parse HEAD)\"",
+ "deploy:staging:http": "yarn deploy:staging --trigger-http --allow-unauthenticated",
+ "deploy:production": "gcloud beta functions deploy --gen2 --concurrency=80 --cpu 1 --memory=512MB --project=celo-mobile-mainnet --region=us-central1 --runtime=nodejs20 --env-vars-file=src/api/production.yaml --update-labels \"valora-repo=hooks,commit-sha=$(git rev-parse HEAD)\" --set-secrets=NETWORK_ID_TO_RPC_URL=hooks-rpc-urls:latest,ALLBRIDGE_API_KEY=allbridge-api-key:latest",
+ "deploy:production:http": "yarn deploy:production --trigger-http --allow-unauthenticated"
},
"dependencies": {
- "bignumber.js": "^9.1.1",
+ "@0xsquid/squid-types": "^0.1.137",
+ "@bgd-labs/aave-address-book": "4.17.2",
+ "@google-cloud/functions-framework": "^3.5.1",
+ "@valora/http-handler": "^0.0.1",
+ "@valora/logging": "^1.3.18",
+ "bignumber.js": "^9.2.0",
+ "cors": "^2.8.5",
+ "dotenv": "^16.4.7",
+ "express": "^5.1.0",
"got": "^11.8.6",
- "viem": "^1.2.12"
+ "i18next": "^24.2.3",
+ "i18next-fs-backend": "^2.6.0",
+ "i18next-http-middleware": "^3.7.1",
+ "lru-cache": "^11.1.0",
+ "semver": "^7.7.1",
+ "viem": "^2.23.2",
+ "zod": "^3.24.2"
},
"devDependencies": {
- "@types/jest": "^29.5.2",
- "@types/shelljs": "^0.8.12",
- "@typescript-eslint/eslint-plugin": "^5.61.0",
- "@valora/eslint-config-typescript": "^1.0.1",
+ "@types/cors": "^2.8.17",
+ "@types/jest": "^29.5.14",
+ "@types/js-yaml": "^4.0.9",
+ "@types/qrcode-terminal": "^0.12.2",
+ "@types/shelljs": "^0.8.15",
+ "@types/supertest": "^6.0.3",
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
+ "@valora/eslint-config-typescript": "^1.1.9",
"@valora/prettier-config": "^0.0.1",
+ "chalk": "^4.1.2",
"conventional-changelog-conventionalcommits": "^6.1.0",
- "eslint": "^8.44.0",
- "eslint-plugin-import": "^2.27.5",
- "eslint-plugin-jest": "^27.2.2",
- "eslint-plugin-react": "^7.32.2",
- "eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-native": "^4.0.0",
- "jest": "^29.6.1",
- "prettier": "^2.8.8",
- "semantic-release": "^21.0.7",
+ "eslint": "^8.57.1",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jest": "^27.9.0",
+ "eslint-plugin-react": "^7.37.4",
+ "eslint-plugin-react-hooks": "^4.6.2",
+ "eslint-plugin-react-native": "^4.1.0",
+ "internal-ip": "^6.2.0",
+ "jest": "^29.7.0",
+ "js-yaml": "^4.1.0",
+ "msw": "^1.3.5",
+ "prettier": "^3.0.3",
+ "qrcode-terminal": "^0.12.0",
"shelljs": "^0.8.5",
- "ts-jest": "^29.1.1",
- "ts-node": "^10.9.1",
- "typescript": "^5.1.6",
+ "supertest": "^7.1.0",
+ "terminate": "^2.8.0",
+ "ts-jest": "^29.3.0",
+ "ts-node": "^10.9.2",
+ "tsc-watch": "^6.2.1",
+ "typescript": "^5.8.2",
"yargs": "^17.7.2"
},
"prettier": "@valora/prettier-config",
diff --git a/scripts/getPositions.e2e.ts b/scripts/getPositions.e2e.ts
index 5d46d1b4..87a698c0 100644
--- a/scripts/getPositions.e2e.ts
+++ b/scripts/getPositions.e2e.ts
@@ -1,10 +1,13 @@
import * as $ from 'shelljs'
describe('getPositions', () => {
- it('should get the address positions successfully', () => {
- const result = $.exec(
- 'yarn getPositions --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
- expect(result.code).toBe(0)
- })
+ it.each(['celo-mainnet', 'ethereum-mainnet'])(
+ 'should get the address positions successfully for networkId %s',
+ (networkId) => {
+ const result = $.exec(
+ `yarn getPositions --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d -n ${networkId}`,
+ )
+ expect(result.code).toBe(0)
+ },
+ )
})
diff --git a/scripts/getPositions.ts b/scripts/getPositions.ts
index 8063651d..c8b550b7 100644
--- a/scripts/getPositions.ts
+++ b/scripts/getPositions.ts
@@ -1,24 +1,27 @@
-// Helper script to call the plugins and get the positions
+// Helper script to call the hooks and get the positions
/* eslint-disable no-console */
import yargs from 'yargs'
import BigNumber from 'bignumber.js'
import { Token } from '../src/types/positions'
-import { getPositions } from '../src/runtime/getPositions'
+import { getPositions, getBaseTokensInfo } from '../src/runtime/getPositions'
+import { NetworkId } from '../src/types/networkId'
+import { t } from '../test/i18next'
+import { getConfig } from '../src/config'
const argv = yargs(process.argv.slice(2))
.usage('Usage: $0 --address ')
.options({
- network: {
+ networkId: {
alias: 'n',
- describe: 'Network to get positions for',
- choices: ['celo', 'celoAlfajores'],
- default: 'celo',
+ describe: 'Network ID to get positions for',
+ choices: Object.values(NetworkId),
+ default: NetworkId['celo-mainnet'],
},
address: {
alias: 'a',
- describe: 'Address to get positions for',
+ describe:
+ 'Optional address to get positions for. When not specified it lists all available positions.',
type: 'string',
- demandOption: true,
},
apps: {
alias: 'p',
@@ -48,7 +51,16 @@ function breakdownToken(token: Token): string {
}
void (async () => {
- const positions = await getPositions(argv.network, argv.address, argv.apps)
+ const baseTokensInfo = await getBaseTokensInfo(
+ getConfig().GET_TOKENS_INFO_URL,
+ )
+ const positions = await getPositions({
+ networkId: argv.networkId,
+ address: argv.address,
+ appIds: argv.apps,
+ t,
+ baseTokensInfo,
+ })
console.log('positions', JSON.stringify(positions, null, ' '))
console.table(
@@ -59,7 +71,7 @@ void (async () => {
appId: position.appId,
type: position.type,
address: position.address,
- network: position.network,
+ network: position.networkId,
title: `${position.displayProps.title} (${position.displayProps.description})`,
priceUsd: new BigNumber(position.priceUsd).toFixed(2),
balance: balance.toFixed(2),
@@ -72,7 +84,7 @@ void (async () => {
appId: position.appId,
type: position.type,
address: position.address,
- network: position.network,
+ network: position.networkId,
title: `${position.displayProps.title} (${position.displayProps.description})`,
balanceUsd: new BigNumber(position.balanceUsd).toFixed(2),
breakdown: position.tokens.map(breakdownToken).join(', '),
diff --git a/scripts/getShortcuts.e2e.ts b/scripts/getShortcuts.e2e.ts
index 7778652c..287376d1 100644
--- a/scripts/getShortcuts.e2e.ts
+++ b/scripts/getShortcuts.e2e.ts
@@ -1,7 +1,14 @@
import * as $ from 'shelljs'
describe('getShortcuts', () => {
- it('should get shortcuts successfully', () => {
+ it('should get shortcuts successfully with --address', () => {
+ const result = $.exec(
+ 'yarn getShortcuts --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ )
+ expect(result.code).toBe(0)
+ })
+
+ it('should get shortcuts successfully without --address', () => {
const result = $.exec('yarn getShortcuts')
expect(result.code).toBe(0)
})
diff --git a/scripts/getShortcuts.ts b/scripts/getShortcuts.ts
index 624a0bfc..27e39d86 100644
--- a/scripts/getShortcuts.ts
+++ b/scripts/getShortcuts.ts
@@ -2,10 +2,22 @@
/* eslint-disable no-console */
import yargs from 'yargs'
import { getShortcuts } from '../src/runtime/getShortcuts'
+import { NetworkId } from '../src/types/networkId'
const argv = yargs(process.argv.slice(2))
.usage('Usage: $0 --apps app1[,app2]')
.options({
+ networkId: {
+ alias: 'n',
+ describe: 'Network ID to get positions for',
+ choices: Object.values(NetworkId),
+ default: NetworkId['celo-mainnet'],
+ },
+ address: {
+ alias: 'a',
+ describe: 'Address to get positions for',
+ type: 'string',
+ },
apps: {
alias: 'p',
describe: 'App IDs to get shortcuts for, defaults to all',
@@ -20,7 +32,7 @@ const argv = yargs(process.argv.slice(2))
.parseSync()
void (async () => {
- const shortcuts = await getShortcuts(argv.apps)
+ const shortcuts = await getShortcuts(argv.networkId, argv.address, argv.apps)
console.log('shortcuts', JSON.stringify(shortcuts, null, ' '))
console.table(shortcuts)
diff --git a/scripts/loadProductionEnvVars.ts b/scripts/loadProductionEnvVars.ts
new file mode 100644
index 00000000..12296b66
--- /dev/null
+++ b/scripts/loadProductionEnvVars.ts
@@ -0,0 +1,11 @@
+import yaml from 'js-yaml'
+import fs from 'fs'
+
+// load static env vars from production.yaml into the environment
+// useful for e2e tests that would otherwise fail if required env vars were missing
+const envFileContent = yaml.load(
+ fs.readFileSync('src/api/production.yaml', 'utf8'),
+) as Record
+for (const [key, value] of Object.entries(envFileContent)) {
+ process.env[key] = value
+}
diff --git a/scripts/start.e2e.ts b/scripts/start.e2e.ts
new file mode 100644
index 00000000..ca813085
--- /dev/null
+++ b/scripts/start.e2e.ts
@@ -0,0 +1,25 @@
+import * as $ from 'shelljs'
+import terminate from 'terminate/promise'
+
+describe('start', () => {
+ it('should start the preview server successfully', async () => {
+ const child = $.exec(`yarn start`, { async: true })
+
+ // Wait for the server to be ready
+ await new Promise((resolve, _reject) => {
+ child.stdout!.on('data', function (data: Buffer) {
+ const output = data.toString()
+ if (output.includes('Server logs will appear below')) {
+ resolve()
+ }
+ })
+ })
+
+ if (!child.pid) {
+ throw new Error('Child process has no PID')
+ }
+
+ // Terminate the child process along with all its children
+ await expect(terminate(child.pid)).resolves.toBeUndefined()
+ })
+})
diff --git a/scripts/start.ts b/scripts/start.ts
new file mode 100644
index 00000000..0db203df
--- /dev/null
+++ b/scripts/start.ts
@@ -0,0 +1,99 @@
+/* eslint-disable no-console */
+import yargs from 'yargs'
+import qrcodeTerminal from 'qrcode-terminal'
+import internalIp from 'internal-ip'
+import chalk from 'chalk'
+import * as $ from 'shelljs'
+
+$.config.fatal = true
+
+const DEFAULT_PORT = 18000
+
+const argv = yargs(process.argv.slice(2))
+ .usage('Usage: $0 [--watch]')
+ .options({
+ watch: {
+ alias: 'w',
+ describe: 'Watch for changes, defaults to true',
+ type: 'boolean',
+ default: true,
+ },
+ port: {
+ alias: 'p',
+ describe: `Port to listen on, defaults to ${DEFAULT_PORT}`,
+ type: 'number',
+ default: DEFAULT_PORT,
+ },
+ })
+ .parseSync()
+
+console.log('Starting hooks preview API server...')
+
+function printServerInfo() {
+ const ipAddress = internalIp.v4.sync()
+ if (!ipAddress) {
+ throw new Error('Could not determine IP address')
+ }
+
+ const serverUrl = `http://${ipAddress}:${argv.port}`
+
+ const deeplink = `celo://wallet/hooks/enablePreview?hooksApiUrl=${encodeURIComponent(
+ serverUrl,
+ )}`
+ // This directly prints the QR code to the terminal
+ qrcodeTerminal.generate(deeplink, { small: true })
+ console.log(chalk.gray(deeplink) + '\n')
+
+ console.log(`› Server URL: ${chalk.underline(serverUrl)}`)
+ console.log(
+ `› Scan the QR code above with Valora to enable live preview of hooks\n`,
+ )
+ console.log(
+ `Server logs will appear below. ${chalk.gray('Press Ctrl+C to exit.')}`,
+ )
+}
+
+function startServer(command: string) {
+ const child = $.exec(command, { async: true, silent: true })
+ let serverReadyOnce = false
+ // This string is printed by the functions-framework when the server is ready
+ // but we don't want print it since it says localhost
+ const serverReadyString = `URL: http://localhost:${argv.port}/`
+
+ // Wait for the server to be ready before printing the server info
+ child.stdout!.on('data', function (data: Buffer) {
+ const output = data.toString()
+ // Remove serverReadyString from the output if it exists
+ const readyIndex = output.indexOf(serverReadyString)
+ if (readyIndex > -1) {
+ data = Buffer.from(
+ output.slice(0, readyIndex) +
+ output.slice(readyIndex + serverReadyString.length),
+ )
+ }
+
+ process.stdout.write(data)
+
+ if (readyIndex > -1) {
+ if (!serverReadyOnce) {
+ printServerInfo()
+ } else {
+ console.log('› Server restarted and ready')
+ }
+ serverReadyOnce = true
+ }
+ })
+
+ child.stderr!.on('data', function (data: Buffer) {
+ process.stderr.write(data)
+ })
+}
+
+const serverCommand = `functions-framework --target=hooks-api --signature-type=http --port=${argv.port}`
+
+if (argv.watch) {
+ startServer(`tsc-watch --noClear --onSuccess "${serverCommand}"`)
+} else {
+ $.exec('yarn build')
+ startServer(serverCommand)
+}
diff --git a/scripts/triggerShortcut.e2e.ts b/scripts/triggerShortcut.e2e.ts
index cf2e2c67..1ddf89a2 100644
--- a/scripts/triggerShortcut.e2e.ts
+++ b/scripts/triggerShortcut.e2e.ts
@@ -3,7 +3,7 @@ import * as $ from 'shelljs'
describe('triggerShortcut', () => {
it('should trigger a shortcut successfully', () => {
const result = $.exec(
- 'yarn triggerShortcut --network celo --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d --app ubeswap --shortcut claim-reward --positionAddress 0xda7f463c27ec862cfbf2369f3f74c364d050d93f',
+ `yarn triggerShortcut --network celo --address 0x2b8441ef13333ffa955c9ea5ab5b3692da95260d --app ubeswap --shortcut claim-reward --triggerInput '{"positionAddress": "0xda7f463c27ec862cfbf2369f3f74c364d050d93f"}'`,
)
expect(result.code).toBe(0)
})
diff --git a/scripts/triggerShortcut.ts b/scripts/triggerShortcut.ts
index 3db68c34..e9da8fc6 100644
--- a/scripts/triggerShortcut.ts
+++ b/scripts/triggerShortcut.ts
@@ -1,24 +1,63 @@
// Helper script to trigger a shortcut
/* eslint-disable no-console */
import yargs from 'yargs'
-import { Address, createWalletClient, http, createPublicClient } from 'viem'
+import {
+ Address,
+ createWalletClient,
+ http,
+ createPublicClient,
+ Chain,
+} from 'viem'
import { mnemonicToAccount } from 'viem/accounts'
-import { celo } from 'viem/chains'
+import {
+ arbitrum,
+ arbitrumSepolia,
+ base,
+ baseSepolia,
+ celo,
+ celoAlfajores,
+ mainnet,
+ optimism,
+ optimismSepolia,
+ polygon,
+ polygonAmoy,
+ sepolia,
+} from 'viem/chains'
import { getShortcuts } from '../src/runtime/getShortcuts'
+import { NetworkId } from '../src/types/networkId'
+import { z } from 'zod'
const CELO_DERIVATION_PATH = "m/44'/52752'/0'/0/0"
+const NETWORK_ID_TO_CHAIN: Record = {
+ [NetworkId['celo-mainnet']]: celo,
+ [NetworkId['celo-alfajores']]: celoAlfajores,
+ [NetworkId['ethereum-mainnet']]: mainnet,
+ [NetworkId['ethereum-sepolia']]: sepolia,
+ [NetworkId['arbitrum-one']]: arbitrum,
+ [NetworkId['arbitrum-sepolia']]: arbitrumSepolia,
+ [NetworkId['base-mainnet']]: base,
+ [NetworkId['base-sepolia']]: baseSepolia,
+ [NetworkId['op-mainnet']]: optimism,
+ [NetworkId['op-sepolia']]: optimismSepolia,
+ [NetworkId['polygon-pos-mainnet']]: polygon,
+ [NetworkId['polygon-pos-amoy']]: polygonAmoy,
+}
+
const argv = yargs(process.argv.slice(2))
+ .parserConfiguration({
+ 'parse-numbers': false, // prevents 0x{string} from being parsed as a number
+ })
.usage(
- 'Usage: $0 --network --address --app --shortcut --positionAddress ',
+ 'Usage: $0 --network --address --app --shortcut --triggerInputShape [--mnemonic ] [--derivationPath ]',
)
.env('')
.options({
- network: {
+ networkId: {
alias: 'n',
- describe: 'Network to get positions for',
- choices: ['celo', 'celoAlfajores'],
- default: 'celo',
+ describe: 'Network ID to get positions for',
+ choices: Object.values(NetworkId),
+ default: NetworkId['celo-mainnet'],
},
address: {
alias: 'a',
@@ -38,10 +77,11 @@ const argv = yargs(process.argv.slice(2))
type: 'string',
demandOption: true,
},
- positionAddress: {
- describe: 'Position address to trigger the shortcut on',
+ triggerInput: {
+ describe:
+ 'JSON for the triggerInput of shortcut. It should respect the triggerInputShape of the shortcut.',
type: 'string',
- demandOption: true,
+ default: '{}',
},
mnemonic: {
describe: 'Mnemonic to use to sign the shortcut transaction(s)',
@@ -56,7 +96,7 @@ const argv = yargs(process.argv.slice(2))
.parseSync()
void (async () => {
- const shortcuts = await getShortcuts([argv.app])
+ const shortcuts = await getShortcuts(argv.networkId, argv.address, [argv.app])
const shortcut = shortcuts.find((s) => s.id === argv.shortcut)
if (!shortcut) {
@@ -67,19 +107,24 @@ void (async () => {
)
}
+ // TODO: consider showing a user friendly prompt to fill in the trigger input
+ // or at least a list of the expected fields
+ // This just throws a Zod error if the input is not valid
+ const triggerInput = z
+ .object(shortcut.triggerInputShape)
+ .parse(JSON.parse(argv.triggerInput))
+
+ const triggerArgs = {
+ networkId: argv.networkId,
+ address: argv.address,
+ ...triggerInput,
+ }
+
console.log(
`Triggering shortcut '${shortcut.id}' for app '${shortcut.appId}'`,
- {
- network: argv.network,
- address: argv.address,
- positionAddress: argv.positionAddress,
- },
- )
- const result = await shortcut.onTrigger(
- argv.network,
- argv.address,
- argv.positionAddress,
+ triggerArgs,
)
+ const result = await shortcut.onTrigger(triggerArgs)
console.log('Transaction(s) to send:', result)
@@ -100,15 +145,15 @@ void (async () => {
const wallet = createWalletClient({
account,
- chain: celo,
+ chain: NETWORK_ID_TO_CHAIN[argv.networkId],
transport: http(),
})
const client = createPublicClient({
- chain: celo,
+ chain: NETWORK_ID_TO_CHAIN[argv.networkId],
transport: http(),
})
- for (const transaction of result) {
+ for (const transaction of result.transactions) {
const txHash = await wallet.sendTransaction({
// from: transaction.from as Address,
to: transaction.to as Address,
diff --git a/src/api/index.test.ts b/src/api/index.test.ts
new file mode 100644
index 00000000..33d31785
--- /dev/null
+++ b/src/api/index.test.ts
@@ -0,0 +1,547 @@
+import request from 'supertest'
+// See https://github.com/GoogleCloudPlatform/functions-framework-nodejs/pull/461#issuecomment-1184147725
+// Using the workaround with NodeNext module resolution causes a cascade of other issues
+// @ts-expect-error
+import { getTestServer } from '@google-cloud/functions-framework/testing'
+import { getPositions } from '../runtime/getPositions'
+import { getShortcuts } from '../runtime/getShortcuts'
+import { Position } from '../types/positions'
+import { SerializedDecimalNumber } from '../types/numbers'
+import { NetworkId } from '../types/networkId'
+import { getConfig } from '../config'
+
+jest.mock('../config')
+jest.mocked(getConfig).mockReturnValue({
+ POSITION_IDS: ['uniswap', 'aave', 'curve'],
+ GET_TOKENS_INFO_URL: 'https://valoraapp.com/mock-endpoint',
+ GOOGLE_CLOUD_PROJECT: 'dev-project',
+ SHORTCUT_IDS: [],
+ NETWORK_ID_TO_RPC_URL: {},
+ EARN_SUPPORTED_NETWORK_IDS: [
+ NetworkId['celo-mainnet'],
+ NetworkId['arbitrum-one'],
+ ],
+ GET_SWAP_QUOTE_URL: 'https://valoraapp.com/mock-swap-endpoint',
+})
+import './index' // NOTE: there are side effects of importing this module-- loading config params from the environment in particular. so mocking configs MUST be done before importing.
+import { ZodAddressLowerCased } from '../types/address'
+jest.mock('../runtime/getPositions')
+jest.mock('../runtime/getShortcuts')
+
+const TEST_POSITIONS_CELO: Position[] = [
+ {
+ type: 'app-token',
+ appId: 'ubeswap',
+ appName: 'Ubeswap',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ positionId: 'celo-mainnet:0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ symbol: 'ULP',
+ decimals: 18,
+ label: 'Pool: G$ / cUSD',
+ displayProps: {
+ title: 'G$ / cUSD',
+ description: 'Pool',
+ imageUrl: '',
+ manageUrl: '',
+ },
+ tokenId: 'celo-mainnet:0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ tokens: [
+ {
+ type: 'base-token',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x62b8b11039fcfe5ab0c56e502b1c372a3d2a9c7a',
+ symbol: 'G$',
+ decimals: 18,
+ priceUsd: '0.00015738574843135427' as SerializedDecimalNumber,
+ balance: '12445.060074286696111325' as SerializedDecimalNumber,
+ tokenId: 'celo-mainnet:0x62b8b11039fcfe5ab0c56e502b1c372a3d2a9c7a',
+ },
+ {
+ type: 'base-token',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x765de816845861e75a25fca122bb6898b8b1282a',
+ symbol: 'cUSD',
+ decimals: 18,
+ priceUsd: '1' as SerializedDecimalNumber,
+ balance: '2.061316226302041758' as SerializedDecimalNumber,
+ tokenId: 'celo-mainnet:0x765de816845861e75a25fca122bb6898b8b1282a',
+ },
+ ],
+ pricePerShare: [
+ '77.77845724145984437582' as SerializedDecimalNumber,
+ '0.0128827016512212377' as SerializedDecimalNumber,
+ ],
+ priceUsd: '0.0130404016454077124' as SerializedDecimalNumber,
+ balance: '160.006517430032680046' as SerializedDecimalNumber,
+ supply: '170.324243277473535226' as SerializedDecimalNumber,
+ availableShortcutIds: [],
+ shortcutTriggerArgs: {},
+ },
+]
+
+const TEST_POSITIONS_ETHEREUM: Position[] = [
+ {
+ type: 'app-token',
+ appId: 'uniswap',
+ appName: 'Uniswap',
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ positionId: 'ethereum-mainnet:0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ symbol: 'ULP',
+ decimals: 18,
+ label: 'Pool: UNI / USDC',
+ displayProps: {
+ title: 'UNI / USDC',
+ description: 'Pool',
+ imageUrl: '',
+ manageUrl: '',
+ },
+ tokenId: 'ethereum-mainnet:0x31f9dee850b4284b81b52b25a3194f2fc8ff18cf',
+ tokens: [
+ {
+ type: 'base-token',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+ symbol: 'UNI',
+ decimals: 18,
+ priceUsd: '11.17' as SerializedDecimalNumber,
+ balance: '12445.060074286696111325' as SerializedDecimalNumber,
+ tokenId: 'ethereum-mainnet:0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+ },
+ {
+ type: 'base-token',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ symbol: 'USDC',
+ decimals: 18,
+ priceUsd: '1' as SerializedDecimalNumber,
+ balance: '2.061316226302041758' as SerializedDecimalNumber,
+ tokenId: 'ethereum-mainnet:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ },
+ ],
+ pricePerShare: [
+ '1.77845724145984437582' as SerializedDecimalNumber,
+ '2.0128827016512212377' as SerializedDecimalNumber,
+ ],
+ priceUsd: '0.25' as SerializedDecimalNumber,
+ balance: '100.01' as SerializedDecimalNumber,
+ supply: '170.10' as SerializedDecimalNumber,
+ availableShortcutIds: [],
+ shortcutTriggerArgs: {},
+ },
+]
+
+const TEST_POSITIONS_ARBITRUM: Position[] = [
+ {
+ type: 'app-token',
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ tokenId: 'arbitrum-one:0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ positionId: 'arbitrum-one:0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ appId: 'aave',
+ appName: 'Aave',
+ symbol: 'aArbUSDCn',
+ decimals: 6,
+ label: 'USDC',
+ displayProps: {
+ title: 'USDC',
+ description: 'Supplied (APY: 7.42%)',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/aave.png',
+ manageUrl: undefined,
+ },
+ dataProps: {
+ yieldRates: [
+ {
+ percentage: 7.419092396389471,
+ label: 'Earnings APY',
+ tokenId: 'arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
+ },
+ ],
+ earningItems: [],
+ depositTokenId: 'arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
+ withdrawTokenId:
+ 'arbitrum-one:0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ },
+ tokens: [
+ {
+ address: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
+ decimals: 6,
+ symbol: 'USDC',
+ networkId: NetworkId['arbitrum-one'],
+ tokenId: 'arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
+ priceUsd: '1' as SerializedDecimalNumber,
+ type: 'base-token',
+ balance: '0' as SerializedDecimalNumber,
+ },
+ ],
+ pricePerShare: ['1' as SerializedDecimalNumber],
+ priceUsd: '1' as SerializedDecimalNumber,
+ balance: '0' as SerializedDecimalNumber,
+ supply: '239859963.713137' as SerializedDecimalNumber,
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: {},
+ },
+]
+
+const TEST_POSITIONS_CELO_EARN: Position[] = [
+ {
+ type: 'app-token',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af',
+ tokenId: 'celo-mainnet:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af',
+ positionId: 'celo-mainnet:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af',
+ appId: 'allbridge',
+ appName: 'Allbridge',
+ symbol: 'LP-USDT',
+ decimals: 6,
+ label: 'USDT',
+ displayProps: {
+ title: 'USDT',
+ description: 'Supplied (APR: 2.61%)',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/allbridgecore.png',
+ manageUrl: undefined,
+ },
+ dataProps: {
+ yieldRates: [
+ {
+ percentage: 2.61,
+ label: 'Earnings APR',
+ tokenId: 'celo-mainnet:0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
+ },
+ ],
+ earningItems: [],
+ depositTokenId: 'celo-mainnet:0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
+ withdrawTokenId:
+ 'celo-mainnet:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af',
+ },
+ tokens: [
+ {
+ address: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
+ decimals: 6,
+ symbol: 'USDT',
+ networkId: NetworkId['celo-mainnet'],
+ tokenId: 'celo-mainnet:0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
+ priceUsd: '1' as SerializedDecimalNumber,
+ type: 'base-token',
+ balance: '0' as SerializedDecimalNumber,
+ },
+ ],
+ pricePerShare: ['1' as SerializedDecimalNumber],
+ priceUsd: '1' as SerializedDecimalNumber,
+ balance: '0' as SerializedDecimalNumber,
+ supply: '239859963.713137' as SerializedDecimalNumber,
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: {},
+ },
+]
+
+jest.mocked(getPositions).mockImplementation(async ({ networkId }) => {
+ if (networkId === NetworkId['celo-mainnet']) {
+ return TEST_POSITIONS_CELO
+ } else if (networkId === NetworkId['ethereum-mainnet']) {
+ return TEST_POSITIONS_ETHEREUM
+ } else if (networkId === NetworkId['arbitrum-one']) {
+ return TEST_POSITIONS_ARBITRUM
+ } else {
+ return []
+ }
+})
+
+const TEST_SHORTCUTS: Awaited> = [
+ {
+ appId: 'ubeswap',
+ id: 'claim-reward',
+ name: 'Claim',
+ description: 'Claim rewards for staked liquidity',
+ networkIds: [NetworkId['celo-mainnet']],
+ category: 'claim',
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address, positionAddress }) {
+ // Bogus implementation for testing
+ return {
+ transactions: [
+ {
+ networkId,
+ from: address,
+ to: positionAddress,
+ data: '0xTEST',
+ },
+ ],
+ }
+ },
+ },
+]
+
+jest.mocked(getShortcuts).mockResolvedValue(TEST_SHORTCUTS)
+
+const WALLET_ADDRESS = '0x0000000000000000000000000000000000007e57'
+
+beforeEach(() => {
+ jest.clearAllMocks()
+})
+
+describe('GET /getPositions', () => {
+ it('returns balances for celo', async () => {
+ const server = getTestServer('hooks-api')
+ await request(server)
+ .get('/getPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ .expect({ message: 'OK', data: TEST_POSITIONS_CELO })
+ })
+
+ it('returns balances for celo and ethereum', async () => {
+ const server = getTestServer('hooks-api')
+ await request(server)
+ .get('/getPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet'], NetworkId['ethereum-mainnet']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ .expect({
+ message: 'OK',
+ data: TEST_POSITIONS_CELO.concat(TEST_POSITIONS_ETHEREUM),
+ })
+ })
+
+ it('returns all positions when address is not provided', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getPositions')
+ .query({
+ network: 'celo', // note: this old schema should still be supported.
+ })
+ .expect(200)
+ expect(response.body).toStrictEqual({
+ message: 'OK',
+ data: TEST_POSITIONS_CELO,
+ })
+ })
+
+ for (const [userAgent, shouldIncludeAave] of [
+ ['Valora/1.90.0', true],
+ ['Valora/1.100.0', true],
+ ['Valora/1.89.9', false],
+ ['Valora/1.89.10', false],
+ ['SomeOtherApp/1.90.0', true],
+ [undefined, true],
+ ] as const) {
+ it(`returns positions for User-Agent ${userAgent ?? 'undefined'} ${
+ shouldIncludeAave ? 'including' : 'excluding'
+ } Aave`, async () => {
+ const server = getTestServer('hooks-api')
+ await request(server)
+ .get('/getPositions')
+ .set('user-agent', userAgent ?? '')
+ .query({
+ networkIds: [NetworkId['arbitrum-one']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+
+ expect(getPositions).toHaveBeenCalledWith(
+ expect.objectContaining({
+ appIds: shouldIncludeAave
+ ? expect.arrayContaining(['aave']) // eslint-disable-line jest/no-conditional-expect
+ : expect.not.arrayContaining(['aave']), // eslint-disable-line jest/no-conditional-expect
+ }),
+ )
+ })
+ }
+})
+
+describe('GET /getEarnPositions', () => {
+ it('returns default earn positions for arbitrum when supportedPools and supportedAppIds not passed in', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getEarnPositions')
+ .query({
+ networkIds: [NetworkId['arbitrum-one']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: TEST_POSITIONS_ARBITRUM,
+ })
+ })
+ it('returns expected earn positions for arbitrum when supportedPools and supportedAppIds are passed in', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getEarnPositions')
+ .query({
+ networkIds: [NetworkId['arbitrum-one']],
+ supportedPools: [
+ 'arbitrum-one:0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ ],
+ supportedAppIds: ['allbridge', 'aave'],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: TEST_POSITIONS_ARBITRUM,
+ })
+ })
+ it('returns default earn positions for celo when supportedPools and supportedAppIds not passed in', async () => {
+ jest.mocked(getPositions).mockResolvedValue(TEST_POSITIONS_CELO_EARN)
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getEarnPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: TEST_POSITIONS_CELO_EARN,
+ })
+ })
+ it('returns expected earn positions for celo when supportedPools and supportedAppIds are passed in', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getEarnPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet']],
+ supportedPools: [
+ `${NetworkId['celo-mainnet']}:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af`,
+ ],
+ supportedAppIds: ['allbridge', 'aave'],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: TEST_POSITIONS_CELO_EARN,
+ })
+ })
+ it('does not return pool if ID not in supportedPools', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getEarnPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet']],
+ supportedPools: ['0xbadAddress'],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: [],
+ })
+ })
+})
+
+describe('GET /getShortcuts', () => {
+ it('returns shortcuts', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server).get('/getShortcuts').expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: TEST_SHORTCUTS.map(
+ ({ onTrigger, triggerInputShape, ...shortcut }) => ({
+ ...shortcut,
+ }),
+ ),
+ })
+ })
+})
+
+describe('POST /triggerShortcut', () => {
+ it('calls the shortcut onTrigger and returns transactions', async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .post('/triggerShortcut')
+ .send({
+ networkId: 'celo-mainnet',
+ address: WALLET_ADDRESS,
+ appId: TEST_SHORTCUTS[0].appId,
+ shortcutId: TEST_SHORTCUTS[0].id,
+ positionAddress: TEST_POSITIONS_CELO[0].address,
+ })
+ .expect(200)
+ expect(response.body).toEqual({
+ message: 'OK',
+ data: {
+ transactions: [
+ {
+ networkId: 'celo-mainnet',
+ from: WALLET_ADDRESS.toLowerCase(),
+ to: TEST_POSITIONS_CELO[0].address,
+ data: '0xTEST',
+ },
+ ],
+ },
+ })
+ })
+
+ it("returns 400 when the shortcut doesn't exist", async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .post('/triggerShortcut')
+ .send({
+ networkId: 'celo-mainnet',
+ address: WALLET_ADDRESS,
+ appId: TEST_SHORTCUTS[0].appId,
+ shortcutId: 'flarf',
+ positionAddress: TEST_POSITIONS_CELO[0].address,
+ })
+ .expect(400)
+ expect(response.body).toMatchInlineSnapshot(`
+ {
+ "message": "No shortcut found with id 'flarf' for app 'ubeswap', available shortcuts: claim-reward",
+ }
+ `)
+ })
+
+ it("returns 400 when the shortcut trigger inputs don't match the schema", async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .post('/triggerShortcut')
+ .send({
+ networkId: 'celo-mainnet',
+ address: WALLET_ADDRESS,
+ appId: TEST_SHORTCUTS[0].appId,
+ shortcutId: TEST_SHORTCUTS[0].id,
+ positionAddress: 'barf',
+ })
+ .expect(400)
+ expect(response.body).toStrictEqual({
+ details: {
+ _errors: [],
+ body: {
+ _errors: [],
+ positionAddress: {
+ _errors: ['Invalid Address barf'],
+ },
+ },
+ },
+ message: 'Invalid request',
+ })
+ })
+})
+
+describe('CORS', () => {
+ it("allows all origins to access the function's resources", async () => {
+ const server = getTestServer('hooks-api')
+ const response = await request(server)
+ .get('/getPositions')
+ .query({
+ networkIds: [NetworkId['celo-mainnet']],
+ address: WALLET_ADDRESS,
+ })
+ .expect(200)
+
+ expect(response.header['access-control-allow-origin']).toBe('*')
+ })
+})
diff --git a/src/api/index.ts b/src/api/index.ts
new file mode 100644
index 00000000..a544f870
--- /dev/null
+++ b/src/api/index.ts
@@ -0,0 +1,341 @@
+import { http, HttpFunction } from '@google-cloud/functions-framework'
+import {
+ HttpError,
+ asyncHandler as valoraAsyncHandler,
+} from '@valora/http-handler'
+import { createLoggingMiddleware } from '@valora/logging'
+import cors from 'cors'
+import express from 'express'
+import i18nextMiddleware from 'i18next-http-middleware'
+import semver from 'semver'
+import { z } from 'zod'
+import { getConfig } from '../config'
+import { logger } from '../log'
+import { getBaseTokensInfo, getPositions } from '../runtime/getPositions'
+import { getShortcuts } from '../runtime/getShortcuts'
+import {
+ LegacyNetwork,
+ legacyNetworkToNetworkId,
+ NetworkId,
+} from '../types/networkId'
+import { Transaction } from '../types/shortcuts'
+import { createI18Next } from '../utils/i18next'
+import { parseRequest } from './parseRequest'
+
+const DEFAULT_EARN_SUPPORTED_APP_IDS = ['aave', 'allbridge']
+const DEFAULT_EARN_SUPPORTED_POSITION_IDS = new Set([
+ // Aave USDC
+ `${NetworkId['arbitrum-one']}:0x724dc807b04555b71ed48a6896b6f41593b8c637`,
+ `${NetworkId['arbitrum-sepolia']}:0x460b97bd498e1157530aeb3086301d5225b91216`,
+ // Allbridge USDT
+ `${NetworkId['celo-mainnet']}:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af`,
+ // Somm Real Yield ETH
+ `${NetworkId['op-mainnet']}:0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c`,
+])
+
+// Copied over from https://github.com/valora-inc/valora-rest-api/blob/main/src/middleware/requestMetadata.ts#L65
+function getValoraAppVersion(userAgent: string | undefined) {
+ const appInfo = getAppInfoFromUserAgent(userAgent)
+ return appInfo?.app?.toLowerCase() === 'valora' ? appInfo.version : undefined
+}
+
+// Copied over from https://github.com/valora-inc/valora-rest-api/blob/main/src/middleware/requestMetadata.ts#L76
+function getAppInfoFromUserAgent(userAgent: string | undefined):
+ | {
+ app?: string
+ version?: string
+ }
+ | undefined {
+ const match = userAgent?.match(/^([^\s/]+)(?:\/(\S+))?/)
+ return match ? { app: match[1], version: match[2] } : undefined
+}
+
+function asyncHandler(handler: HttpFunction) {
+ return valoraAsyncHandler(handler, logger)
+}
+
+function getNetworkIds(
+ args: { network: LegacyNetwork } | { networkIds: NetworkId | NetworkId[] },
+): NetworkId[] {
+ if ('network' in args) {
+ return [legacyNetworkToNetworkId[args.network]]
+ } else if (Array.isArray(args.networkIds)) {
+ return args.networkIds
+ } else {
+ return [args.networkIds]
+ }
+}
+
+function serializeShortcuts(
+ shortcuts: Awaited>,
+) {
+ // TODO: consider returning JSON schema for triggerInputShape
+ return shortcuts.map(({ onTrigger, triggerInputShape, ...shortcut }) => ({
+ ...shortcut,
+ }))
+}
+
+function serializeTransactions(transactions: Transaction[]) {
+ return transactions.map((tx) => ({
+ ...tx,
+ ...(tx.value !== undefined ? { value: tx.value.toString() } : {}),
+ ...(tx.gas !== undefined ? { gas: tx.gas.toString() } : {}),
+ ...(tx.estimatedGasUse !== undefined
+ ? { estimatedGasUse: tx.estimatedGasUse.toString() }
+ : {}),
+ }))
+}
+
+function createApp() {
+ const config = getConfig()
+
+ const app = express()
+
+ app.use(
+ cors({
+ origin: '*',
+ }),
+ )
+
+ app.use(
+ createLoggingMiddleware({
+ logger,
+ projectId: config.GOOGLE_CLOUD_PROJECT,
+ }),
+ )
+ const i18next = createI18Next()
+ app.use(i18nextMiddleware.handle(i18next))
+
+ const getHooksRequestSchema = z.object({
+ query: z.intersection(
+ z.object({
+ address: z
+ .string()
+ .regex(/^0x[a-fA-F0-9]{40}$/)
+ .transform((val) => val.toLowerCase())
+ .optional(),
+ }),
+ z.union([
+ z.object({ network: z.nativeEnum(LegacyNetwork) }), // legacy schema: 'celo' or 'celoAlfajores' passed as 'network' field on the request
+ z.object({
+ networkIds: z
+ .array(z.nativeEnum(NetworkId))
+ .nonempty()
+ .or(z.nativeEnum(NetworkId)), // singleton arrays sometimes serialize as single values
+ }), // current schema: any members of NetworkId enum passed as 'networkIds' field on the request
+ ]),
+ ),
+ })
+
+ app.get(
+ '/getPositions',
+ asyncHandler(async (req, res) => {
+ const parsedRequest = await parseRequest(req, getHooksRequestSchema)
+ const userAgent = req.header('user-agent')
+ const valoraAppVersion = getValoraAppVersion(userAgent)
+ const returnAavePositions = valoraAppVersion
+ ? semver.gte(valoraAppVersion, '1.90.0')
+ : true
+ const { address } = parsedRequest.query
+ const networkIds = getNetworkIds(parsedRequest.query)
+ const appIds = config.POSITION_IDS.filter((appId) =>
+ returnAavePositions ? true : appId !== 'aave',
+ )
+ const baseTokensInfo = await getBaseTokensInfo(
+ getConfig().GET_TOKENS_INFO_URL,
+ networkIds,
+ )
+ const positions = (
+ await Promise.all(
+ networkIds.map((networkId) =>
+ getPositions({
+ networkId,
+ address,
+ appIds,
+ t: req.t,
+ baseTokensInfo,
+ }),
+ ),
+ )
+ ).flat()
+ res.send({ message: 'OK', data: positions })
+ }),
+ )
+
+ const getEarnPositionsRequestSchema = z.object({
+ query: z.object({
+ networkIds: z
+ .array(z.nativeEnum(NetworkId))
+ .nonempty()
+ .or(z.nativeEnum(NetworkId)), // singleton arrays sometimes serialize as single values
+ supportedPools: z
+ .array(z.string())
+ .nonempty()
+ .or(z.string()) // singleton arrays sometimes serialize as single values
+ .optional(),
+ supportedAppIds: z
+ .array(z.string())
+ .nonempty()
+ .or(z.string()) // singleton arrays sometimes serialize as single values
+ .optional(),
+ }),
+ })
+
+ // Positions for the Earn feature
+ app.get(
+ '/getEarnPositions',
+ asyncHandler(async (req, res) => {
+ const parsedRequest = await parseRequest(
+ req,
+ getEarnPositionsRequestSchema,
+ )
+ const networkIds = getNetworkIds(parsedRequest.query).filter(
+ (networkId) => config.EARN_SUPPORTED_NETWORK_IDS.includes(networkId),
+ )
+ const supportedPools = parsedRequest.query.supportedPools
+ ? new Set(
+ Array.isArray(parsedRequest.query.supportedPools)
+ ? parsedRequest.query.supportedPools
+ : [parsedRequest.query.supportedPools],
+ )
+ : DEFAULT_EARN_SUPPORTED_POSITION_IDS
+ const supportedAppIds = parsedRequest.query.supportedAppIds
+ ? Array.isArray(parsedRequest.query.supportedAppIds)
+ ? parsedRequest.query.supportedAppIds
+ : [parsedRequest.query.supportedAppIds]
+ : DEFAULT_EARN_SUPPORTED_APP_IDS
+
+ const baseTokensInfo = await getBaseTokensInfo(
+ getConfig().GET_TOKENS_INFO_URL,
+ networkIds,
+ )
+
+ const positions = (
+ await Promise.all(
+ networkIds.map((networkId) =>
+ getPositions({
+ networkId,
+ // Earn positions are not user-specific
+ address: undefined,
+ appIds: supportedAppIds,
+ t: req.t,
+ baseTokensInfo,
+ }),
+ ),
+ )
+ )
+ .flat()
+ .filter(
+ // For now limit to specific positions
+ (position) => supportedPools.has(position.positionId),
+ )
+
+ res.send({ message: 'OK', data: positions })
+ }),
+ )
+
+ // Deprecated route, will be removed in the future
+ app.get(
+ '/getShortcuts',
+ asyncHandler(async (_req, res) => {
+ const shortcuts = await getShortcuts(
+ NetworkId['celo-mainnet'],
+ undefined,
+ config.SHORTCUT_IDS,
+ )
+ res.send({ message: 'OK', data: serializeShortcuts(shortcuts) })
+ }),
+ )
+
+ app.get(
+ '/v2/getShortcuts',
+ asyncHandler(async (req, res) => {
+ const parsedRequest = await parseRequest(req, getHooksRequestSchema)
+ const { address } = parsedRequest.query
+ const networkIds = getNetworkIds(parsedRequest.query)
+ const shortcuts = (
+ await Promise.all(
+ networkIds.map((networkId) =>
+ getShortcuts(networkId, address, config.SHORTCUT_IDS),
+ ),
+ )
+ ).flat()
+ res.send({ message: 'OK', data: serializeShortcuts(shortcuts) })
+ }),
+ )
+
+ const triggerShortcutRequestSchema = z.object({
+ body: z.intersection(
+ z.object({
+ address: z
+ .string({ required_error: 'address is required' })
+ .regex(/^0x[a-fA-F0-9]{40}$/)
+ .transform((val) => val.toLowerCase()),
+ appId: z.string({ required_error: 'appId is required' }),
+ shortcutId: z.string({ required_error: 'shortcutId is required' }),
+ }),
+ z.union([
+ z.object({ network: z.nativeEnum(LegacyNetwork) }), // legacy schema: 'celo' or 'celoAlfajores' passed as 'network' field on the request
+ z.object({ networkId: z.nativeEnum(NetworkId) }), // current schema: any member of NetworkId enum passed as 'networkId' field on the request
+ ]),
+ ),
+ })
+
+ app.post(
+ '/triggerShortcut',
+ asyncHandler(async (req, res) => {
+ const parsedRequest = await parseRequest(
+ req,
+ triggerShortcutRequestSchema,
+ )
+
+ const { address, appId, shortcutId } = parsedRequest.body
+
+ const networkId =
+ 'network' in parsedRequest.body
+ ? legacyNetworkToNetworkId[parsedRequest.body.network]
+ : parsedRequest.body.networkId
+
+ const shortcuts = await getShortcuts(networkId, address, [appId])
+
+ const shortcut = shortcuts.find((s) => s.id === shortcutId)
+ if (!shortcut) {
+ throw new HttpError(
+ 400,
+ `No shortcut found with id '${shortcutId}' for app '${appId}', available shortcuts: ${shortcuts
+ .map((s) => s.id)
+ .join(', ')}`,
+ )
+ }
+
+ // Now check the trigger input
+ const parsedTriggerInput = await parseRequest(
+ req,
+ z.object({
+ body: z.object(shortcut.triggerInputShape),
+ }),
+ )
+
+ const { transactions, ...triggerOuput } = await shortcut.onTrigger({
+ networkId,
+ address,
+ ...parsedTriggerInput.body,
+ })
+
+ res.send({
+ message: 'OK',
+ data: {
+ transactions: serializeTransactions(transactions),
+ ...triggerOuput,
+ },
+ })
+ }),
+ )
+
+ // We'll add more routes here
+
+ return app
+}
+
+// Register the main Cloud Function
+http('hooks-api', createApp())
diff --git a/src/api/parseRequest.ts b/src/api/parseRequest.ts
new file mode 100644
index 00000000..5e081a3f
--- /dev/null
+++ b/src/api/parseRequest.ts
@@ -0,0 +1,19 @@
+import { logger } from '../log'
+import { AnyZodObject, ZodError, z } from 'zod'
+import { HttpError, Request } from '@valora/http-handler'
+
+export async function parseRequest(
+ req: Request,
+ schema: T,
+): Promise> {
+ try {
+ return await schema.parseAsync(req)
+ } catch (err) {
+ logger.warn({ err }, 'Failed to parse request')
+ if (err instanceof ZodError) {
+ throw new HttpError(400, 'Invalid request', err.format())
+ }
+
+ throw err
+ }
+}
diff --git a/src/api/production.yaml b/src/api/production.yaml
new file mode 100644
index 00000000..b44608d7
--- /dev/null
+++ b/src/api/production.yaml
@@ -0,0 +1,8 @@
+# This is interestingly not set for us in the Cloud Function environment
+GOOGLE_CLOUD_PROJECT: celo-mobile-mainnet
+POSITION_IDS: 'curve,beefy,gooddollar,hedgey,locked-celo,mento,moola,stake-dao,ubeswap,uniswap,allbridge,aave,walletconnect,somm'
+SHORTCUT_IDS: 'gooddollar,hedgey,ubeswap,allbridge,aave,somm'
+GET_TOKENS_INFO_URL: 'https://api.mainnet.valora.xyz/getTokensInfoWithPrices'
+EARN_SUPPORTED_NETWORK_IDS: 'arbitrum-one,celo-mainnet,op-mainnet,base-mainnet'
+SIMULATE_TRANSACTIONS_URL: 'https://api.mainnet.valora.xyz/simulateTransactions'
+GET_SWAP_QUOTE_URL: 'https://api.mainnet.valora.xyz/getSwapQuote'
diff --git a/src/api/staging.yaml b/src/api/staging.yaml
new file mode 100644
index 00000000..7217c607
--- /dev/null
+++ b/src/api/staging.yaml
@@ -0,0 +1,8 @@
+# This is interestingly not set for us in the Cloud Function environment
+GOOGLE_CLOUD_PROJECT: celo-mobile-alfajores
+POSITION_IDS: 'curve,gooddollar,hedgey,locked-celo,mento,moola,stake-dao,ubeswap,uniswap,allbridge,aave,walletconnect,somm'
+SHORTCUT_IDS: 'gooddollar,hedgey,ubeswap,allbridge,aave,somm'
+GET_TOKENS_INFO_URL: 'https://api.alfajores.valora.xyz/getTokensInfoWithPrices'
+EARN_SUPPORTED_NETWORK_IDS: 'arbitrum-sepolia'
+SIMULATE_TRANSACTIONS_URL: 'https://api.alfajores.valora.xyz/simulateTransactions'
+GET_SWAP_QUOTE_URL: 'https://api.alfajores.valora.xyz/getSwapQuote'
diff --git a/src/apps/aave/abis/atoken.ts b/src/apps/aave/abis/atoken.ts
new file mode 100644
index 00000000..0a0d9a74
--- /dev/null
+++ b/src/apps/aave/abis/atoken.ts
@@ -0,0 +1,512 @@
+// From https://arbiscan.io/address/0x1be1798b70aee431c2986f7ff48d9d1fa350786a#code
+export const aTokenAbi = [
+ {
+ inputs: [{ internalType: 'contract IPool', name: 'pool', type: 'address' }],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'BalanceTransfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'target',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'balanceIncrease',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'Burn',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'underlyingAsset',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'pool', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'treasury',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'incentivesController',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint8',
+ name: 'aTokenDecimals',
+ type: 'uint8',
+ },
+ {
+ indexed: false,
+ internalType: 'string',
+ name: 'aTokenName',
+ type: 'string',
+ },
+ {
+ indexed: false,
+ internalType: 'string',
+ name: 'aTokenSymbol',
+ type: 'string',
+ },
+ { indexed: false, internalType: 'bytes', name: 'params', type: 'bytes' },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'caller',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'onBehalfOf',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'balanceIncrease',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'Mint',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'ATOKEN_REVISION',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'DOMAIN_SEPARATOR',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'EIP712_REVISION',
+ outputs: [{ internalType: 'bytes', name: '', type: 'bytes' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'PERMIT_TYPEHASH',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'POOL',
+ outputs: [{ internalType: 'contract IPool', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'RESERVE_TREASURY_ADDRESS',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'UNDERLYING_ASSET_ADDRESS',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'receiverOfUnderlying',
+ type: 'address',
+ },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'index', type: 'uint256' },
+ ],
+ name: 'burn',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
+ ],
+ name: 'decreaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getIncentivesController',
+ outputs: [
+ {
+ internalType: 'contract IAaveIncentivesController',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'getPreviousIndex',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'getScaledUserBalanceAndSupply',
+ outputs: [
+ { internalType: 'uint256', name: '', type: 'uint256' },
+ { internalType: 'uint256', name: '', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'handleRepayment',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
+ ],
+ name: 'increaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPool',
+ name: 'initializingPool',
+ type: 'address',
+ },
+ { internalType: 'address', name: 'treasury', type: 'address' },
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ internalType: 'contract IAaveIncentivesController',
+ name: 'incentivesController',
+ type: 'address',
+ },
+ { internalType: 'uint8', name: 'aTokenDecimals', type: 'uint8' },
+ { internalType: 'string', name: 'aTokenName', type: 'string' },
+ { internalType: 'string', name: 'aTokenSymbol', type: 'string' },
+ { internalType: 'bytes', name: 'params', type: 'bytes' },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'caller', type: 'address' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'index', type: 'uint256' },
+ ],
+ name: 'mint',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'index', type: 'uint256' },
+ ],
+ name: 'mintToTreasury',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],
+ name: 'nonces',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ { internalType: 'uint256', name: 'deadline', type: 'uint256' },
+ { internalType: 'uint8', name: 'v', type: 'uint8' },
+ { internalType: 'bytes32', name: 'r', type: 'bytes32' },
+ { internalType: 'bytes32', name: 's', type: 'bytes32' },
+ ],
+ name: 'permit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'token', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'rescueTokens',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'scaledBalanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'scaledTotalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IAaveIncentivesController',
+ name: 'controller',
+ type: 'address',
+ },
+ ],
+ name: 'setIncentivesController',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'recipient', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'sender', type: 'address' },
+ { internalType: 'address', name: 'recipient', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'transferOnLiquidation',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'target', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferUnderlyingTo',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/aave/abis/incentives-controller-v3.ts b/src/apps/aave/abis/incentives-controller-v3.ts
new file mode 100644
index 00000000..17d2db27
--- /dev/null
+++ b/src/apps/aave/abis/incentives-controller-v3.ts
@@ -0,0 +1,915 @@
+// From https://docs.aave.com/developers/periphery-contracts/rewardscontroller
+export const incentivesControllerV3Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'emissionManager',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'assetIndex',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'userIndex',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'rewardsAccrued',
+ type: 'uint256',
+ },
+ ],
+ name: 'Accrued',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'oldEmission',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newEmission',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'oldDistributionEnd',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newDistributionEnd',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'assetIndex',
+ type: 'uint256',
+ },
+ ],
+ name: 'AssetConfigUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'claimer',
+ type: 'address',
+ },
+ ],
+ name: 'ClaimerSet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'oldEmissionManager',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newEmissionManager',
+ type: 'address',
+ },
+ ],
+ name: 'EmissionManagerUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'rewardOracle',
+ type: 'address',
+ },
+ ],
+ name: 'RewardOracleUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'claimer',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'RewardsClaimed',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'transferStrategy',
+ type: 'address',
+ },
+ ],
+ name: 'TransferStrategyInstalled',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'REVISION',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ ],
+ name: 'claimAllRewards',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: 'rewardsList',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'claimedAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ ],
+ name: 'claimAllRewardsOnBehalf',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: 'rewardsList',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'claimedAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ ],
+ name: 'claimAllRewardsToSelf',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: 'rewardsList',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'claimedAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'claimRewards',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'claimRewardsOnBehalf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'claimRewardsToSelf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ components: [
+ {
+ internalType: 'uint88',
+ name: 'emissionPerSecond',
+ type: 'uint88',
+ },
+ {
+ internalType: 'uint256',
+ name: 'totalSupply',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint32',
+ name: 'distributionEnd',
+ type: 'uint32',
+ },
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ internalType: 'contract ITransferStrategyBase',
+ name: 'transferStrategy',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: 'rewardOracle',
+ type: 'address',
+ },
+ ],
+ internalType: 'struct RewardsDataTypes.RewardsConfigInput[]',
+ name: 'config',
+ type: 'tuple[]',
+ },
+ ],
+ name: 'configureAssets',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ ],
+ name: 'getAllUserRewards',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: 'rewardsList',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'unclaimedAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ ],
+ name: 'getAssetDecimals',
+ outputs: [
+ {
+ internalType: 'uint8',
+ name: '',
+ type: 'uint8',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ ],
+ name: 'getClaimer',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getDistributionEnd',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getEmissionManager',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getRewardOracle',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ ],
+ name: 'getRewardsByAsset',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: '',
+ type: 'address[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getRewardsData',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getRewardsList',
+ outputs: [
+ {
+ internalType: 'address[]',
+ name: '',
+ type: 'address[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getTransferStrategy',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getUserAccruedRewards',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getUserAssetIndex',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ ],
+ name: 'getUserRewards',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'totalSupply',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'userBalance',
+ type: 'uint256',
+ },
+ ],
+ name: 'handleAction',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'emissionManager',
+ type: 'address',
+ },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'caller',
+ type: 'address',
+ },
+ ],
+ name: 'setClaimer',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ internalType: 'uint32',
+ name: 'newDistributionEnd',
+ type: 'uint32',
+ },
+ ],
+ name: 'setDistributionEnd',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'emissionManager',
+ type: 'address',
+ },
+ ],
+ name: 'setEmissionManager',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address[]',
+ name: 'rewards',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint88[]',
+ name: 'newEmissionsPerSecond',
+ type: 'uint88[]',
+ },
+ ],
+ name: 'setEmissionPerSecond',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: 'rewardOracle',
+ type: 'address',
+ },
+ ],
+ name: 'setRewardOracle',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'reward',
+ type: 'address',
+ },
+ {
+ internalType: 'contract ITransferStrategyBase',
+ name: 'transferStrategy',
+ type: 'address',
+ },
+ ],
+ name: 'setTransferStrategy',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/aave/abis/pool-v3.ts b/src/apps/aave/abis/pool-v3.ts
new file mode 100644
index 00000000..e5a301d4
--- /dev/null
+++ b/src/apps/aave/abis/pool-v3.ts
@@ -0,0 +1,1168 @@
+// Contract from https://docs.aave.com/developers/core-contracts/pool#abi
+// Arbiscan: https://arbiscan.io/address/0x794a61358d6845594f94dc1db02a252b5b4814ad#readProxyContract
+export const poolV3Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'backer',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ { indexed: false, internalType: 'uint256', name: 'fee', type: 'uint256' },
+ ],
+ name: 'BackUnbacked',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'onBehalfOf',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'enum DataTypes.InterestRateMode',
+ name: 'interestRateMode',
+ type: 'uint8',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'borrowRate',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'uint16',
+ name: 'referralCode',
+ type: 'uint16',
+ },
+ ],
+ name: 'Borrow',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'target',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'initiator',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'enum DataTypes.InterestRateMode',
+ name: 'interestRateMode',
+ type: 'uint8',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'premium',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'uint16',
+ name: 'referralCode',
+ type: 'uint16',
+ },
+ ],
+ name: 'FlashLoan',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalDebt',
+ type: 'uint256',
+ },
+ ],
+ name: 'IsolationModeTotalDebtUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'collateralAsset',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'debtAsset',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'debtToCover',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'liquidatedCollateralAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'liquidator',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'receiveAToken',
+ type: 'bool',
+ },
+ ],
+ name: 'LiquidationCall',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'onBehalfOf',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'uint16',
+ name: 'referralCode',
+ type: 'uint16',
+ },
+ ],
+ name: 'MintUnbacked',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amountMinted',
+ type: 'uint256',
+ },
+ ],
+ name: 'MintedToTreasury',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'RebalanceStableBorrowRate',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'repayer',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'useATokens',
+ type: 'bool',
+ },
+ ],
+ name: 'Repay',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'liquidityRate',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'stableBorrowRate',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'variableBorrowRate',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'liquidityIndex',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'variableBorrowIndex',
+ type: 'uint256',
+ },
+ ],
+ name: 'ReserveDataUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'ReserveUsedAsCollateralDisabled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'ReserveUsedAsCollateralEnabled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'onBehalfOf',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'uint16',
+ name: 'referralCode',
+ type: 'uint16',
+ },
+ ],
+ name: 'Supply',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'enum DataTypes.InterestRateMode',
+ name: 'interestRateMode',
+ type: 'uint8',
+ },
+ ],
+ name: 'SwapBorrowRateMode',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint8',
+ name: 'categoryId',
+ type: 'uint8',
+ },
+ ],
+ name: 'UserEModeSet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'reserve',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'ADDRESSES_PROVIDER',
+ outputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'BRIDGE_PROTOCOL_FEE',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'FLASHLOAN_PREMIUM_TOTAL',
+ outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'FLASHLOAN_PREMIUM_TO_PROTOCOL',
+ outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_NUMBER_RESERVES',
+ outputs: [{ internalType: 'uint16', name: '', type: 'uint16' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_STABLE_RATE_BORROW_SIZE_PERCENT',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'POOL_REVISION',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'fee', type: 'uint256' },
+ ],
+ name: 'backUnbacked',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ ],
+ name: 'borrow',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'borrow',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint8', name: 'id', type: 'uint8' },
+ {
+ components: [
+ { internalType: 'uint16', name: 'ltv', type: 'uint16' },
+ {
+ internalType: 'uint16',
+ name: 'liquidationThreshold',
+ type: 'uint16',
+ },
+ { internalType: 'uint16', name: 'liquidationBonus', type: 'uint16' },
+ { internalType: 'address', name: 'priceSource', type: 'address' },
+ { internalType: 'string', name: 'label', type: 'string' },
+ ],
+ internalType: 'struct DataTypes.EModeCategory',
+ name: 'category',
+ type: 'tuple',
+ },
+ ],
+ name: 'configureEModeCategory',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ ],
+ name: 'deposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'dropReserve',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'balanceFromBefore', type: 'uint256' },
+ { internalType: 'uint256', name: 'balanceToBefore', type: 'uint256' },
+ ],
+ name: 'finalizeTransfer',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'receiverAddress', type: 'address' },
+ { internalType: 'address[]', name: 'assets', type: 'address[]' },
+ { internalType: 'uint256[]', name: 'amounts', type: 'uint256[]' },
+ {
+ internalType: 'uint256[]',
+ name: 'interestRateModes',
+ type: 'uint256[]',
+ },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'bytes', name: 'params', type: 'bytes' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ ],
+ name: 'flashLoan',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'receiverAddress', type: 'address' },
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'bytes', name: 'params', type: 'bytes' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ ],
+ name: 'flashLoanSimple',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'getConfiguration',
+ outputs: [
+ {
+ components: [
+ { internalType: 'uint256', name: 'data', type: 'uint256' },
+ ],
+ internalType: 'struct DataTypes.ReserveConfigurationMap',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }],
+ name: 'getEModeCategoryData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'uint16', name: 'ltv', type: 'uint16' },
+ {
+ internalType: 'uint16',
+ name: 'liquidationThreshold',
+ type: 'uint16',
+ },
+ { internalType: 'uint16', name: 'liquidationBonus', type: 'uint16' },
+ { internalType: 'address', name: 'priceSource', type: 'address' },
+ { internalType: 'string', name: 'label', type: 'string' },
+ ],
+ internalType: 'struct DataTypes.EModeCategory',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint16', name: 'id', type: 'uint16' }],
+ name: 'getReserveAddressById',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'getReserveData',
+ outputs: [
+ {
+ components: [
+ {
+ components: [
+ { internalType: 'uint256', name: 'data', type: 'uint256' },
+ ],
+ internalType: 'struct DataTypes.ReserveConfigurationMap',
+ name: 'configuration',
+ type: 'tuple',
+ },
+ { internalType: 'uint128', name: 'liquidityIndex', type: 'uint128' },
+ {
+ internalType: 'uint128',
+ name: 'currentLiquidityRate',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint128',
+ name: 'variableBorrowIndex',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint128',
+ name: 'currentVariableBorrowRate',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint128',
+ name: 'currentStableBorrowRate',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint40',
+ name: 'lastUpdateTimestamp',
+ type: 'uint40',
+ },
+ { internalType: 'uint16', name: 'id', type: 'uint16' },
+ { internalType: 'address', name: 'aTokenAddress', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'stableDebtTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'variableDebtTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'interestRateStrategyAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint128',
+ name: 'accruedToTreasury',
+ type: 'uint128',
+ },
+ { internalType: 'uint128', name: 'unbacked', type: 'uint128' },
+ {
+ internalType: 'uint128',
+ name: 'isolationModeTotalDebt',
+ type: 'uint128',
+ },
+ ],
+ internalType: 'struct DataTypes.ReserveData',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'getReserveNormalizedIncome',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'getReserveNormalizedVariableDebt',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getReservesCount',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getReservesList',
+ outputs: [{ internalType: 'address[]', name: '', type: 'address[]' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'getUserAccountData',
+ outputs: [
+ { internalType: 'uint256', name: 'totalCollateralBase', type: 'uint256' },
+ { internalType: 'uint256', name: 'totalDebtBase', type: 'uint256' },
+ {
+ internalType: 'uint256',
+ name: 'availableBorrowsBase',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'currentLiquidationThreshold',
+ type: 'uint256',
+ },
+ { internalType: 'uint256', name: 'ltv', type: 'uint256' },
+ { internalType: 'uint256', name: 'healthFactor', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'getUserConfiguration',
+ outputs: [
+ {
+ components: [
+ { internalType: 'uint256', name: 'data', type: 'uint256' },
+ ],
+ internalType: 'struct DataTypes.UserConfigurationMap',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'getUserEMode',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'address', name: 'aTokenAddress', type: 'address' },
+ { internalType: 'address', name: 'stableDebtAddress', type: 'address' },
+ { internalType: 'address', name: 'variableDebtAddress', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'interestRateStrategyAddress',
+ type: 'address',
+ },
+ ],
+ name: 'initReserve',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'collateralAsset', type: 'address' },
+ { internalType: 'address', name: 'debtAsset', type: 'address' },
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'debtToCover', type: 'uint256' },
+ { internalType: 'bool', name: 'receiveAToken', type: 'bool' },
+ ],
+ name: 'liquidationCall',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'args1', type: 'bytes32' },
+ { internalType: 'bytes32', name: 'args2', type: 'bytes32' },
+ ],
+ name: 'liquidationCall',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address[]', name: 'assets', type: 'address[]' }],
+ name: 'mintToTreasury',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ ],
+ name: 'mintUnbacked',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'rebalanceStableBorrowRate',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'rebalanceStableBorrowRate',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'repay',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ ],
+ name: 'repay',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' },
+ ],
+ name: 'repayWithATokens',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'repayWithATokens',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'args', type: 'bytes32' },
+ { internalType: 'bytes32', name: 'r', type: 'bytes32' },
+ { internalType: 'bytes32', name: 's', type: 'bytes32' },
+ ],
+ name: 'repayWithPermit',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint256', name: 'deadline', type: 'uint256' },
+ { internalType: 'uint8', name: 'permitV', type: 'uint8' },
+ { internalType: 'bytes32', name: 'permitR', type: 'bytes32' },
+ { internalType: 'bytes32', name: 'permitS', type: 'bytes32' },
+ ],
+ name: 'repayWithPermit',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'token', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'rescueTokens',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'asset', type: 'address' }],
+ name: 'resetIsolationModeTotalDebt',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ {
+ components: [
+ { internalType: 'uint256', name: 'data', type: 'uint256' },
+ ],
+ internalType: 'struct DataTypes.ReserveConfigurationMap',
+ name: 'configuration',
+ type: 'tuple',
+ },
+ ],
+ name: 'setConfiguration',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'address', name: 'rateStrategyAddress', type: 'address' },
+ ],
+ name: 'setReserveInterestRateStrategyAddress',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint8', name: 'categoryId', type: 'uint8' }],
+ name: 'setUserEMode',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'setUserUseReserveAsCollateral',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'bool', name: 'useAsCollateral', type: 'bool' },
+ ],
+ name: 'setUserUseReserveAsCollateral',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ ],
+ name: 'supply',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'supply',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'address', name: 'onBehalfOf', type: 'address' },
+ { internalType: 'uint16', name: 'referralCode', type: 'uint16' },
+ { internalType: 'uint256', name: 'deadline', type: 'uint256' },
+ { internalType: 'uint8', name: 'permitV', type: 'uint8' },
+ { internalType: 'bytes32', name: 'permitR', type: 'bytes32' },
+ { internalType: 'bytes32', name: 'permitS', type: 'bytes32' },
+ ],
+ name: 'supplyWithPermit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'args', type: 'bytes32' },
+ { internalType: 'bytes32', name: 'r', type: 'bytes32' },
+ { internalType: 'bytes32', name: 's', type: 'bytes32' },
+ ],
+ name: 'supplyWithPermit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'swapBorrowRateMode',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' },
+ ],
+ name: 'swapBorrowRateMode',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'protocolFee', type: 'uint256' }],
+ name: 'updateBridgeProtocolFee',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint128',
+ name: 'flashLoanPremiumTotal',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint128',
+ name: 'flashLoanPremiumToProtocol',
+ type: 'uint128',
+ },
+ ],
+ name: 'updateFlashloanPremiums',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'asset', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ ],
+ name: 'withdraw',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'args', type: 'bytes32' }],
+ name: 'withdraw',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/aave/abis/ui-incentive-data-provider.ts b/src/apps/aave/abis/ui-incentive-data-provider.ts
new file mode 100644
index 00000000..c6f16229
--- /dev/null
+++ b/src/apps/aave/abis/ui-incentive-data-provider.ts
@@ -0,0 +1,643 @@
+// From https://docs.aave.com/developers/periphery-contracts/uiincentivedataproviderv3
+export const uiIncentiveDataProviderV3Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ { internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'getFullReservesIncentiveData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionPerSecond',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'incentivesLastUpdateTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionEndTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ { internalType: 'uint8', name: 'precision', type: 'uint8' },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.RewardInfo[]',
+ name: 'rewardsTokenInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.IncentiveData',
+ name: 'aIncentiveData',
+ type: 'tuple',
+ },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionPerSecond',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'incentivesLastUpdateTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionEndTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ { internalType: 'uint8', name: 'precision', type: 'uint8' },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.RewardInfo[]',
+ name: 'rewardsTokenInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.IncentiveData',
+ name: 'vIncentiveData',
+ type: 'tuple',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.AggregatedReserveIncentiveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'userUnclaimedRewards',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesUserIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserRewardInfo[]',
+ name: 'userRewardsInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.UserIncentiveData',
+ name: 'aTokenIncentivesUserData',
+ type: 'tuple',
+ },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'userUnclaimedRewards',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesUserIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserRewardInfo[]',
+ name: 'userRewardsInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.UserIncentiveData',
+ name: 'vTokenIncentivesUserData',
+ type: 'tuple',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserReserveIncentiveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ name: 'getReservesIncentivesData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionPerSecond',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'incentivesLastUpdateTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionEndTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ { internalType: 'uint8', name: 'precision', type: 'uint8' },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.RewardInfo[]',
+ name: 'rewardsTokenInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.IncentiveData',
+ name: 'aIncentiveData',
+ type: 'tuple',
+ },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionPerSecond',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'incentivesLastUpdateTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'emissionEndTimestamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ { internalType: 'uint8', name: 'precision', type: 'uint8' },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.RewardInfo[]',
+ name: 'rewardsTokenInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.IncentiveData',
+ name: 'vIncentiveData',
+ type: 'tuple',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.AggregatedReserveIncentiveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ { internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'getUserReservesIncentivesData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'userUnclaimedRewards',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesUserIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserRewardInfo[]',
+ name: 'userRewardsInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.UserIncentiveData',
+ name: 'aTokenIncentivesUserData',
+ type: 'tuple',
+ },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'tokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'incentiveControllerAddress',
+ type: 'address',
+ },
+ {
+ components: [
+ {
+ internalType: 'string',
+ name: 'rewardTokenSymbol',
+ type: 'string',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardOracleAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'rewardTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'userUnclaimedRewards',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenIncentivesUserIndex',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'rewardPriceFeed',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'priceFeedDecimals',
+ type: 'uint8',
+ },
+ {
+ internalType: 'uint8',
+ name: 'rewardTokenDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserRewardInfo[]',
+ name: 'userRewardsInformation',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct IUiIncentiveDataProviderV3.UserIncentiveData',
+ name: 'vTokenIncentivesUserData',
+ type: 'tuple',
+ },
+ ],
+ internalType:
+ 'struct IUiIncentiveDataProviderV3.UserReserveIncentiveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/aave/abis/ui-pool-data-provider-v3.ts b/src/apps/aave/abis/ui-pool-data-provider-v3.ts
new file mode 100644
index 00000000..c9797cf3
--- /dev/null
+++ b/src/apps/aave/abis/ui-pool-data-provider-v3.ts
@@ -0,0 +1,338 @@
+// From https://docs.aave.com/developers/periphery-contracts/uipooldataproviderv3
+export const uiPoolDataProviderV3Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: '_networkBaseTokenPriceInUsdProxyAggregator',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: '_marketReferenceCurrencyPriceInUsdProxyAggregator',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ inputs: [],
+ name: 'ETH_CURRENCY_UNIT',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MKR_ADDRESS',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: '_bytes32', type: 'bytes32' }],
+ name: 'bytes32ToString',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ name: 'getEModes',
+ outputs: [
+ {
+ components: [
+ { internalType: 'uint8', name: 'id', type: 'uint8' },
+ {
+ components: [
+ { internalType: 'uint16', name: 'ltv', type: 'uint16' },
+ {
+ internalType: 'uint16',
+ name: 'liquidationThreshold',
+ type: 'uint16',
+ },
+ {
+ internalType: 'uint16',
+ name: 'liquidationBonus',
+ type: 'uint16',
+ },
+ {
+ internalType: 'uint128',
+ name: 'collateralBitmap',
+ type: 'uint128',
+ },
+ { internalType: 'string', name: 'label', type: 'string' },
+ {
+ internalType: 'uint128',
+ name: 'borrowableBitmap',
+ type: 'uint128',
+ },
+ ],
+ internalType: 'struct DataTypes.EModeCategory',
+ name: 'eMode',
+ type: 'tuple',
+ },
+ ],
+ internalType: 'struct IUiPoolDataProviderV3.Emode[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ name: 'getReservesData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ { internalType: 'string', name: 'name', type: 'string' },
+ { internalType: 'string', name: 'symbol', type: 'string' },
+ { internalType: 'uint256', name: 'decimals', type: 'uint256' },
+ {
+ internalType: 'uint256',
+ name: 'baseLTVasCollateral',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'reserveLiquidationThreshold',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'reserveLiquidationBonus',
+ type: 'uint256',
+ },
+ { internalType: 'uint256', name: 'reserveFactor', type: 'uint256' },
+ {
+ internalType: 'bool',
+ name: 'usageAsCollateralEnabled',
+ type: 'bool',
+ },
+ { internalType: 'bool', name: 'borrowingEnabled', type: 'bool' },
+ { internalType: 'bool', name: 'isActive', type: 'bool' },
+ { internalType: 'bool', name: 'isFrozen', type: 'bool' },
+ { internalType: 'uint128', name: 'liquidityIndex', type: 'uint128' },
+ {
+ internalType: 'uint128',
+ name: 'variableBorrowIndex',
+ type: 'uint128',
+ },
+ { internalType: 'uint128', name: 'liquidityRate', type: 'uint128' },
+ {
+ internalType: 'uint128',
+ name: 'variableBorrowRate',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint40',
+ name: 'lastUpdateTimestamp',
+ type: 'uint40',
+ },
+ { internalType: 'address', name: 'aTokenAddress', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'variableDebtTokenAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'interestRateStrategyAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'availableLiquidity',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'totalScaledVariableDebt',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'priceInMarketReferenceCurrency',
+ type: 'uint256',
+ },
+ { internalType: 'address', name: 'priceOracle', type: 'address' },
+ {
+ internalType: 'uint256',
+ name: 'variableRateSlope1',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'variableRateSlope2',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'baseVariableBorrowRate',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'optimalUsageRatio',
+ type: 'uint256',
+ },
+ { internalType: 'bool', name: 'isPaused', type: 'bool' },
+ { internalType: 'bool', name: 'isSiloedBorrowing', type: 'bool' },
+ {
+ internalType: 'uint128',
+ name: 'accruedToTreasury',
+ type: 'uint128',
+ },
+ { internalType: 'uint128', name: 'unbacked', type: 'uint128' },
+ {
+ internalType: 'uint128',
+ name: 'isolationModeTotalDebt',
+ type: 'uint128',
+ },
+ { internalType: 'bool', name: 'flashLoanEnabled', type: 'bool' },
+ { internalType: 'uint256', name: 'debtCeiling', type: 'uint256' },
+ {
+ internalType: 'uint256',
+ name: 'debtCeilingDecimals',
+ type: 'uint256',
+ },
+ { internalType: 'uint256', name: 'borrowCap', type: 'uint256' },
+ { internalType: 'uint256', name: 'supplyCap', type: 'uint256' },
+ { internalType: 'bool', name: 'borrowableInIsolation', type: 'bool' },
+ { internalType: 'bool', name: 'virtualAccActive', type: 'bool' },
+ {
+ internalType: 'uint128',
+ name: 'virtualUnderlyingBalance',
+ type: 'uint128',
+ },
+ ],
+ internalType: 'struct IUiPoolDataProviderV3.AggregatedReserveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'marketReferenceCurrencyUnit',
+ type: 'uint256',
+ },
+ {
+ internalType: 'int256',
+ name: 'marketReferenceCurrencyPriceInUsd',
+ type: 'int256',
+ },
+ {
+ internalType: 'int256',
+ name: 'networkBaseTokenPriceInUsd',
+ type: 'int256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'networkBaseTokenPriceDecimals',
+ type: 'uint8',
+ },
+ ],
+ internalType: 'struct IUiPoolDataProviderV3.BaseCurrencyInfo',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ ],
+ name: 'getReservesList',
+ outputs: [{ internalType: 'address[]', name: '', type: 'address[]' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IPoolAddressesProvider',
+ name: 'provider',
+ type: 'address',
+ },
+ { internalType: 'address', name: 'user', type: 'address' },
+ ],
+ name: 'getUserReservesData',
+ outputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'underlyingAsset', type: 'address' },
+ {
+ internalType: 'uint256',
+ name: 'scaledATokenBalance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'bool',
+ name: 'usageAsCollateralEnabledOnUser',
+ type: 'bool',
+ },
+ {
+ internalType: 'uint256',
+ name: 'scaledVariableDebt',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct IUiPoolDataProviderV3.UserReserveData[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ { internalType: 'uint8', name: '', type: 'uint8' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'marketReferenceCurrencyPriceInUsdProxyAggregator',
+ outputs: [
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'networkBaseTokenPriceInUsdProxyAggregator',
+ outputs: [
+ {
+ internalType: 'contract IEACAggregatorProxy',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/aave/constants.ts b/src/apps/aave/constants.ts
new file mode 100644
index 00000000..e1d83ded
--- /dev/null
+++ b/src/apps/aave/constants.ts
@@ -0,0 +1,133 @@
+import { Address } from '../../types/address'
+import { NetworkId } from '../../types/networkId'
+import {
+ AaveV3Ethereum,
+ AaveV3Sepolia,
+ AaveV3Arbitrum,
+ AaveV3ArbitrumSepolia,
+ AaveV3Optimism,
+ AaveV3OptimismSepolia,
+ AaveV3Polygon,
+ AaveV3Base,
+ AaveV3Celo,
+} from '@bgd-labs/aave-address-book'
+
+export const AAVE_V3_ADDRESSES_BY_NETWORK_ID: Record<
+ NetworkId,
+ | {
+ poolAddressesProvider: Address
+ uiPoolDataProvider: Address
+ uiIncentiveDataProvider: Address
+ incentivesController: Address
+ pool: Address
+ }
+ | undefined
+> = {
+ [NetworkId['celo-mainnet']]: {
+ poolAddressesProvider: AaveV3Celo.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Celo.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Celo.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Celo.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Celo.POOL,
+ },
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['ethereum-mainnet']]: {
+ poolAddressesProvider: AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Ethereum.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Ethereum.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Ethereum.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Ethereum.POOL,
+ },
+ [NetworkId['ethereum-sepolia']]: {
+ poolAddressesProvider: AaveV3Sepolia.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Sepolia.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Sepolia.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Sepolia.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Sepolia.POOL,
+ },
+ [NetworkId['arbitrum-one']]: {
+ poolAddressesProvider: AaveV3Arbitrum.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Arbitrum.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Arbitrum.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Arbitrum.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Arbitrum.POOL,
+ },
+ [NetworkId['arbitrum-sepolia']]: {
+ poolAddressesProvider: AaveV3ArbitrumSepolia.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3ArbitrumSepolia.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3ArbitrumSepolia.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3ArbitrumSepolia.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3ArbitrumSepolia.POOL,
+ },
+ [NetworkId['op-mainnet']]: {
+ poolAddressesProvider: AaveV3Optimism.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Optimism.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Optimism.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Optimism.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Optimism.POOL,
+ },
+ [NetworkId['op-sepolia']]: {
+ poolAddressesProvider: AaveV3OptimismSepolia.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3OptimismSepolia.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3OptimismSepolia.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3OptimismSepolia.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3OptimismSepolia.POOL,
+ },
+ [NetworkId['polygon-pos-mainnet']]: {
+ poolAddressesProvider: AaveV3Polygon.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Polygon.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Polygon.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Polygon.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Polygon.POOL,
+ },
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['base-mainnet']]: {
+ poolAddressesProvider: AaveV3Base.POOL_ADDRESSES_PROVIDER,
+ uiPoolDataProvider: AaveV3Base.UI_POOL_DATA_PROVIDER,
+ uiIncentiveDataProvider: AaveV3Base.UI_INCENTIVE_DATA_PROVIDER,
+ incentivesController: AaveV3Base.DEFAULT_INCENTIVES_CONTROLLER,
+ pool: AaveV3Base.POOL,
+ },
+ [NetworkId['base-sepolia']]: undefined, // does not have UI_POOL_DATA_PROVIDER
+}
+
+enum AaveMarketName {
+ proto_mainnet_v3 = 'proto_mainnet_v3',
+ proto_arbitrum_v3 = 'proto_arbitrum_v3',
+ proto_optimism_v3 = 'proto_optimism_v3',
+ proto_polygon_v3 = 'proto_polygon_v3',
+ proto_base_v3 = 'proto_base_v3',
+ proto_celo_v3 = 'proto_celo_v3',
+}
+
+export const AAVE_LOGO =
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/aave.png'
+
+export const AAVE_POOLS_BASE_URL = 'https://app.aave.com/'
+
+export const NETWORK_ID_TO_AAVE_MARKET_NAME: Record<
+ NetworkId,
+ AaveMarketName | undefined
+> = {
+ [NetworkId['celo-mainnet']]: AaveMarketName.proto_celo_v3,
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['ethereum-mainnet']]: AaveMarketName.proto_mainnet_v3,
+ [NetworkId['ethereum-sepolia']]: undefined,
+ [NetworkId['arbitrum-one']]: AaveMarketName.proto_arbitrum_v3,
+ [NetworkId['arbitrum-sepolia']]: undefined,
+ [NetworkId['op-mainnet']]: AaveMarketName.proto_optimism_v3,
+ [NetworkId['op-sepolia']]: undefined,
+ [NetworkId['polygon-pos-mainnet']]: AaveMarketName.proto_polygon_v3,
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['base-mainnet']]: AaveMarketName.proto_base_v3,
+ [NetworkId['base-sepolia']]: undefined,
+}
+
+export const AAVE_CONTRACT_CREATED_AT: Record = {
+ [`${NetworkId['arbitrum-one']}:0x724dc807b04555b71ed48a6896b6f41593b8c637`]:
+ '2023-06-28T10:09:48.000Z',
+ [`${NetworkId['arbitrum-sepolia']}:0x460b97bd498e1157530aeb3086301d5225b91216`]:
+ '2024-03-08T14:23:53.000Z',
+}
+
+export const AAVE_TERMS_URL = 'https://aave.com/terms-of-service'
diff --git a/src/apps/aave/getAaveTokensWithIncentives.ts b/src/apps/aave/getAaveTokensWithIncentives.ts
new file mode 100644
index 00000000..22c1534d
--- /dev/null
+++ b/src/apps/aave/getAaveTokensWithIncentives.ts
@@ -0,0 +1,29 @@
+import { Address } from 'viem'
+
+interface IncentiveData {
+ readonly tokenAddress: Address
+ readonly rewardsTokenInformation: readonly any[]
+}
+
+// Just a subset of the actual data
+interface ReserveIncentivesData {
+ readonly aIncentiveData: IncentiveData
+ readonly vIncentiveData: IncentiveData
+}
+
+export function getAaveTokensWithIncentives(
+ reservesIncentiveData: readonly ReserveIncentivesData[],
+): Address[] {
+ return reservesIncentiveData
+ .map(({ aIncentiveData, vIncentiveData }) => {
+ const assetsWithRewards: Address[] = []
+ if (aIncentiveData.rewardsTokenInformation.length) {
+ assetsWithRewards.push(aIncentiveData.tokenAddress)
+ }
+ if (vIncentiveData.rewardsTokenInformation.length) {
+ assetsWithRewards.push(vIncentiveData.tokenAddress)
+ }
+ return assetsWithRewards
+ })
+ .flat()
+}
diff --git a/src/apps/aave/positions.e2e.ts b/src/apps/aave/positions.e2e.ts
new file mode 100644
index 00000000..fd7b112e
--- /dev/null
+++ b/src/apps/aave/positions.e2e.ts
@@ -0,0 +1,29 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe.each([NetworkId['arbitrum-one'], NetworkId['ethereum-mainnet']])(
+ 'getPositionDefinitions for networkId %s',
+ (networkId) => {
+ it('should get the address definitions successfully', async () => {
+ if (networkId === NetworkId['ethereum-mainnet']) {
+ // We don't yet have a position with our test wallet
+ // TODO: add one
+ return
+ }
+ const positions = await hook.getPositionDefinitions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should get definitions successfully when no address is provided', async () => {
+ const positions = await hook.getPositionDefinitions({ networkId, t })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+ },
+)
diff --git a/src/apps/aave/positions.ts b/src/apps/aave/positions.ts
new file mode 100644
index 00000000..56789bff
--- /dev/null
+++ b/src/apps/aave/positions.ts
@@ -0,0 +1,304 @@
+import {
+ PositionsHook,
+ AppTokenPositionDefinition,
+ UnknownAppTokenError,
+ TokenDefinition,
+ ContractPositionDefinition,
+ ClaimType,
+} from '../../types/positions'
+import { Address } from 'viem'
+import {
+ DecimalNumber,
+ toDecimalNumber,
+ toSerializedDecimalNumber,
+} from '../../types/numbers'
+import BigNumber from 'bignumber.js'
+import { getClient } from '../../runtime/client'
+import { uiPoolDataProviderV3Abi } from './abis/ui-pool-data-provider-v3'
+import { getTokenId } from '../../runtime/getTokenId'
+import { uiIncentiveDataProviderV3Abi } from './abis/ui-incentive-data-provider'
+import {
+ AAVE_CONTRACT_CREATED_AT,
+ AAVE_LOGO,
+ AAVE_POOLS_BASE_URL,
+ AAVE_TERMS_URL,
+ AAVE_V3_ADDRESSES_BY_NETWORK_ID,
+ NETWORK_ID_TO_AAVE_MARKET_NAME,
+} from './constants'
+import { aTokenAbi } from './abis/atoken'
+import { incentivesControllerV3Abi } from './abis/incentives-controller-v3'
+import { getAaveTokensWithIncentives } from './getAaveTokensWithIncentives'
+import { getPositionId } from '../../runtime/getPositionId'
+
+const COMPOUND_PERIOD = 365 * 24 * 60 * 60 // 1 year in seconds
+
+// Get APY from APR, both in percentage (0-100)
+function getApy(apr: number) {
+ // Note: not using BigNumber here as it takes too long to calculate
+ return ((1 + apr / 100 / COMPOUND_PERIOD) ** COMPOUND_PERIOD - 1) * 100
+}
+
+// The chain data is in RAY units (1e27) and non compounded
+// https://docs.aave.com/developers/guides/rates-guide#formatting-rates
+function getApyFromRayApr(apr: bigint) {
+ return getApy(new BigNumber(apr.toString()).div(1e27).times(100).toNumber())
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Aave',
+ }
+ },
+ async getPositionDefinitions({ networkId, address, t }) {
+ const aaveAddresses = AAVE_V3_ADDRESSES_BY_NETWORK_ID[networkId]
+ if (!aaveAddresses) {
+ return []
+ }
+
+ const client = getClient(networkId)
+
+ const [reservesData] = await client.readContract({
+ address: aaveAddresses.uiPoolDataProvider,
+ abi: uiPoolDataProviderV3Abi,
+ functionName: 'getReservesData',
+ args: [aaveAddresses.poolAddressesProvider],
+ })
+
+ const [
+ [userReserveData, _userEmodeCategoryId],
+ [reserveIncentiveData, _userIncentivesData],
+ ] = address
+ ? await client.multicall({
+ contracts: [
+ {
+ address: aaveAddresses.uiPoolDataProvider,
+ abi: uiPoolDataProviderV3Abi,
+ functionName: 'getUserReservesData',
+ args: [aaveAddresses.poolAddressesProvider, address as Address],
+ },
+ {
+ address: aaveAddresses.uiIncentiveDataProvider,
+ abi: uiIncentiveDataProviderV3Abi,
+ functionName: 'getFullReservesIncentiveData',
+ args: [aaveAddresses.poolAddressesProvider, address as Address],
+ },
+ ],
+ allowFailure: false,
+ })
+ : [
+ [undefined, undefined],
+ [undefined, undefined],
+ ]
+
+ // Note: Instead of calling `getAllUserRewards`, we could use reserveIncentiveData and userIncentivesData to get all user rewards
+ // but it requires some additional calculations to get the accrued rewards (linked to a/v/sToken held) on top of the unclaimedRewards to get total rewards.
+ // This is for simplicity here.
+ // See https://github.com/aave/aave-utilities/blob/446d9af6f14154771c0343538b59e2aeb7b38e47/packages/math-utils/src/formatters/incentive/calculate-all-user-incentives.ts#L31
+ const allUserRewards = address
+ ? await client.readContract({
+ address: aaveAddresses.incentivesController,
+ abi: incentivesControllerV3Abi,
+ functionName: 'getAllUserRewards',
+ args: [
+ // This builds the list of a/v/sToken address with incentives
+ // Because `getAllUserRewards` reverts if we pass an address with no incentives
+ getAaveTokensWithIncentives(reserveIncentiveData ?? []),
+ address as Address,
+ ],
+ })
+ : [[], []]
+ const [rewardTokenAddresses, rewardTokenAmounts] = allUserRewards
+ const userRewards = rewardTokenAddresses
+ .map((rewardTokenAddress, i) => ({
+ rewardTokenAddress,
+ rewardTokenAmount: rewardTokenAmounts[i],
+ }))
+ .filter(({ rewardTokenAmount }) => rewardTokenAmount > 0n)
+
+ const [totalSupplies, lpTokenDecimals] = await Promise.all([
+ Promise.all(
+ reservesData.map(({ aTokenAddress }) => {
+ return client.readContract({
+ address: aTokenAddress,
+ abi: aTokenAbi,
+ functionName: 'totalSupply',
+ args: [],
+ })
+ }),
+ ),
+ Promise.all(
+ reservesData.map(({ aTokenAddress }) => {
+ return client.readContract({
+ address: aTokenAddress,
+ abi: aTokenAbi,
+ functionName: 'decimals',
+ args: [],
+ })
+ }),
+ ),
+ ])
+
+ const manageUrl =
+ AAVE_POOLS_BASE_URL +
+ (NETWORK_ID_TO_AAVE_MARKET_NAME[networkId]
+ ? `?marketName=${NETWORK_ID_TO_AAVE_MARKET_NAME[networkId]}`
+ : '')
+
+ const rewardsPositionDefinition = userRewards.length
+ ? ({
+ type: 'contract-position-definition',
+ networkId,
+ address: aaveAddresses.incentivesController.toLowerCase(),
+ tokens: userRewards.map((userReward) => ({
+ address: userReward.rewardTokenAddress.toLowerCase(),
+ networkId,
+ category: 'claimable',
+ })),
+ shortcutTriggerArgs: {
+ 'claim-rewards': {
+ positionAddress: aaveAddresses.incentivesController.toLowerCase(),
+ },
+ },
+ availableShortcutIds: ['claim-rewards'],
+ balances: async ({ resolvedTokensByTokenId }) =>
+ userRewards.map((userRewards) => {
+ const rewardsDecimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: userRewards.rewardTokenAddress,
+ networkId,
+ })
+ ].decimals
+ return toDecimalNumber(
+ userRewards.rewardTokenAmount,
+ rewardsDecimals,
+ )
+ }),
+ displayProps: {
+ title: `Claimable rewards`,
+ description: 'For supplying and borrowing',
+ imageUrl: AAVE_LOGO,
+ manageUrl,
+ },
+ } satisfies ContractPositionDefinition)
+ : null
+
+ return [
+ reservesData.flatMap((reserveData, i) => {
+ const supplyApy = getApyFromRayApr(reserveData.liquidityRate)
+ const variableBorrowApy = getApyFromRayApr(
+ reserveData.variableBorrowRate,
+ )
+
+ // Include a token if the user has a balance
+ // or if no user data is available (when querying all positions)
+ const useAToken =
+ !userReserveData || userReserveData[i].scaledATokenBalance > 0n
+ const useVariableDebt =
+ !userReserveData || userReserveData[i].scaledVariableDebt > 0n
+
+ return [
+ // AToken
+ useAToken &&
+ ({
+ type: 'app-token-definition',
+ networkId,
+ address: reserveData.aTokenAddress.toLowerCase(),
+ tokens: [
+ {
+ address: reserveData.underlyingAsset.toLowerCase(),
+ networkId,
+ },
+ ],
+ availableShortcutIds: ['deposit', 'withdraw', 'swap-deposit'],
+ shortcutTriggerArgs: {
+ deposit: {
+ tokenAddress: reserveData.underlyingAsset.toLowerCase(),
+ tokenDecimals: Number(reserveData.decimals),
+ },
+ withdraw: {
+ tokenAddress: reserveData.aTokenAddress.toLowerCase(),
+ tokenDecimals: lpTokenDecimals[i],
+ },
+ 'swap-deposit': {
+ tokenAddress: reserveData.underlyingAsset.toLowerCase(),
+ },
+ },
+ displayProps: {
+ title: reserveData.symbol,
+ description: `Supplied (APY: ${supplyApy.toFixed(2)}%)`,
+ imageUrl: AAVE_LOGO,
+ manageUrl,
+ },
+ dataProps: {
+ manageUrl,
+ claimType: ClaimType.Rewards,
+ termsUrl: AAVE_TERMS_URL,
+ cantSeparateCompoundedInterest: true,
+ contractCreatedAt:
+ AAVE_CONTRACT_CREATED_AT[
+ getTokenId({
+ networkId,
+ address: reserveData.aTokenAddress.toLowerCase(),
+ })
+ ],
+ tvl: toSerializedDecimalNumber(
+ toDecimalNumber(totalSupplies[i], lpTokenDecimals[i]),
+ ),
+ yieldRates: [
+ {
+ percentage: supplyApy,
+ label: t('yieldRates.earningsApy'),
+ tokenId: getTokenId({
+ networkId,
+ address: reserveData.underlyingAsset.toLowerCase(),
+ }),
+ },
+ ],
+ earningItems: [],
+ depositTokenId: getTokenId({
+ networkId,
+ address: reserveData.underlyingAsset.toLowerCase(),
+ }),
+ withdrawTokenId: getTokenId({
+ networkId,
+ address: reserveData.aTokenAddress.toLowerCase(),
+ }),
+ rewardsPositionIds: rewardsPositionDefinition
+ ? [getPositionId(rewardsPositionDefinition)]
+ : [],
+ },
+ pricePerShare: [new BigNumber(1) as DecimalNumber],
+ } satisfies AppTokenPositionDefinition),
+ // Variable debt token
+ useVariableDebt &&
+ ({
+ type: 'app-token-definition',
+ networkId,
+ address: reserveData.variableDebtTokenAddress.toLowerCase(),
+ tokens: [{ address: reserveData.underlyingAsset, networkId }],
+ displayProps: {
+ title: `${reserveData.symbol} debt`,
+ description: `Borrowed variable (APY: ${variableBorrowApy.toFixed(
+ 2,
+ )}%)`,
+ imageUrl: AAVE_LOGO,
+ manageUrl,
+ },
+ // TODO: update runtime so we can specify a negative balance for debt
+ // instead of using a negative pricePerShare
+ pricePerShare: [new BigNumber(-1) as DecimalNumber],
+ } satisfies AppTokenPositionDefinition),
+ ].filter((x) => !!x)
+ }),
+ // User rewards
+ rewardsPositionDefinition ? [rewardsPositionDefinition] : [],
+ ].flat()
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/aave/shortcuts.e2e.ts b/src/apps/aave/shortcuts.e2e.ts
new file mode 100644
index 00000000..9d129d42
--- /dev/null
+++ b/src/apps/aave/shortcuts.e2e.ts
@@ -0,0 +1,113 @@
+import hook from './shortcuts'
+import { NetworkId } from '../../types/networkId'
+import { ShortcutDefinition } from '../../types/shortcuts'
+
+describe('getShortcutDefinitions', () => {
+ it('should get the definitions successfully', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ expect(shortcuts.length).toBeGreaterThan(0)
+ })
+
+ describe('deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'deposit')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC
+ tokenDecimals: 6,
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0xaf88d065e77c8cc2239327c5edb3a432268e5831`,
+ amount: '10',
+ },
+ ],
+ })
+
+ expect(transactions.length).toEqual(2)
+ })
+ })
+
+ describe('withdraw.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'withdraw')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637', // aArbUSDCn
+ tokenDecimals: 6,
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0x724dc807b04555b71ed48a6896b6f41593b8c637`,
+ amount: '10',
+ },
+ ],
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+
+ describe('claim-rewards.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find(
+ (shortcut) => shortcut.id === 'claim-rewards',
+ )
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ positionAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+
+ describe('swap-deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find(
+ (shortcut) => shortcut.id === 'swap-deposit',
+ )
+ expect(shortcut).toBeDefined()
+ expect(shortcut!.category).toEqual('swap-deposit')
+
+ const { transactions, dataProps } = await (
+ shortcut as ShortcutDefinition<'swap-deposit', any>
+ ).onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: {
+ decimals: 18,
+ tokenId: `${NetworkId['arbitrum-one']}:native`, // ETH
+ amount: '0.0001',
+ isNative: true,
+ },
+ tokenAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC
+ })
+
+ expect(transactions.length).toEqual(1)
+ expect(dataProps).toBeDefined()
+ expect(dataProps.swapTransaction).toBeDefined()
+ })
+ })
+})
diff --git a/src/apps/aave/shortcuts.ts b/src/apps/aave/shortcuts.ts
new file mode 100644
index 00000000..c7511c4b
--- /dev/null
+++ b/src/apps/aave/shortcuts.ts
@@ -0,0 +1,303 @@
+import {
+ Address,
+ encodeFunctionData,
+ parseUnits,
+ erc20Abi,
+ maxUint256,
+} from 'viem'
+import {
+ createShortcut,
+ ShortcutsHook,
+ tokenAmounts,
+ tokenAmountWithMetadata,
+ ZodEnableAppFee,
+ Transaction,
+} from '../../types/shortcuts'
+import { NetworkId } from '../../types/networkId'
+import { ZodAddressLowerCased } from '../../types/address'
+import { z } from 'zod'
+import { getClient } from '../../runtime/client'
+import { poolV3Abi } from './abis/pool-v3'
+import { aTokenAbi } from './abis/atoken'
+import { AAVE_V3_ADDRESSES_BY_NETWORK_ID } from './constants'
+import { incentivesControllerV3Abi } from './abis/incentives-controller-v3'
+import { simulateTransactions } from '../../runtime/simulateTransactions'
+import { uiIncentiveDataProviderV3Abi } from './abis/ui-incentive-data-provider'
+import { getAaveTokensWithIncentives } from './getAaveTokensWithIncentives'
+import { ChainType, SquidCallType } from '@0xsquid/squid-types'
+import { prepareSwapTransactions } from '../../utils/prepareSwapTransactions'
+
+// Hardcoded fallback if simulation isn't enabled
+const DEFAULT_DEPOSIT_GAS = 1_000_000n
+const DEFAULT_APPROVE_GAS = 200_000n
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId, _address?: string) {
+ const aaveAddresses = AAVE_V3_ADDRESSES_BY_NETWORK_ID[networkId]
+ if (!aaveAddresses) {
+ return []
+ }
+
+ const poolContractAddress = aaveAddresses.pool
+ const incentivesContractAddress = aaveAddresses.incentivesController
+
+ return [
+ createShortcut({
+ id: 'deposit',
+ name: 'Deposit',
+ description: 'Lend your assets to earn interest',
+ networkIds: [networkId],
+ category: 'deposit',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ // these two will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ tokenAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ tokenAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ // amount in smallest unit
+ const amountToSupply = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const client = getClient(networkId)
+
+ const approvedAllowanceForSpender = await client.readContract({
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'allowance',
+ args: [walletAddress, poolContractAddress],
+ })
+
+ if (approvedAllowanceForSpender < amountToSupply) {
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [poolContractAddress, amountToSupply],
+ })
+
+ const approveTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: tokenAddress,
+ data,
+ }
+ transactions.push(approveTx)
+ }
+
+ const supplyTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: poolContractAddress,
+ data: encodeFunctionData({
+ abi: poolV3Abi,
+ functionName: 'supply',
+ args: [tokenAddress, amountToSupply, walletAddress, 0],
+ }),
+ }
+
+ transactions.push(supplyTx)
+
+ // TODO: consider moving this concern to the runtime
+ try {
+ const simulatedTransactions = await simulateTransactions({
+ transactions,
+ networkId,
+ })
+ const supplySimulatedTx =
+ simulatedTransactions[simulatedTransactions.length - 1]
+
+ // 15% buffer on the estimation from the simulation
+ supplyTx.gas = (BigInt(supplySimulatedTx.gasNeeded) * 115n) / 100n
+ supplyTx.estimatedGasUse = BigInt(supplySimulatedTx.gasUsed)
+ } catch (error) {
+ supplyTx.gas = DEFAULT_DEPOSIT_GAS
+ supplyTx.estimatedGasUse = DEFAULT_DEPOSIT_GAS / 3n
+ }
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'withdraw',
+ name: 'Withdraw',
+ description: 'Withdraw your assets',
+ networkIds: [networkId],
+ category: 'withdraw',
+ triggerInputShape: {
+ // token must be the A token
+ tokens: tokenAmounts.length(1),
+ // these two will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ tokenAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ tokenAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ // amount in smallest unit
+ // useMax Withdraws entire balance https://docs.aave.com/developers/core-contracts/pool#withdraw
+ const amountToWithdraw = tokens[0].useMax
+ ? maxUint256
+ : parseUnits(tokens[0].amount, tokenDecimals)
+
+ const client = getClient(networkId)
+
+ const underlyingAssetAddress = await client.readContract({
+ address: tokenAddress,
+ abi: aTokenAbi,
+ functionName: 'UNDERLYING_ASSET_ADDRESS',
+ })
+
+ const withdrawTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: poolContractAddress,
+ data: encodeFunctionData({
+ abi: poolV3Abi,
+ functionName: 'withdraw',
+ args: [underlyingAssetAddress, amountToWithdraw, walletAddress],
+ }),
+ }
+
+ transactions.push(withdrawTx)
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'claim-rewards',
+ name: 'Claim',
+ description: 'Claim rewards',
+ networkIds: [networkId],
+ category: 'claim',
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address }) {
+ const walletAddress = address as Address
+
+ const client = getClient(networkId)
+
+ // Get a/v/sToken for which we can claim rewards
+ const reserveIncentiveData = await client.readContract({
+ address: aaveAddresses.uiIncentiveDataProvider,
+ abi: uiIncentiveDataProviderV3Abi,
+ functionName: 'getReservesIncentivesData',
+ args: [aaveAddresses.poolAddressesProvider],
+ })
+
+ // This builds the list of a/v/sToken address with incentives
+ const assetsWithIncentives =
+ getAaveTokensWithIncentives(reserveIncentiveData)
+
+ return {
+ transactions: [
+ {
+ networkId,
+ from: walletAddress,
+ to: incentivesContractAddress,
+ data: encodeFunctionData({
+ abi: incentivesControllerV3Abi,
+ functionName: 'claimAllRewardsToSelf',
+ args: [assetsWithIncentives],
+ }),
+ },
+ ],
+ }
+ },
+ }),
+ createShortcut({
+ id: 'swap-deposit',
+ name: 'Swap & Deposit',
+ description: 'Swap assets and lend them to earn interest',
+ networkIds: [networkId],
+ category: 'swap-deposit',
+ triggerInputShape: {
+ swapFromToken: tokenAmountWithMetadata,
+ enableAppFee: ZodEnableAppFee,
+ // set via shortcutTriggerArgs, the deposit token's address
+ tokenAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({
+ swapFromToken,
+ tokenAddress,
+ address,
+ networkId,
+ enableAppFee,
+ }) {
+ const walletAddress = address as Address
+ // use a placeholder non zero amount so tx simulation can succeed.
+ // squid postHook will replace this with the actual amount after swap.
+ const amount = 1n
+ const approveData = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [poolContractAddress, amount],
+ })
+ const supplyData = encodeFunctionData({
+ abi: poolV3Abi,
+ functionName: 'supply',
+ args: [tokenAddress, amount, walletAddress, 0],
+ })
+
+ return await prepareSwapTransactions({
+ networkId,
+ swapFromToken,
+ swapToTokenAddress: tokenAddress,
+ walletAddress,
+ enableAppFee,
+ // based off of https://docs.squidrouter.com/building-with-squid-v2/key-concepts/hooks/build-a-posthook
+ postHook: {
+ chainType: ChainType.EVM,
+ calls: [
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: tokenAddress,
+ callData: approveData,
+ payload: {
+ tokenAddress,
+ inputPos: 1,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_APPROVE_GAS.toString(),
+ },
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: poolContractAddress,
+ callData: supplyData,
+ payload: {
+ tokenAddress,
+ inputPos: 1,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_DEPOSIT_GAS.toString(),
+ },
+ ],
+ description: 'Deposit into aave pool',
+ },
+ })
+ },
+ }),
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/allbridge/abis/pool.ts b/src/apps/allbridge/abis/pool.ts
new file mode 100644
index 00000000..293eff7c
--- /dev/null
+++ b/src/apps/allbridge/abis/pool.ts
@@ -0,0 +1,555 @@
+// https://docs-core.allbridge.io/product/how-does-allbridge-core-work/allbridge-core-contracts
+// https://celoscan.io/address/0xfb2C7c10e731EBe96Dabdf4A96D656Bfe8e2b5Af#code
+
+export const poolAbi = [
+ {
+ inputs: [
+ { internalType: 'address', name: 'router_', type: 'address' },
+ { internalType: 'uint256', name: 'a_', type: 'uint256' },
+ { internalType: 'contract ERC20', name: 'token_', type: 'address' },
+ { internalType: 'uint16', name: 'feeShareBP_', type: 'uint16' },
+ { internalType: 'uint256', name: 'balanceRatioMinBP_', type: 'uint256' },
+ { internalType: 'string', name: 'lpName', type: 'string' },
+ { internalType: 'string', name: 'lpSymbol', type: 'string' },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Deposit',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'previousOwner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'RewardsClaimed',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'recipient',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'vUsdAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ { indexed: false, internalType: 'uint256', name: 'fee', type: 'uint256' },
+ ],
+ name: 'SwappedFromVUsd',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'sender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'vUsdAmount',
+ type: 'uint256',
+ },
+ { indexed: false, internalType: 'uint256', name: 'fee', type: 'uint256' },
+ ],
+ name: 'SwappedToVUsd',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'user', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ { stateMutability: 'payable', type: 'fallback' },
+ {
+ inputs: [],
+ name: 'a',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'accRewardPerShareP',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adjustTotalLpAmount',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adminFeeAmount',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adminFeeShareBP',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'balanceRatioMinBP',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'canDeposit',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'canWithdraw',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'claimAdminFee',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'claimRewards',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'd',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
+ ],
+ name: 'decreaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
+ name: 'deposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'feeShareBP',
+ outputs: [{ internalType: 'uint16', name: '', type: 'uint16' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getPrice',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'x', type: 'uint256' }],
+ name: 'getY',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
+ ],
+ name: 'increaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'pendingReward',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'renounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'reserves',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'router',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'adminFeeShareBP_', type: 'uint256' },
+ ],
+ name: 'setAdminFeeShare',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'balanceRatioMinBP_', type: 'uint256' },
+ ],
+ name: 'setBalanceRatioMinBP',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint16', name: 'feeShareBP_', type: 'uint16' }],
+ name: 'setFeeShare',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'router_', type: 'address' }],
+ name: 'setRouter',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'stopAuthority_', type: 'address' },
+ ],
+ name: 'setStopAuthority',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'startDeposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'startWithdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'stopDeposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'stopWithdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'receiveAmountMin', type: 'uint256' },
+ { internalType: 'bool', name: 'zeroFee', type: 'bool' },
+ ],
+ name: 'swapFromVUsd',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'bool', name: 'zeroFee', type: 'bool' },
+ ],
+ name: 'swapToVUsd',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'token',
+ outputs: [{ internalType: 'contract ERC20', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'tokenBalance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'userRewardDebt',
+ outputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'vUsdBalance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'amountLp', type: 'uint256' }],
+ name: 'withdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ { stateMutability: 'payable', type: 'receive' },
+] as const
diff --git a/src/apps/allbridge/api.ts b/src/apps/allbridge/api.ts
new file mode 100644
index 00000000..3d829bac
--- /dev/null
+++ b/src/apps/allbridge/api.ts
@@ -0,0 +1,121 @@
+import got from '../../utils/got'
+import { NetworkId } from '../../types/networkId'
+import { Address } from 'viem'
+import { LRUCache } from 'lru-cache'
+import { getConfig } from '../../config'
+
+type SupportedAllbridgeChainSymbols =
+ | 'ETH'
+ | 'CEL'
+ | 'POL'
+ | 'ARB'
+ | 'OPT'
+ | 'BAS'
+
+const NETWORK_ID_TO_ALLBRIDGE_BLOCKCHAIN_SYMBOL: Record<
+ NetworkId,
+ SupportedAllbridgeChainSymbols | undefined
+> = {
+ [NetworkId['ethereum-mainnet']]: 'ETH',
+ [NetworkId['ethereum-sepolia']]: undefined,
+ [NetworkId['celo-mainnet']]: 'CEL',
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['polygon-pos-mainnet']]: 'POL',
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['arbitrum-one']]: 'ARB',
+ [NetworkId['arbitrum-sepolia']]: undefined,
+ [NetworkId['op-mainnet']]: 'OPT',
+ [NetworkId['op-sepolia']]: undefined,
+ [NetworkId['base-mainnet']]: 'BAS',
+ [NetworkId['base-sepolia']]: undefined,
+}
+
+type AllbridgeApiResponse = {
+ [key in SupportedAllbridgeChainSymbols]: NetworkInfo
+}
+
+interface TokenInfo {
+ name: string
+ poolAddress: Address
+ tokenAddress: Address
+ decimals: number
+ symbol: string
+ poolInfo: PoolInfo
+ feeShare: string
+ apr: string
+ apr7d: string
+ apr30d: string
+ lpRate: string
+}
+
+interface PoolInfo {
+ aValue: string
+ dValue: string
+ tokenBalance: string
+ vUsdBalance: string
+ totalLpAmount: string
+ accRewardPerShareP: string
+ p: number
+}
+
+interface TransferTime {
+ allbridge: number
+ wormhole: number
+ cctp: number | null
+}
+
+interface TxCostAmount {
+ swap: string
+ transfer: string
+ maxAmount: string
+}
+
+interface NetworkInfo {
+ tokens: TokenInfo[]
+ chainId: number
+ bridgeAddress: Address
+ swapAddress: Address
+ transferTime: Record
+ confirmations: number
+ txCostAmount: TxCostAmount
+}
+
+const cache = new LRUCache({
+ max: 1,
+ // In milliseconds
+ ttl: 10 * 60 * 1000,
+})
+
+const TOKEN_INFO_RESPONSE_KEY =
+ 'https://core.api.allbridgecoreapi.net/token-info'
+
+export async function getAllbridgeTokenInfo({
+ networkId,
+}: {
+ networkId: NetworkId
+}): Promise {
+ let allbridgeTokensInfoResponse = cache.get(
+ TOKEN_INFO_RESPONSE_KEY,
+ ) as AllbridgeApiResponse
+ if (!allbridgeTokensInfoResponse) {
+ const headers: Record = {
+ 'x-Sdk-Agent': 'AllbridgeCoreSDK/3.21.0', // as in https://github.com/allbridge-io/allbridge-core-js-sdk/blob/5deb0623d6fffcbc7a85dba22b98942c47d4af6c/src/client/core-api/api-client.ts#L48
+ }
+
+ const allBridgeApiKey = getConfig().ALLBRIDGE_API_KEY
+ if (allBridgeApiKey) {
+ headers['valora-allbridge-core'] = allBridgeApiKey
+ }
+
+ allbridgeTokensInfoResponse = await got
+ .get('https://core.api.allbridgecoreapi.net/token-info', { headers })
+ .json()
+ cache.set(TOKEN_INFO_RESPONSE_KEY, allbridgeTokensInfoResponse)
+ }
+
+ const allbridgeBlockchain =
+ NETWORK_ID_TO_ALLBRIDGE_BLOCKCHAIN_SYMBOL[networkId]
+ return allbridgeBlockchain
+ ? allbridgeTokensInfoResponse[allbridgeBlockchain]
+ : undefined
+}
diff --git a/src/apps/allbridge/constants.ts b/src/apps/allbridge/constants.ts
new file mode 100644
index 00000000..ffb876ab
--- /dev/null
+++ b/src/apps/allbridge/constants.ts
@@ -0,0 +1,41 @@
+import { NetworkId } from '../../types/networkId'
+
+enum AllbridgeChain {
+ CEL = 'CEL',
+ ETH = 'ETH',
+ ARB = 'ARB',
+ OPT = 'OPT',
+ POL = 'POL',
+ BAS = 'BAS',
+}
+
+export const ALLBRIDGE_LOGO =
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/allbridgecore.png'
+
+export const ALLBRIDGE_POOLS_BASE_URL = 'https://core.allbridge.io/pools'
+
+export const NETWORK_ID_TO_ALLBRIDGE_CHAIN: Record<
+ NetworkId,
+ AllbridgeChain | undefined
+> = {
+ [NetworkId['celo-mainnet']]: AllbridgeChain.CEL,
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['ethereum-mainnet']]: AllbridgeChain.ETH,
+ [NetworkId['ethereum-sepolia']]: undefined,
+ [NetworkId['arbitrum-one']]: AllbridgeChain.ARB,
+ [NetworkId['arbitrum-sepolia']]: undefined,
+ [NetworkId['op-mainnet']]: AllbridgeChain.OPT,
+ [NetworkId['op-sepolia']]: undefined,
+ [NetworkId['polygon-pos-mainnet']]: AllbridgeChain.POL,
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['base-mainnet']]: AllbridgeChain.BAS,
+ [NetworkId['base-sepolia']]: undefined,
+}
+
+export const ALLBRIGE_CONTRACT_CREATED_AT: Record = {
+ [`${NetworkId['celo-mainnet']}:0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af`]:
+ '2024-05-08T09:09:55.000Z',
+}
+
+export const ALLBRIDGE_TERMS_URL =
+ 'https://allbridge.io/assets/docs/Allbridge%20-%20Terms%20and%20Conditions.pdf'
diff --git a/src/apps/allbridge/positions.e2e.ts b/src/apps/allbridge/positions.e2e.ts
new file mode 100644
index 00000000..6d89c796
--- /dev/null
+++ b/src/apps/allbridge/positions.e2e.ts
@@ -0,0 +1,24 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe.each([NetworkId['celo-mainnet']])(
+ 'getPositionDefinitions for networkId %s',
+ (networkId) => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should get definitions successfully when no address is provided', async () => {
+ const positions = await hook.getPositionDefinitions({ networkId, t })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+ },
+)
diff --git a/src/apps/allbridge/positions.ts b/src/apps/allbridge/positions.ts
new file mode 100644
index 00000000..9a0ee682
--- /dev/null
+++ b/src/apps/allbridge/positions.ts
@@ -0,0 +1,225 @@
+import {
+ PositionsHook,
+ AppTokenPositionDefinition,
+ UnknownAppTokenError,
+ TokenDefinition,
+ ContractPositionDefinition,
+ ClaimType,
+} from '../../types/positions'
+import { Address } from 'viem'
+import {
+ DecimalNumber,
+ toDecimalNumber,
+ toSerializedDecimalNumber,
+} from '../../types/numbers'
+import BigNumber from 'bignumber.js'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { getAllbridgeTokenInfo } from './api'
+import { poolAbi } from './abis/pool'
+import {
+ ALLBRIDGE_LOGO,
+ ALLBRIDGE_POOLS_BASE_URL,
+ ALLBRIDGE_TERMS_URL,
+ ALLBRIGE_CONTRACT_CREATED_AT,
+ NETWORK_ID_TO_ALLBRIDGE_CHAIN,
+} from './constants'
+import { getPositionId } from '../../runtime/getPositionId'
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Allbridge',
+ }
+ },
+ async getPositionDefinitions({ networkId, address, t }) {
+ const allbridgeTokenInfo = (await getAllbridgeTokenInfo({ networkId }))
+ ?.tokens
+ if (!allbridgeTokenInfo) {
+ return []
+ }
+
+ const client = getClient(networkId)
+
+ const [balances, rewards, totalSupplies, lpTokenDecimals] =
+ await Promise.all([
+ Promise.all(
+ allbridgeTokenInfo.map((tokenInfo) => {
+ return address
+ ? client.readContract({
+ address: tokenInfo.poolAddress,
+ abi: poolAbi,
+ functionName: 'balanceOf',
+ args: [address as Address],
+ })
+ : undefined
+ }),
+ ),
+ Promise.all(
+ allbridgeTokenInfo.map((tokenInfo) => {
+ return address
+ ? client.readContract({
+ address: tokenInfo.poolAddress,
+ abi: poolAbi,
+ functionName: 'pendingReward',
+ args: [address as Address],
+ })
+ : undefined
+ }),
+ ),
+ Promise.all(
+ allbridgeTokenInfo.map((tokenInfo) => {
+ return client.readContract({
+ address: tokenInfo.poolAddress,
+ abi: poolAbi,
+ functionName: 'totalSupply',
+ args: [],
+ })
+ }),
+ ),
+ Promise.all(
+ allbridgeTokenInfo.map((tokenInfo) => {
+ return client.readContract({
+ address: tokenInfo.poolAddress,
+ abi: poolAbi,
+ functionName: 'decimals',
+ args: [],
+ })
+ }),
+ ),
+ ])
+
+ return allbridgeTokenInfo.flatMap((tokenInfo, i) => {
+ const apr = new BigNumber(tokenInfo.apr7d).toNumber() * 100
+ const manageUrl = `${ALLBRIDGE_POOLS_BASE_URL}?chain=${NETWORK_ID_TO_ALLBRIDGE_CHAIN[networkId]}`
+
+ const balanceOf = balances[i]
+ const pendingReward = rewards[i]
+
+ const showLpToken = !address || (!!balanceOf && balanceOf > 0)
+ const showReward = !!pendingReward && pendingReward > 0
+
+ const rewardPositionDefinition =
+ showReward &&
+ ({
+ type: 'contract-position-definition',
+ networkId,
+ address: tokenInfo.poolAddress.toLowerCase(),
+ extraId: 'supply-incentives',
+ tokens: [
+ {
+ address: tokenInfo.tokenAddress.toLowerCase(),
+ networkId,
+ category: 'claimable',
+ },
+ ],
+ availableShortcutIds: ['claim-rewards'],
+ shortcutTriggerArgs: {
+ 'claim-rewards': {
+ positionAddress: tokenInfo.poolAddress.toLowerCase(),
+ },
+ },
+ balances: [toDecimalNumber(pendingReward, tokenInfo.decimals)],
+ displayProps: {
+ title: `${tokenInfo.symbol} supply incentives`,
+ description: 'Rewards for supplying',
+ imageUrl: ALLBRIDGE_LOGO,
+ manageUrl,
+ },
+ } satisfies ContractPositionDefinition)
+
+ return [
+ showLpToken &&
+ ({
+ type: 'app-token-definition',
+ networkId,
+ address: tokenInfo.poolAddress.toLowerCase(),
+ tokens: [
+ { address: tokenInfo.tokenAddress.toLowerCase(), networkId },
+ ],
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: {
+ deposit: {
+ tokenAddress: tokenInfo.tokenAddress.toLowerCase(),
+ tokenDecimals: tokenInfo.decimals,
+ positionAddress: tokenInfo.poolAddress.toLowerCase(),
+ },
+ withdraw: {
+ tokenDecimals: lpTokenDecimals[i],
+ positionAddress: tokenInfo.poolAddress.toLowerCase(),
+ },
+ 'swap-deposit': {
+ tokenAddress: tokenInfo.tokenAddress.toLowerCase(),
+ positionAddress: tokenInfo.poolAddress.toLowerCase(),
+ },
+ },
+ displayProps: {
+ title: tokenInfo.symbol,
+ description: `Supplied (APR: ${apr.toFixed(2)}%)`,
+ imageUrl: ALLBRIDGE_LOGO,
+ manageUrl,
+ },
+ dataProps: {
+ manageUrl,
+ claimType: ClaimType.Earnings,
+ withdrawalIncludesClaim: true,
+ termsUrl: ALLBRIDGE_TERMS_URL,
+ contractCreatedAt:
+ ALLBRIGE_CONTRACT_CREATED_AT[
+ getTokenId({
+ networkId,
+ address: tokenInfo.poolAddress.toLowerCase(),
+ })
+ ],
+ tvl: toSerializedDecimalNumber(
+ toDecimalNumber(totalSupplies[i], lpTokenDecimals[i]),
+ ),
+ yieldRates: [
+ {
+ percentage: apr,
+ label: t('yieldRates.earningsApr'),
+ tokenId: getTokenId({
+ networkId,
+ address: tokenInfo.tokenAddress.toLowerCase(),
+ }),
+ },
+ ],
+ earningItems: pendingReward
+ ? [
+ {
+ amount: toDecimalNumber(
+ pendingReward,
+ tokenInfo.decimals,
+ ),
+ label: t('earningItems.earnings'),
+ tokenId: getTokenId({
+ networkId,
+ address: tokenInfo.tokenAddress.toLowerCase(),
+ }),
+ },
+ ]
+ : [],
+ depositTokenId: getTokenId({
+ networkId,
+ address: tokenInfo.tokenAddress.toLowerCase(),
+ }),
+ withdrawTokenId: getTokenId({
+ networkId,
+ address: tokenInfo.poolAddress.toLowerCase(),
+ }),
+ rewardsPositionIds: rewardPositionDefinition
+ ? [getPositionId(rewardPositionDefinition)]
+ : [],
+ },
+ pricePerShare: [new BigNumber(1) as DecimalNumber],
+ } satisfies AppTokenPositionDefinition),
+ rewardPositionDefinition,
+ ].filter((x) => !!x)
+ })
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/allbridge/shortcuts.e2e.ts b/src/apps/allbridge/shortcuts.e2e.ts
new file mode 100644
index 00000000..487286f9
--- /dev/null
+++ b/src/apps/allbridge/shortcuts.e2e.ts
@@ -0,0 +1,119 @@
+import hook from './shortcuts'
+import { NetworkId } from '../../types/networkId'
+import { ShortcutDefinition } from '../../types/shortcuts'
+
+describe('getShortcutDefinitions', () => {
+ it('should get the definitions successfully', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ expect(shortcuts.length).toBeGreaterThan(0)
+ expect(shortcuts[0].id).toBe('deposit')
+ })
+
+ describe('deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'deposit')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC
+ tokenDecimals: 6,
+ positionAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0xaf88d065e77c8cc2239327c5edb3a432268e5831`,
+ amount: '10',
+ },
+ ],
+ })
+
+ expect(transactions.length).toEqual(2)
+ })
+ })
+
+ describe('withdraw.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'withdraw')
+ expect(shortcut).toBeDefined()
+ expect(shortcuts[1].id).toBe('withdraw')
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0x724dc807b04555b71ed48a6896b6f41593b8c637`,
+ amount: '1',
+ },
+ ],
+ positionAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ tokenDecimals: 3,
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+
+ describe('claim-rewards.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find(
+ (shortcut) => shortcut.id === 'claim-rewards',
+ )
+ expect(shortcut).toBeDefined()
+ expect(shortcuts[2].id).toBe('claim-rewards')
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ positionAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+
+ describe('swap-deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['celo-mainnet'],
+ )
+ const shortcut = shortcuts.find(
+ (shortcut) => shortcut.id === 'swap-deposit',
+ )
+ expect(shortcut).toBeDefined()
+ expect(shortcut!.category).toEqual('swap-deposit')
+
+ const { transactions, dataProps } = await (
+ shortcut as ShortcutDefinition<'swap-deposit', any>
+ ).onTrigger({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0x617f3112bf5397d0467d315cc709ef968d9ba546', // USDT
+ positionAddress: '0xfb2c7c10e731ebe96dabdf4a96d656bfe8e2b5af',
+ swapFromToken: {
+ tokenId: 'celo-mainnet:0x765de816845861e75a25fca122bb6898b8b1282a', // CUSD
+ amount: '1',
+ decimals: 18,
+ address: '0x765de816845861e75a25fca122bb6898b8b1282a',
+ isNative: false,
+ },
+ })
+
+ expect(transactions.length).toEqual(2)
+ expect(dataProps).toBeDefined()
+ expect(dataProps.swapTransaction).toBeDefined()
+ })
+ })
+})
diff --git a/src/apps/allbridge/shortcuts.ts b/src/apps/allbridge/shortcuts.ts
new file mode 100644
index 00000000..4ec0a8c0
--- /dev/null
+++ b/src/apps/allbridge/shortcuts.ts
@@ -0,0 +1,269 @@
+import { Address, encodeFunctionData, erc20Abi, parseUnits } from 'viem'
+import { z } from 'zod'
+import { getClient } from '../../runtime/client'
+import { ZodAddressLowerCased } from '../../types/address'
+import { NetworkId } from '../../types/networkId'
+import {
+ createShortcut,
+ ShortcutsHook,
+ tokenAmounts,
+ tokenAmountWithMetadata,
+ ZodEnableAppFee,
+ Transaction,
+} from '../../types/shortcuts'
+import { poolAbi } from './abis/pool'
+import {
+ UnsupportedSimulateRequest,
+ simulateTransactions,
+} from '../../runtime/simulateTransactions'
+import { logger } from '../../log'
+import { prepareSwapTransactions } from '../../utils/prepareSwapTransactions'
+import { ChainType, SquidCallType } from '@0xsquid/squid-types'
+
+// Hardcoded fallback if simulation isn't enabled
+const DEFAULT_DEPOSIT_GAS = 500_000n
+// Padding we add to simulation gas to ensure we specify enough
+const SIMULATED_DEPOSIT_GAS_PADDING = 250_000n
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId) {
+ return [
+ createShortcut({
+ id: 'deposit',
+ name: 'Deposit',
+ description: 'Lend your assets to earn interest',
+ networkIds: [networkId],
+ category: 'deposit',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ positionAddress: ZodAddressLowerCased,
+ // these two will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ tokenAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ // amount in smallest unit
+ const amountToSupply = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const client = getClient(networkId)
+
+ const approvedAllowanceForSpender = await client.readContract({
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'allowance',
+ args: [walletAddress, positionAddress],
+ })
+
+ if (approvedAllowanceForSpender < amountToSupply) {
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [positionAddress, amountToSupply],
+ })
+
+ const approveTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: tokenAddress,
+ data,
+ }
+ transactions.push(approveTx)
+ }
+
+ const supplyTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: poolAbi,
+ functionName: 'deposit',
+ args: [amountToSupply],
+ }),
+ }
+
+ transactions.push(supplyTx)
+
+ // TODO: consider moving this concern to the runtime
+ try {
+ const simulatedTransactions = await simulateTransactions({
+ transactions,
+ networkId,
+ })
+ const supplySimulatedTx =
+ simulatedTransactions[simulatedTransactions.length - 1]
+
+ supplyTx.gas =
+ BigInt(supplySimulatedTx.gasNeeded) +
+ SIMULATED_DEPOSIT_GAS_PADDING
+ supplyTx.estimatedGasUse = BigInt(supplySimulatedTx.gasUsed)
+ } catch (error) {
+ if (!(error instanceof UnsupportedSimulateRequest)) {
+ logger.warn(error, 'Unexpected error during simulateTransactions')
+ }
+ supplyTx.gas = DEFAULT_DEPOSIT_GAS
+ supplyTx.estimatedGasUse = DEFAULT_DEPOSIT_GAS / 3n
+ }
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'withdraw',
+ name: 'Withdraw',
+ description: 'Withdraw your assets',
+ networkIds: [networkId],
+ category: 'withdraw',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ positionAddress: ZodAddressLowerCased,
+ // this will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ tokenDecimals: z.coerce.number(),
+ },
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ const amountToWithdraw = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const withdrawTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: poolAbi,
+ functionName: 'withdraw',
+ args: [amountToWithdraw],
+ }),
+ }
+
+ transactions.push(withdrawTx)
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'claim-rewards',
+ name: 'Claim',
+ description: 'Claim rewards',
+ networkIds: [networkId],
+ category: 'claim',
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address, positionAddress }) {
+ const walletAddress = address as Address
+
+ const claimTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: poolAbi,
+ functionName: 'claimRewards',
+ args: [],
+ }),
+ }
+
+ return { transactions: [claimTx] }
+ },
+ }),
+ createShortcut({
+ id: 'swap-deposit',
+ name: 'Swap & Deposit',
+ description: 'Swap assets and lend them to earn interest',
+ networkIds: [networkId],
+ category: 'swap-deposit',
+ triggerInputShape: {
+ swapFromToken: tokenAmountWithMetadata,
+ enableAppFee: ZodEnableAppFee,
+ // set via shortcutTriggerArgs, the deposit token and position addresses
+ tokenAddress: ZodAddressLowerCased,
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({
+ swapFromToken,
+ tokenAddress,
+ address,
+ positionAddress,
+ networkId,
+ enableAppFee,
+ }) {
+ const walletAddress = address as Address
+ // use a placeholder non zero amount so tx simulation can succeed.
+ // squid postHook will replace this with the actual amount after swap.
+ const amount = 1n
+ const approveData = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [positionAddress, amount],
+ })
+ const supplyData = encodeFunctionData({
+ abi: poolAbi,
+ functionName: 'deposit',
+ args: [amount],
+ })
+
+ return await prepareSwapTransactions({
+ networkId,
+ swapFromToken,
+ swapToTokenAddress: tokenAddress,
+ walletAddress,
+ enableAppFee,
+ // based off of https://docs.squidrouter.com/building-with-squid-v2/key-concepts/hooks/build-a-posthook
+ postHook: {
+ chainType: ChainType.EVM,
+ calls: [
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: tokenAddress,
+ callData: approveData,
+ payload: {
+ tokenAddress,
+ inputPos: 1,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_DEPOSIT_GAS.toString(),
+ },
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: positionAddress,
+ callData: supplyData,
+ payload: {
+ tokenAddress,
+ inputPos: 0,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_DEPOSIT_GAS.toString(),
+ },
+ ],
+ description: 'Deposit into allbridge pool',
+ },
+ })
+ },
+ }),
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/beefy/abis/BeefyClmVaults.sol b/src/apps/beefy/abis/BeefyClmVaults.sol
new file mode 100644
index 00000000..b398c7f2
--- /dev/null
+++ b/src/apps/beefy/abis/BeefyClmVaults.sol
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.2;
+
+interface ClmVault {
+ function balanceOf(address owner) external view returns (uint256);
+
+ function balances() external view returns (uint256, uint256);
+
+ function totalSupply() external view returns (uint256);
+
+ function wants() external view returns (address, address);
+}
+
+interface ClmPool {
+ function balanceOf(address owner) external view returns (uint256);
+
+ function totalSupply() external view returns (uint256);
+}
+
+contract BeefyClmVaults {
+ struct VaultInfo {
+ address token0;
+ address token1;
+ uint256 amount0;
+ uint256 amount1;
+ }
+
+ function getUserVaults(
+ address owner,
+ address[] memory vaults
+ ) external view returns (VaultInfo[] memory userVaults) {
+ userVaults = new VaultInfo[](vaults.length);
+
+ for (uint16 index = 0; index < vaults.length; index++) {
+ ClmVault vault = ClmVault(vaults[index]);
+ (address token0, address token1) = vault.wants();
+
+ (uint256 amount0, uint256 amount1) = vault.balances();
+ uint256 supply = vault.totalSupply();
+ uint256 balance = vault.balanceOf(owner);
+
+ userVaults[index] = VaultInfo(
+ token0,
+ token1,
+ (balance * amount0) / supply,
+ (balance * amount1) / supply
+ );
+ }
+ }
+
+ function getUserClmPools(
+ address owner,
+ address[] memory vaults,
+ address[] memory pools
+ ) external view returns (VaultInfo[] memory userVaults) {
+ userVaults = new VaultInfo[](vaults.length);
+
+ for (uint16 index = 0; index < vaults.length; index++) {
+ ClmVault vault = ClmVault(vaults[index]);
+ ClmPool pool = ClmPool(pools[index]);
+ (address token0, address token1) = vault.wants();
+ (uint256 amount0, uint256 amount1) = vault.balances();
+ uint256 vaultSupply = vault.totalSupply();
+ uint256 vaultBalance = vault.balanceOf(pools[index]);
+
+ uint256 poolSupply = pool.totalSupply();
+ uint256 poolBalance = pool.balanceOf(owner);
+
+ uint256 poolAmount0 = (vaultBalance * amount0) / vaultSupply;
+ uint256 poolAmount1 = (vaultBalance * amount1) / vaultSupply;
+
+ userVaults[index] = VaultInfo(
+ token0,
+ token1,
+ (poolBalance * poolAmount0) / poolSupply,
+ (poolBalance * poolAmount1) / poolSupply
+ );
+ }
+ }
+}
diff --git a/src/apps/beefy/abis/beefy-clm-vaults-multicall.ts b/src/apps/beefy/abis/beefy-clm-vaults-multicall.ts
new file mode 100644
index 00000000..959b4286
--- /dev/null
+++ b/src/apps/beefy/abis/beefy-clm-vaults-multicall.ts
@@ -0,0 +1,101 @@
+export const beefyClmVaultsMulticallBytecode =
+ '0x6080806040523461001657610d2f908161001c8239f35b600080fdfe60806040526004361015610013575b600080fd5b60003560e01c8063714bf8511461003b5763ce6b81021461003357600080fd5b61000e6107cb565b3461000e576060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57610076600435610608565b67ffffffffffffffff60243581811161000e576100979036906004016106eb565b9060443590811161000e576100b09036906004016106eb565b916100bb8251610aee565b9260005b835161ffff821610156105f657806101176100fe6100e461ffff610432951688610be6565b5173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b61012b6100fe6100e461ffff851687610be6565b90604051917f6584493400000000000000000000000000000000000000000000000000000000835260408360048173ffffffffffffffffffffffffffffffffffffffff86165afa9182156105e9575b6000936000936105b2575b50604051907f7bb98a6800000000000000000000000000000000000000000000000000000000825260408260048173ffffffffffffffffffffffffffffffffffffffff85165afa9283156105a5575b60009260009461055a575b509073ffffffffffffffffffffffffffffffffffffffff91604051917f18160ddd0000000000000000000000000000000000000000000000000000000083528a896020856004818987165afa94851561054d575b600095610517575b50916102546100e46102a69361ffff6020961690610be6565b6040519687809481937f70a082310000000000000000000000000000000000000000000000000000000083526004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b0392165afa92831561050a575b6000936104d3575b5073ffffffffffffffffffffffffffffffffffffffff1693604051937f18160ddd000000000000000000000000000000000000000000000000000000008552602085600481895afa9485156104c6575b6000956104a5575b50602060405180977f70a08231000000000000000000000000000000000000000000000000000000008252818061036c6004356004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa958615610498575b600096610437575b50926103bb856103a96103b4866103a96103a9976103ae6104069c9a6103a96103c19d8b610c83565b610cc0565b97610c83565b9389610c83565b95610c83565b926103e96103cd6106a4565b73ffffffffffffffffffffffffffffffffffffffff9096168652565b73ffffffffffffffffffffffffffffffffffffffff166020850152565b60408301528582015261041d61ffff831688610be6565b5261042c61ffff821687610be6565b50610bc6565b6100bf565b6103c194919650856103a96103b4866103a96103a9976103ae6104069c9a6103a961047c6103bb9a60203d602011610491575b6104748183610656565b810190610c74565b9f9a9d50505050975050965050509550610380565b503d61046a565b6104a0610c51565b610378565b6104bf91955060203d602011610491576104748183610656565b938e610313565b6104ce610c51565b61030b565b73ffffffffffffffffffffffffffffffffffffffff9193506105039060203d602011610491576104748183610656565b92906102bb565b610512610c51565b6102b3565b6020939195506100e46102a69361ffff61054061025494883d8a11610491576104748183610656565b989496505093505061023b565b610555610c51565b610233565b61059591945073ffffffffffffffffffffffffffffffffffffffff92935060403d60401161059e575b61058d8183610656565b810190610c5e565b939092916101df565b503d610583565b6105ad610c51565b6101d4565b9092506105d891935060403d6040116105e2575b6105d08183610656565b810190610c29565b929092918a610185565b503d6105c6565b6105f1610c51565b61017a565b604051806106048782610753565b0390f35b73ffffffffffffffffffffffffffffffffffffffff81160361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761069757604052565b61069f610626565b604052565b604051906080820182811067ffffffffffffffff82111761069757604052565b60209067ffffffffffffffff81116106de575b60051b0190565b6106e6610626565b6106d7565b81601f8201121561000e57803591610702836106c4565b926107106040519485610656565b808452602092838086019260051b82010192831161000e578301905b82821061073a575050505090565b838091833561074881610608565b81520191019061072c565b60208082019080835283518092528060408094019401926000905b83821061077d57505050505090565b8451805173ffffffffffffffffffffffffffffffffffffffff90811688528185015116878501528082015187830152606090810151908701526080909501949382019360019091019061076e565b503461000e576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576004803561080981610608565b60243567ffffffffffffffff811161000e5761082890369084016106eb565b906108338251610aee565b9060005b835161ffff821690811015610ae1579061042c826108616100fe6100fe6100e4610a0c978b610be6565b888a8051927f6584493400000000000000000000000000000000000000000000000000000000845281848481845afa8015610ad4575b6000948591610ab1575b508251917f7bb98a6800000000000000000000000000000000000000000000000000000000835283838681845afa8015610aa4575b6000938491610a81575b50848c610978959651937f18160ddd000000000000000000000000000000000000000000000000000000008552602098899384878381865afa968715610a74575b600097610a55575b50518098819482937f70a08231000000000000000000000000000000000000000000000000000000008452830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa938415610a48575b600094610a11575b50906103a96109ad926109a7836103a988996109f299610c83565b96610c83565b936109d56109b96106a4565b73ffffffffffffffffffffffffffffffffffffffff9097168752565b85019073ffffffffffffffffffffffffffffffffffffffff169052565b8b8301526060820152610a058288610be6565b5285610be6565b610837565b6109f2945082916109a76109ad946103a9610a3b6103a9958c8d3d10610491576104748183610656565b985050505091925061098c565b610a50610c51565b610984565b610a6d919750853d8711610491576104748183610656565b9538610929565b610a7c610c51565b610921565b6109789450610a9d9150853d871161059e5761058d8183610656565b90936108e0565b610aac610c51565b6108d6565b9050610acb919450823d84116105e2576105d08183610656565b939093386108a1565b610adc610c51565b610897565b8651806106048682610753565b90610af8826106c4565b604090610b0782519182610656565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610b3582956106c4565b019160005b838110610b475750505050565b60209082516080810181811067ffffffffffffffff821117610b89575b8452600081528260008183015260008583015260006060830152828601015201610b3a565b610b91610626565b610b64565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60019061ffff809116908114610bda570190565b610be2610b96565b0190565b8051821015610bfa5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919082604091031261000e5760208251610c4281610608565b920151610c4e81610608565b90565b506040513d6000823e3d90fd5b919082604091031261000e576020825192015190565b9081602091031261000e575190565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821181151516610cb4570290565b610cbc610b96565b0290565b8115610cca570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220c29f1220efb3fa2ba5f9cc27788712b17cfee44bf986ac0c17f49f9ed23f6fff64736f6c634300080d0033'
+export const beefyClmVaultsMulticallAbi = [
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address[]',
+ name: 'vaults',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address[]',
+ name: 'pools',
+ type: 'address[]',
+ },
+ ],
+ name: 'getUserClmPools',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'token0',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token1',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount0',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount1',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct BeefyClmVaults.VaultInfo[]',
+ name: 'userVaults',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address[]',
+ name: 'vaults',
+ type: 'address[]',
+ },
+ ],
+ name: 'getUserVaults',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'token0',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token1',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount0',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount1',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct BeefyClmVaults.VaultInfo[]',
+ name: 'userVaults',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/beefy/abis/beefy-v2-app-multicall.ts b/src/apps/beefy/abis/beefy-v2-app-multicall.ts
new file mode 100644
index 00000000..4c9abf49
--- /dev/null
+++ b/src/apps/beefy/abis/beefy-v2-app-multicall.ts
@@ -0,0 +1,353 @@
+export const beefyV2AppMulticallAbi = [
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'tokens',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address[][]',
+ name: 'spenders',
+ type: 'address[][]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getAllowances',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256[]',
+ name: 'allowances',
+ type: 'uint256[]',
+ },
+ ],
+ internalType: 'struct AllowanceInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'tokens',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address[][]',
+ name: 'spenders',
+ type: 'address[][]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getAllowancesFlat',
+ outputs: [
+ {
+ internalType: 'uint256[]',
+ name: '',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'boosts',
+ type: 'address[]',
+ },
+ ],
+ name: 'getBoostInfo',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'totalSupply',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'rewardRate',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'periodFinish',
+ type: 'uint256',
+ },
+ {
+ internalType: 'bool',
+ name: 'isPreStake',
+ type: 'bool',
+ },
+ ],
+ internalType: 'struct BoostInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'boosts',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getBoostOrGovBalance',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'rewards',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct BoostBalanceInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'vaults',
+ type: 'address[]',
+ },
+ ],
+ name: 'getCowVaultInfo',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'token0Balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'token1Balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'strategy',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'paused',
+ type: 'bool',
+ },
+ ],
+ internalType: 'struct CowVaultInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'govVaults',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getGovVaultBalance',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'rewards',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct GovVaultBalanceInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'govVaults',
+ type: 'address[]',
+ },
+ ],
+ name: 'getGovVaultInfo',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'totalSupply',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct GovVaultInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'vaults',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getGovVaultMultiBalance',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address[]',
+ name: 'rewardTokens',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'rewards',
+ type: 'uint256[]',
+ },
+ ],
+ internalType: 'struct BoostBalanceInfoV2[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'tokens',
+ type: 'address[]',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getTokenBalances',
+ outputs: [
+ {
+ internalType: 'uint256[]',
+ name: '',
+ type: 'uint256[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address[]',
+ name: 'vaults',
+ type: 'address[]',
+ },
+ ],
+ name: 'getVaultInfo',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint256',
+ name: 'balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'pricePerFullShare',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'strategy',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'paused',
+ type: 'bool',
+ },
+ ],
+ internalType: 'struct VaultInfo[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/beefy/abis/vault.ts b/src/apps/beefy/abis/vault.ts
new file mode 100644
index 00000000..8752d99d
--- /dev/null
+++ b/src/apps/beefy/abis/vault.ts
@@ -0,0 +1,342 @@
+export const vaultAbi = [
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: false, internalType: 'uint8', name: 'version', type: 'uint8' },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'implementation',
+ type: 'address',
+ },
+ ],
+ name: 'NewStratCandidate',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'previousOwner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'implementation',
+ type: 'address',
+ },
+ ],
+ name: 'UpgradeStrat',
+ type: 'event',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'approvalDelay',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'available',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'balance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
+ ],
+ name: 'decreaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }],
+ name: 'deposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'depositAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'earn',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getPricePerFullShare',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_token', type: 'address' }],
+ name: 'inCaseTokensGetStuck',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
+ ],
+ name: 'increaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IStrategyV7',
+ name: '_strategy',
+ type: 'address',
+ },
+ { internalType: 'string', name: '_name', type: 'string' },
+ { internalType: 'string', name: '_symbol', type: 'string' },
+ { internalType: 'uint256', name: '_approvalDelay', type: 'uint256' },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_implementation', type: 'address' },
+ ],
+ name: 'proposeStrat',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'renounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'stratCandidate',
+ outputs: [
+ { internalType: 'address', name: 'implementation', type: 'address' },
+ { internalType: 'uint256', name: 'proposedTime', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'strategy',
+ outputs: [
+ { internalType: 'contract IStrategyV7', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'upgradeStrat',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'want',
+ outputs: [
+ { internalType: 'contract IERC20Upgradeable', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '_shares', type: 'uint256' }],
+ name: 'withdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'withdrawAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/beefy/api.ts b/src/apps/beefy/api.ts
new file mode 100644
index 00000000..6fe05e0e
--- /dev/null
+++ b/src/apps/beefy/api.ts
@@ -0,0 +1,154 @@
+import got from '../../utils/got'
+import { Address } from 'viem'
+import { NetworkId } from '../../types/networkId'
+
+export type BeefyVault = {
+ id: string
+ name: string
+ type: string // cowcentrated, gov
+ subType?: string
+ token: string
+ tokenAddress: Address | undefined
+ tokenDecimals: number
+ tokenProviderId: string
+ earnedToken: string
+ earnContractAddress: Address
+ status: string
+ platformId: string
+ assets: string[]
+ risks: string[]
+ strategyTypeId: string
+ network: string
+ chain: string
+ zaps: any[]
+ isGovVault: boolean
+ oracle: string
+ oracleId: string
+ createdAt: number
+}
+
+export type BaseBeefyVault = BeefyVault & {
+ earnedTokenAddress: Address
+ depositTokenAddresses: string[]
+ strategy: Address
+ pricePerFullShare: string
+}
+
+export type GovVault = BeefyVault & {
+ type: 'gov'
+ isGovVault: true
+ earnedTokenAddress: Address[]
+}
+
+export const NETWORK_ID_TO_BEEFY_BLOCKCHAIN_ID: Record<
+ NetworkId,
+ string | null
+> = {
+ [NetworkId['celo-mainnet']]: 'celo',
+ [NetworkId['ethereum-mainnet']]: 'ethereum',
+ [NetworkId['arbitrum-one']]: 'arbitrum',
+ [NetworkId['op-mainnet']]: 'optimism',
+ [NetworkId['polygon-pos-mainnet']]: 'polygon',
+ [NetworkId['base-mainnet']]: 'base',
+ [NetworkId['celo-alfajores']]: null,
+ [NetworkId['ethereum-sepolia']]: null,
+ [NetworkId['arbitrum-sepolia']]: null,
+ [NetworkId['op-sepolia']]: null,
+ [NetworkId['polygon-pos-amoy']]: null,
+ [NetworkId['base-sepolia']]: null,
+}
+
+const NETWORK_ID_TO_CHAIN_ID: {
+ [networkId in NetworkId]: number
+} = {
+ [NetworkId['ethereum-mainnet']]: 1,
+ [NetworkId['arbitrum-one']]: 42161,
+ [NetworkId['op-mainnet']]: 10,
+ [NetworkId['celo-mainnet']]: 42220,
+ [NetworkId['polygon-pos-mainnet']]: 137,
+ [NetworkId['base-mainnet']]: 8453,
+ [NetworkId['ethereum-sepolia']]: 11155111,
+ [NetworkId['arbitrum-sepolia']]: 421614,
+ [NetworkId['op-sepolia']]: 11155420,
+ [NetworkId['celo-alfajores']]: 44787,
+ [NetworkId['polygon-pos-amoy']]: 80002,
+ [NetworkId['base-sepolia']]: 84532,
+}
+
+export async function getBeefyVaults(
+ networkId: NetworkId,
+): Promise<{ vaults: BaseBeefyVault[]; govVaults: GovVault[] }> {
+ const [vaults, govVaults] = await Promise.all([
+ got
+ .get(
+ `https://api.beefy.finance/harvestable-vaults/${NETWORK_ID_TO_BEEFY_BLOCKCHAIN_ID[networkId]}`,
+ )
+ .json(),
+ got
+ .get(
+ `https://api.beefy.finance/gov-vaults/${NETWORK_ID_TO_BEEFY_BLOCKCHAIN_ID[networkId]}`,
+ )
+ .json(),
+ ])
+
+ return {
+ vaults,
+ govVaults,
+ }
+}
+
+export async function getBeefyPrices(
+ networkId: NetworkId,
+): Promise> {
+ const [lpsPrices, tokenPrices, tokens] = await Promise.all([
+ got
+ .get(`https://api.beefy.finance/lps`)
+ .json>(),
+ got
+ .get(`https://api.beefy.finance/prices`)
+ .json>(),
+ got
+ .get(
+ `https://api.beefy.finance/tokens/${NETWORK_ID_TO_BEEFY_BLOCKCHAIN_ID[networkId]}`,
+ )
+ .json<
+ Record<
+ string, // oracleId
+ {
+ // These are the fields we need, but there are more
+ address: string
+ oracle: string // examples: 'lps', 'tokens'
+ oracleId: string
+ }
+ >
+ >(),
+ ])
+
+ // Combine lps prices with token prices
+ return {
+ ...lpsPrices,
+ ...Object.fromEntries(
+ Object.entries(tokens)
+ .filter(([, { oracle }]) => oracle === 'tokens')
+ .map(([, { address, oracleId }]) => [
+ address.toLowerCase(),
+ tokenPrices[oracleId],
+ ]),
+ ),
+ }
+}
+
+export async function getApyBreakdown() {
+ return got
+ .get(`https://api.beefy.finance/apy/breakdown/`)
+ .json | undefined>>()
+}
+
+export async function getTvls(
+ networkId: NetworkId,
+): Promise> {
+ const tvlResponse = await got
+ .get(`https://api.beefy.finance/tvl/`)
+ .json>>()
+ return tvlResponse[NETWORK_ID_TO_CHAIN_ID[networkId]] ?? {}
+}
diff --git a/src/apps/beefy/positions.e2e.ts b/src/apps/beefy/positions.e2e.ts
new file mode 100644
index 00000000..228c8706
--- /dev/null
+++ b/src/apps/beefy/positions.e2e.ts
@@ -0,0 +1,53 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { getBaseTokensInfo, getPositions } from '../../runtime/getPositions'
+import { t } from '../../../test/i18next'
+import { TokensInfo } from '../../types/positions'
+import { getConfig } from '../../config'
+
+describe('getPositionDefinitions', () => {
+ let baseTokensInfo: TokensInfo = {}
+ beforeAll(async () => {
+ baseTokensInfo = await getBaseTokensInfo(getConfig().GET_TOKENS_INFO_URL)
+ })
+
+ it('should get the address definitions successfully', async () => {
+ const positions = await getPositions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['beefy'],
+ t,
+ baseTokensInfo,
+ })
+
+ expect(
+ positions.filter((p) => p.type === 'app-token').length,
+ ).toBeGreaterThan(0)
+ expect(
+ positions.filter((p) => p.type === 'contract-position').length,
+ ).toBeGreaterThan(0)
+ })
+
+ it('should get no definitions for an address with no blockchain interaction', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
+ expect(positions.length).toBe(0)
+ })
+
+ it('should get app token definitions when address is not set', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['op-mainnet'],
+ t,
+ })
+
+ expect(
+ positions.filter((p) => p.type === 'app-token-definition').length,
+ ).toBeGreaterThan(0)
+ expect(
+ positions.filter((p) => p.type === 'contract-position-definition').length,
+ ).toBe(0)
+ })
+})
diff --git a/src/apps/beefy/positions.test.ts b/src/apps/beefy/positions.test.ts
new file mode 100644
index 00000000..e920a38b
--- /dev/null
+++ b/src/apps/beefy/positions.test.ts
@@ -0,0 +1,277 @@
+import { TFunction } from 'i18next'
+import {
+ BaseBeefyVault,
+ getApyBreakdown,
+ getBeefyPrices,
+ getBeefyVaults,
+ getTvls,
+} from './api'
+import hook, { getDailyYieldRatePercentage } from './positions'
+import { NetworkId } from '../../types/networkId'
+import { Address } from 'viem'
+import { AppTokenPositionDefinition } from '../../types/positions'
+import BigNumber from 'bignumber.js'
+
+const mockT = ((x: string) => x) as TFunction
+
+const mockReadContract = jest.fn()
+jest.mock('../../runtime/client', () => ({
+ getClient: jest.fn(() => ({
+ readContract: mockReadContract,
+ })),
+}))
+
+jest.mock('./api.ts')
+
+const mockBeefyVault: BaseBeefyVault = {
+ id: 'defaultVault',
+ name: 'Default Vault',
+ type: 'auto',
+ subType: 'concentrated',
+ token: 'vaultToken',
+ tokenAddress: '0x123456789' as Address,
+ tokenDecimals: 8,
+ tokenProviderId: '',
+ earnedToken: '',
+ earnContractAddress: '' as Address,
+ status: '',
+ platformId: '',
+ assets: [],
+ risks: [],
+ strategyTypeId: '',
+ network: 'arbitrum-one',
+ chain: '',
+ zaps: [],
+ isGovVault: false,
+ oracle: '',
+ oracleId: '',
+ createdAt: 12345,
+ earnedTokenAddress: '0x987654321' as Address,
+ depositTokenAddresses: [],
+ strategy: '' as Address,
+ pricePerFullShare: '120000000',
+}
+
+const mockBeefyVault1: BaseBeefyVault = {
+ ...mockBeefyVault,
+ id: 'vault1',
+ name: 'Vault 1',
+}
+
+const mockBeefyVault2: BaseBeefyVault = {
+ ...mockBeefyVault,
+ id: 'vault2',
+ name: 'Vault 2',
+ tokenAddress: '0x111111111' as Address,
+ createdAt: 135790,
+ earnedTokenAddress: '0x999999999' as Address,
+ pricePerFullShare: '1e+5',
+}
+
+const mockBeefyVaults = {
+ vaults: [mockBeefyVault1, mockBeefyVault2],
+ govVaults: [],
+}
+const mockBeefyPrices = { vault1: 1.2, vault2: 1000 }
+const mockApyBreakdown = {
+ vault1: { totalApy: 0.31 },
+ vault2: { totalApy: 0.06 },
+}
+const mockTvls = { vault1: 98765, vault2: 1234567890 }
+const mockGetTokenBalancesResponse: readonly bigint[] = [0n, 10n]
+
+jest.mocked(getBeefyVaults).mockResolvedValue(mockBeefyVaults)
+jest.mocked(getBeefyPrices).mockResolvedValue(mockBeefyPrices)
+jest.mocked(getApyBreakdown).mockResolvedValue(mockApyBreakdown)
+jest.mocked(getTvls).mockResolvedValue(mockTvls)
+
+const vault: BaseBeefyVault = {
+ type: 'gov',
+ subType: 'cowcentrated',
+} as BaseBeefyVault
+
+const expectedBeefyVault = {
+ address: '0x987654321',
+ availableShortcutIds: ['deposit', 'withdraw', 'swap-deposit'],
+ dataProps: {
+ cantSeparateCompoundedInterest: true,
+ claimType: 'rewards',
+ contractCreatedAt: '1970-01-01T03:25:45.000Z',
+ dailyYieldRatePercentage: 0.07400740957195229,
+ depositTokenId: 'arbitrum-one:0x123456789',
+ earningItems: [],
+ manageUrl: 'https://app.beefy.com/vault/defaultVault',
+ safety: undefined,
+ tvl: '98765',
+ withdrawTokenId: 'arbitrum-one:0x987654321',
+ yieldRates: [
+ {
+ label: 'yieldRates.earningsApy',
+ percentage: 31,
+ tokenId: 'arbitrum-one:0x123456789',
+ },
+ ],
+ },
+ displayProps: expect.any(Function),
+ networkId: 'arbitrum-one',
+ pricePerShare: expect.any(Function),
+ shortcutTriggerArgs: expect.any(Function),
+ tokens: [
+ {
+ address: '0x123456789',
+ fallbackPriceUsd: '1.2',
+ networkId: 'arbitrum-one',
+ },
+ ],
+ type: 'app-token-definition',
+}
+
+const expectedBeefyVault1 = {
+ ...expectedBeefyVault,
+ dataProps: {
+ ...expectedBeefyVault.dataProps,
+ manageUrl: 'https://app.beefy.com/vault/vault1',
+ },
+}
+
+const expectedBeefyVault2 = {
+ ...expectedBeefyVault,
+ address: '0x999999999',
+ dataProps: {
+ ...expectedBeefyVault.dataProps,
+ contractCreatedAt: '1970-01-02T13:43:10.000Z',
+ dailyYieldRatePercentage: 0.015965358745284597,
+ depositTokenId: 'arbitrum-one:0x111111111',
+ manageUrl: 'https://app.beefy.com/vault/vault2',
+ tvl: '1234567890',
+ withdrawTokenId: 'arbitrum-one:0x999999999',
+ yieldRates: [
+ {
+ label: 'yieldRates.earningsApy',
+ percentage: 6,
+ tokenId: 'arbitrum-one:0x111111111',
+ },
+ ],
+ },
+ tokens: [
+ {
+ address: '0x111111111',
+ fallbackPriceUsd: '1000',
+ networkId: 'arbitrum-one',
+ },
+ ],
+}
+
+const apyBreakdownWithCorrectComponents = {
+ vaultApr: 0.1,
+ clmApr: 0.2,
+ tradingApr: 0.3,
+}
+
+const apyBreakdownWithIncorrectComponents = {
+ unsupportedComponent: 0.1,
+ totalApy: 0.5,
+}
+
+describe('getDailyYieldRatePercentage', () => {
+ it('should return the correct daily yield rate percentage when there are components', () => {
+ const dailyYieldRatePercentage = getDailyYieldRatePercentage(
+ apyBreakdownWithCorrectComponents,
+ vault,
+ )
+ expect(dailyYieldRatePercentage).toBeCloseTo(0.164)
+ })
+ it('should return the correct daily yield rate percentage when there are no correct components', () => {
+ const dailyYieldRatePercentage = getDailyYieldRatePercentage(
+ apyBreakdownWithIncorrectComponents,
+ vault,
+ )
+ expect(dailyYieldRatePercentage).toBeCloseTo(0.111)
+ })
+ it('should not include rewardPoolApr in the daily yield rate percentage for gov cowcentrated vault', () => {
+ const dailyYieldRatePercentage = getDailyYieldRatePercentage(
+ { ...apyBreakdownWithCorrectComponents, rewardPoolApr: 0.4 },
+ vault,
+ )
+ expect(dailyYieldRatePercentage).toBeCloseTo(0.164)
+ })
+ it('should return 0 if totalApy is undefined and no components', () => {
+ const dailyYieldRatePercentage = getDailyYieldRatePercentage({}, vault)
+ expect(dailyYieldRatePercentage).toBe(0)
+ })
+ it('should ignore components that are NaN', () => {
+ const dailyYieldRatePercentage = getDailyYieldRatePercentage(
+ {
+ ...apyBreakdownWithCorrectComponents,
+ merklApr: NaN,
+ },
+ vault,
+ )
+ expect(dailyYieldRatePercentage).toBeCloseTo(0.164)
+ })
+})
+
+describe('hook', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+ it('should return the correct hook info', () => {
+ expect(hook.getInfo()).toEqual({
+ name: 'Beefy',
+ })
+ })
+ it('should return expected positions with balances when getPositionDefinitions is called with supported networkId and address', async () => {
+ mockReadContract.mockResolvedValue(mockGetTokenBalancesResponse)
+ const beefyPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x12345',
+ t: mockT,
+ })
+ expect(beefyPositions.length).toBe(1)
+ expect(beefyPositions[0]).toEqual(expectedBeefyVault2)
+ })
+ it('should return all expected positions when getPositionDefinitions is called with supported networkId and no address', async () => {
+ const beefyPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: undefined,
+ t: mockT,
+ })
+ expect(beefyPositions.length).toBe(2)
+ expect(beefyPositions[0]).toEqual(expectedBeefyVault1)
+ expect(beefyPositions[1]).toEqual(expectedBeefyVault2)
+ })
+ it('should return an empty array when getPositionDefinitions is called with an unsupported networkId', async () => {
+ const beefyPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-alfajores'],
+ address: '0x12345',
+ t: mockT,
+ })
+ expect(beefyPositions).toEqual([])
+ })
+ it('should return correct price per share', async () => {
+ const mockPricePerShareContext = {
+ tokensByTokenId: {
+ 'arbitrum-one:0x123456789': { decimals: 6 },
+ 'arbitrum-one:0x111111111': { decimals: 3 },
+ },
+ }
+ const beefyPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: undefined,
+ t: mockT,
+ })
+ expect(beefyPositions.length).toBe(2)
+
+ const pricePerShare0 = (beefyPositions[0] as AppTokenPositionDefinition)
+ .pricePerShare as Function
+ const pricePerShare1 = (beefyPositions[1] as AppTokenPositionDefinition)
+ .pricePerShare as Function
+
+ expect(await pricePerShare0(mockPricePerShareContext)).toEqual([
+ BigNumber('120'),
+ ])
+ expect(await pricePerShare1(mockPricePerShareContext)).toEqual([
+ BigNumber('100'),
+ ])
+ })
+})
diff --git a/src/apps/beefy/positions.ts b/src/apps/beefy/positions.ts
new file mode 100644
index 00000000..5ef43ad9
--- /dev/null
+++ b/src/apps/beefy/positions.ts
@@ -0,0 +1,538 @@
+import { Address } from 'viem'
+import { logger } from '../../log'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { NetworkId } from '../../types/networkId'
+import { toDecimalNumber, toSerializedDecimalNumber } from '../../types/numbers'
+import {
+ AppTokenPositionDefinition,
+ ClaimType,
+ ContractPositionDefinition,
+ PositionsHook,
+ TokenDefinition,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import { createBatches } from '../../utils/batcher'
+import {
+ beefyClmVaultsMulticallAbi,
+ beefyClmVaultsMulticallBytecode,
+} from './abis/beefy-clm-vaults-multicall'
+import { beefyV2AppMulticallAbi } from './abis/beefy-v2-app-multicall'
+import {
+ BaseBeefyVault,
+ GovVault,
+ getApyBreakdown,
+ getBeefyPrices,
+ getBeefyVaults,
+ getTvls,
+} from './api'
+import { TFunction } from 'i18next'
+import { networkIdToNativeAssetAddress } from '../../runtime/isNative'
+import { getSafety } from './safety'
+
+type BeefyPrices = Awaited>
+type BeefyApyBreakdown = Awaited>
+type BeefyTvls = Awaited>
+
+// Fetched addresses from https://github.com/beefyfinance/beefy-v2/blob/main/src/config/config.tsx
+const BEEFY_MULTICALL_ADDRESS: {
+ [networkId in NetworkId]: Address | undefined
+} = {
+ [NetworkId['ethereum-mainnet']]: '0x00d3e26d17aEA6f5c7d2f442aAc68E679E454517',
+ [NetworkId['arbitrum-one']]: '0x47bec05dC291e61cd4360322eA44882cA468dD54',
+ [NetworkId['op-mainnet']]: '0xB089f6c9C99238FC6df256cc66d53Aed198584D9',
+ [NetworkId['celo-mainnet']]: '0x0bF5F48d8F761efAe0f187eCce60784e5d3E87E6',
+ [NetworkId['polygon-pos-mainnet']]:
+ '0x244908D9A21B143911D531cD1D37575D63da4D87',
+ [NetworkId['base-mainnet']]: '0x57B01298DfDdeA1c6CaB01793396af5fbFc213CE',
+ [NetworkId['ethereum-sepolia']]: undefined,
+ [NetworkId['arbitrum-sepolia']]: undefined,
+ [NetworkId['op-sepolia']]: undefined,
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['base-sepolia']]: undefined,
+}
+
+const BEEFY_VAULT_BASE_URL = 'https://app.beefy.com/vault/'
+
+const beefyAppTokenDefinition = ({
+ networkId,
+ vault,
+ prices,
+ apyBreakdown,
+ tvls,
+ t,
+}: {
+ networkId: NetworkId
+ vault: BaseBeefyVault
+ prices: BeefyPrices
+ apyBreakdown: BeefyApyBreakdown
+ tvls: BeefyTvls
+ t: TFunction
+}): AppTokenPositionDefinition => {
+ const priceUsd = prices[vault.id]
+ const vaultTokenAddress =
+ vault.tokenAddress?.toLowerCase() ??
+ networkIdToNativeAssetAddress[networkId]
+ const tvl = tvls[vault.id]
+ const apy = apyBreakdown[vault.id]?.totalApy ?? 0
+ return {
+ type: 'app-token-definition',
+ networkId,
+ address: vault.earnedTokenAddress.toLowerCase(),
+ tokens: [
+ {
+ address: vaultTokenAddress,
+ networkId,
+ fallbackPriceUsd: priceUsd
+ ? toSerializedDecimalNumber(priceUsd)
+ : undefined,
+ },
+ ],
+ displayProps: () => {
+ return {
+ title: vault.name + (vault.status === 'eol' ? ' (Retired)' : ''),
+ description: 'Vault',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/beefy.png',
+ manageUrl: BEEFY_VAULT_BASE_URL + vault.id,
+ }
+ },
+ pricePerShare: async ({ tokensByTokenId }) => {
+ const tokenId = getTokenId({
+ address: vaultTokenAddress,
+ networkId,
+ })
+ const { decimals } = tokensByTokenId[tokenId]
+ return [
+ toDecimalNumber(
+ // pricePerShare can potentially be a string in scientific notation, so convert to Number, round and then to BigInt
+ BigInt(Math.round(Number(vault.pricePerFullShare))),
+ decimals,
+ ),
+ ]
+ },
+ dataProps: {
+ depositTokenId: getTokenId({
+ address: vault.tokenAddress,
+ networkId,
+ }),
+ withdrawTokenId: getTokenId({
+ address: vault.earnedTokenAddress,
+ networkId,
+ }),
+ yieldRates: apy
+ ? [
+ {
+ percentage: apy * 100,
+ label: t('yieldRates.earningsApy'),
+ tokenId: getTokenId({
+ networkId,
+ address: vault.tokenAddress,
+ }),
+ },
+ ]
+ : [],
+ earningItems: [],
+ cantSeparateCompoundedInterest: true,
+ tvl: tvl ? toSerializedDecimalNumber(tvl) : undefined,
+ manageUrl: `${BEEFY_VAULT_BASE_URL}${vault.id}`,
+ contractCreatedAt: new Date(vault.createdAt * 1000).toISOString(),
+ claimType: ClaimType.Rewards,
+ dailyYieldRatePercentage: getDailyYieldRatePercentage(
+ apyBreakdown[vault.id],
+ vault,
+ ),
+ safety: getSafety(vault, t),
+ },
+ availableShortcutIds: ['deposit', 'withdraw', 'swap-deposit'],
+ shortcutTriggerArgs: ({ tokensByTokenId }) => {
+ return {
+ deposit: {
+ tokenAddress: vault.tokenAddress?.toLowerCase(),
+ tokenDecimals: vault.tokenDecimals,
+ positionAddress: vault.earnedTokenAddress.toLowerCase(),
+ },
+ withdraw: {
+ tokenDecimals:
+ tokensByTokenId[
+ getTokenId({
+ address: vault.earnedTokenAddress,
+ networkId,
+ })
+ ].decimals,
+ positionAddress: vault.earnedTokenAddress.toLowerCase(),
+ },
+ 'swap-deposit': {
+ tokenAddress: vault.tokenAddress?.toLowerCase(),
+ positionAddress: vault.earnedTokenAddress.toLowerCase(),
+ },
+ }
+ },
+ }
+}
+
+// Based on https://github.com/beefyfinance/beefy-v2/blob/4413697f3d3cb5e090d8bb6958b621a673f0d739/src/features/data/actions/apy.ts#L46
+export function getDailyYieldRatePercentage(
+ apyBreakdown: BeefyApyBreakdown[string],
+ vault: BaseBeefyVault,
+) {
+ if (!apyBreakdown) {
+ return 0
+ }
+
+ // https://github.com/beefyfinance/beefy-v2/blob/4413697f3d3cb5e090d8bb6958b621a673f0d739/src/helpers/apy.ts#L103
+ const components = [
+ 'vaultApr',
+ 'clmApr',
+ 'tradingApr',
+ 'merklApr',
+ 'stellaSwapApr',
+ 'liquidStakingApr',
+ 'composablePoolApr',
+ 'rewardPoolApr',
+ 'rewardPoolTradingApr',
+ ]
+
+ let totalDaily = 0
+ // Calculate the total daily apy from components
+ if (Object.keys(apyBreakdown).some((key) => components.includes(key))) {
+ for (const component of components) {
+ const apr = apyBreakdown[component]
+ if (apr && !isNaN(Number(apr))) {
+ totalDaily += apr / 365
+ }
+ }
+ } else {
+ // "uncompound" apy to get daily apr
+ totalDaily = _yearlyToDaily(apyBreakdown.totalApy)
+ }
+
+ // At some point the Beefy team decided to change this 'rewardPoolApr' on this specific vault type to be a soft-boost
+ // instead of being calculated as regular APR, so to be backwards compatible they subtract it from the total daily APR
+ if (vault.type === 'gov' && vault.subType === 'cowcentrated') {
+ // anything in 'rewardPoolApr' (i.e. not in 'rewardPoolTradingApr') is considered a soft-boost on the pool
+ // and is should not be counted towards the daily yield rate
+ const additionalApr = apyBreakdown.rewardPoolApr ?? 0
+ totalDaily -= additionalApr / 365
+ }
+
+ // TODO: handle merkl campaigns which are off-chain rewards
+ // https://github.com/beefyfinance/beefy-v2/blob/4413697f3d3cb5e090d8bb6958b621a673f0d739/src/features/data/actions/apy.ts#L132
+
+ return totalDaily * 100
+}
+
+const _yearlyToDaily = (apy: number) => {
+ const dailyApy = Math.pow(10, Math.log10(apy + 1) / 365) - 1
+
+ if (isNaN(dailyApy)) {
+ return 0
+ }
+
+ return dailyApy
+}
+
+// CLM = Cowcentrated Liquidity Manager: https://docs.beefy.finance/beefy-products/clm
+interface ClmVaultBalanceInfo {
+ token0: Address
+ token1: Address
+ amount0: bigint
+ amount1: bigint
+}
+
+const beefyConcentratedContractDefinition = (
+ networkId: NetworkId,
+ vault: BaseBeefyVault,
+ balanceInfo: ClmVaultBalanceInfo | undefined,
+ description: string,
+ prices: BeefyPrices,
+): ContractPositionDefinition | null => {
+ if (!balanceInfo) {
+ return null
+ }
+
+ return {
+ type: 'contract-position-definition',
+ networkId,
+ address: vault.earnedTokenAddress.toLowerCase(),
+ tokens: vault.depositTokenAddresses.map((address) => {
+ const addressLower = address.toLowerCase()
+ const priceUsd = prices[addressLower]
+ return {
+ address: addressLower,
+ networkId,
+ fallbackPriceUsd: priceUsd
+ ? toSerializedDecimalNumber(priceUsd)
+ : undefined,
+ }
+ }),
+ displayProps: () => {
+ return {
+ title: vault.name + (vault.status === 'eol' ? ' (Retired)' : ''),
+ description,
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/beefy.png',
+ manageUrl: BEEFY_VAULT_BASE_URL + vault.id,
+ }
+ },
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const token0Decimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: balanceInfo.token0,
+ })
+ ].decimals
+ const token1Decimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: balanceInfo.token1,
+ })
+ ].decimals
+ return [
+ toDecimalNumber(balanceInfo.amount0, token0Decimals),
+ toDecimalNumber(balanceInfo.amount1, token1Decimals),
+ ]
+ },
+ }
+}
+
+const beefyBaseVaultsPositions = async ({
+ networkId,
+ address,
+ vaults,
+ multicallAddress,
+ prices,
+ apyBreakdown,
+ tvls,
+ t,
+}: {
+ networkId: NetworkId
+ address?: Address
+ vaults: BaseBeefyVault[]
+ multicallAddress: Address
+ prices: BeefyPrices
+ apyBreakdown: BeefyApyBreakdown
+ tvls: BeefyPrices
+ t: TFunction
+}) => {
+ const client = getClient(networkId)
+
+ const userVaults: (BaseBeefyVault & { balance: bigint })[] = []
+
+ if (address) {
+ await Promise.all(
+ createBatches(vaults).map(async (batch) => {
+ if (batch.length === 0) {
+ return
+ }
+ const balances = await client.readContract({
+ abi: beefyV2AppMulticallAbi,
+ address: multicallAddress,
+ functionName: 'getTokenBalances',
+ args: [batch.map((vault) => vault.earnContractAddress), address],
+ })
+ for (let i = 0; i < balances.length; i++) {
+ if (balances[i] > 0) {
+ userVaults.push({
+ ...batch[i],
+ balance: balances[i],
+ })
+ }
+ }
+ }),
+ )
+ } else {
+ userVaults.push(
+ ...vaults.map((vault) => ({ ...vault, balance: BigInt(0) })),
+ )
+ }
+
+ if (!userVaults.length) {
+ return []
+ }
+
+ const clmVaults = userVaults.filter((vault) => vault.type === 'cowcentrated')
+ const info =
+ clmVaults.length === 0 || !address // earn positions can't include clm vaults for now
+ ? []
+ : await client.readContract({
+ code: beefyClmVaultsMulticallBytecode,
+ abi: beefyClmVaultsMulticallAbi,
+ functionName: 'getUserVaults',
+ args: [address, clmVaults.map((vault) => vault.earnContractAddress)],
+ })
+ return userVaults
+ .map((vault) => {
+ try {
+ return vault.type === 'cowcentrated'
+ ? beefyConcentratedContractDefinition(
+ networkId,
+ vault,
+ info.find(
+ (i) =>
+ i.token0 === vault.depositTokenAddresses[0] &&
+ i.token1 === vault.depositTokenAddresses[1],
+ ),
+ 'CLM Vault',
+ prices,
+ )
+ : beefyAppTokenDefinition({
+ networkId,
+ vault,
+ prices,
+ apyBreakdown,
+ tvls,
+ t,
+ })
+ } catch (err) {
+ logger.error({ err, vault }, 'Error processing vault')
+ return null
+ }
+ })
+ .filter((position): position is ContractPositionDefinition => !!position)
+}
+
+const beefyGovVaultsPositions = async (
+ networkId: NetworkId,
+ address: Address,
+ vaults: BaseBeefyVault[],
+ govVaults: GovVault[],
+ multicallAddress: Address,
+ prices: BeefyPrices,
+) => {
+ const client = getClient(networkId)
+
+ const userVaults: (GovVault & { balance: bigint })[] = []
+
+ await Promise.all(
+ createBatches(govVaults).map(async (batch) => {
+ if (batch.length === 0) {
+ return
+ }
+ const balances = await client.readContract({
+ abi: beefyV2AppMulticallAbi,
+ address: multicallAddress,
+ functionName: 'getTokenBalances',
+ args: [batch.map((vault) => vault.earnContractAddress), address],
+ })
+ for (let i = 0; i < balances.length; i++) {
+ if (balances[i] > 0) {
+ userVaults.push({
+ ...batch[i],
+ balance: balances[i],
+ })
+ }
+ }
+ }),
+ )
+
+ if (!userVaults.length) {
+ return []
+ }
+
+ const clmVaults = userVaults
+ .map((vault) => ({
+ userVault: vault,
+ vault: vaults.find(
+ (v) =>
+ v.earnContractAddress === vault.tokenAddress &&
+ v.type === 'cowcentrated',
+ ),
+ }))
+ .filter((v) => v.vault !== undefined)
+ if (clmVaults.length !== userVaults.length) {
+ logger.error(
+ 'clmVaults.length !== userVaults.length some gov vaults are not being processed',
+ )
+ }
+ if (clmVaults.length === 0) {
+ return []
+ }
+
+ // Avoid a possible runtime error if the userVault.tokenAddress is undefined
+ const filteredClmVaults = clmVaults.filter(
+ ({ userVault }) => !!userVault.tokenAddress,
+ )
+
+ const info = await client.readContract({
+ code: beefyClmVaultsMulticallBytecode,
+ abi: beefyClmVaultsMulticallAbi,
+ functionName: 'getUserClmPools',
+ args: [
+ address,
+ // @ts-expect-error filteredVaults should have tokenAddress defined
+ filteredClmVaults.map(({ userVault }) => userVault.tokenAddress),
+ filteredClmVaults.map(({ userVault }) => userVault.earnContractAddress),
+ ],
+ })
+
+ return clmVaults
+ .map(({ vault }) =>
+ beefyConcentratedContractDefinition(
+ networkId,
+ vault!,
+ info.find(
+ (i) =>
+ i.token0 === vault!.depositTokenAddresses[0] &&
+ i.token1 === vault!.depositTokenAddresses[1],
+ ),
+ 'CLM Pool',
+ prices,
+ ),
+ )
+ .filter((position): position is ContractPositionDefinition => !!position)
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Beefy',
+ }
+ },
+ async getPositionDefinitions({ networkId, address, t }) {
+ const multicallAddress = BEEFY_MULTICALL_ADDRESS[networkId]
+ if (!multicallAddress) {
+ return []
+ }
+
+ const [{ vaults, govVaults }, prices, apyBreakdown, tvls] =
+ await Promise.all([
+ getBeefyVaults(networkId),
+ getBeefyPrices(networkId),
+ getApyBreakdown(),
+ getTvls(networkId),
+ ])
+
+ return [
+ ...(await beefyBaseVaultsPositions({
+ networkId,
+ address: address as Address | undefined,
+ vaults,
+ multicallAddress,
+ prices,
+ apyBreakdown,
+ tvls,
+ t,
+ })),
+ // no gov vaults for earn positions, so no need to return 0 balances
+ ...(address
+ ? await beefyGovVaultsPositions(
+ networkId,
+ address as Address,
+ vaults,
+ govVaults,
+ multicallAddress,
+ prices,
+ )
+ : []),
+ ]
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/beefy/safety.test.ts b/src/apps/beefy/safety.test.ts
new file mode 100644
index 00000000..3ce80501
--- /dev/null
+++ b/src/apps/beefy/safety.test.ts
@@ -0,0 +1,98 @@
+import { TFunction } from 'i18next'
+import { BaseBeefyVault } from './api'
+import { getSafety } from './safety'
+
+const mockT = ((x: string) => x) as TFunction
+
+describe('safety', () => {
+ it('returns safety info for known risks', () => {
+ const safety = getSafety(
+ {
+ risks: [
+ 'COMPLEXITY_LOW',
+ 'BATTLE_TESTED',
+ 'IL_NONE',
+ 'MCAP_LARGE',
+ 'AUDIT',
+ 'CONTRACTS_VERIFIED',
+ ],
+ id: 'mock-vault',
+ } as BaseBeefyVault,
+ mockT,
+ )
+
+ expect(safety).toEqual({
+ level: 'high',
+ risks: [
+ {
+ category: 'beefyRisks.Categry-Beefy',
+ isPositive: true,
+ title: 'beefyRisks.Complexity-Low-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Beefy',
+ isPositive: true,
+ title: 'beefyRisks.Testd-Battle-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Asset',
+ isPositive: true,
+ title: 'beefyRisks.IL-None-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Asset',
+ isPositive: true,
+ title: 'beefyRisks.MktCap-Large-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Platform',
+ isPositive: true,
+ title: 'beefyRisks.Platfrm-Audit-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Platform',
+ isPositive: true,
+ title: 'beefyRisks.Platfrm-Verified-Titl',
+ },
+ ],
+ })
+ })
+
+ it('returns undefined if no known risks', () => {
+ const safety = getSafety(
+ {
+ risks: ['foo', 'bar'] as string[],
+ id: 'mock-vault',
+ } as BaseBeefyVault,
+ mockT,
+ )
+
+ expect(safety).toBeUndefined()
+ })
+
+ it('excludes unknown risks if there are some unknown risks', () => {
+ const safety = getSafety(
+ {
+ risks: ['foo', 'EXPERIMENTAL_STRAT', 'MCAP_MICRO'] as string[],
+ id: 'mock-vault',
+ } as BaseBeefyVault,
+ mockT,
+ )
+
+ expect(safety).toEqual({
+ level: 'medium',
+ risks: [
+ {
+ category: 'beefyRisks.Categry-Beefy',
+ isPositive: false,
+ title: 'beefyRisks.Testd-Experimtl-Titl',
+ },
+ {
+ category: 'beefyRisks.Categry-Asset',
+ isPositive: false,
+ title: 'beefyRisks.MktCap-Micro-Titl',
+ },
+ ],
+ })
+ })
+})
diff --git a/src/apps/beefy/safety.ts b/src/apps/beefy/safety.ts
new file mode 100644
index 00000000..6d78f94c
--- /dev/null
+++ b/src/apps/beefy/safety.ts
@@ -0,0 +1,78 @@
+import { TFunction } from 'i18next'
+import { Safety } from '../../types/positions'
+import { MAX_SCORE, RISKS, CATEGORIES } from './safetyConfig'
+import { logger } from '../../log'
+import { BaseBeefyVault } from './api'
+
+// From https://github.com/beefyfinance/beefy-v2/blob/3690e105c4bb98afcf06f9c3e385d13cc23af5cd/src/helpers/safetyScore.tsx
+const calcRisk = (risks: string[]) => {
+ const categories: Record = {}
+ for (const c of Object.keys(CATEGORIES)) {
+ categories[c] = []
+ }
+
+ // reverse lookup
+ risks.forEach((risk) => {
+ // should never happen with check below, but leaving as is from beefy codebase
+ if (!(risk in RISKS)) {
+ return
+ }
+
+ // should never happen with type safety, but leaving as is from beefy codebase
+ const cat = RISKS[risk].category
+ if (!(cat in CATEGORIES)) {
+ return
+ }
+
+ categories[cat].push(risk)
+ })
+
+ // reduce & clamp
+ let score = 0
+ for (const [category, weight] of Object.entries(CATEGORIES)) {
+ score +=
+ weight *
+ Math.min(
+ 1,
+ categories[category].reduce(
+ (acc: number, risk: string) => acc + RISKS[risk].score,
+ 0,
+ ),
+ )
+ }
+
+ return score
+}
+
+const safetyScore = (risks: string[]) => {
+ const score = MAX_SCORE * (1 - calcRisk(risks))
+ // from https://github.com/beefyfinance/beefy-v2/blob/3690e105c4bb98afcf06f9c3e385d13cc23af5cd/src/components/SafetyScore/SafetyScore.tsx#L27-L29
+ return score > 7.5 ? 'high' : score >= 6.4 ? 'medium' : 'low'
+}
+
+export function getSafety(
+ vault: BaseBeefyVault,
+ t: TFunction,
+): Safety | undefined {
+ const { risks } = vault
+ const knownRisks = risks.filter((risk) => !!RISKS[risk])
+
+ if (knownRisks.length !== risks.length) {
+ logger.warn({ vault }, 'Beefy vault has unknown risks')
+ }
+
+ if (!knownRisks.length) return
+ return {
+ level: safetyScore(knownRisks),
+ risks: knownRisks.map((risk) => {
+ const { category, title, score } = RISKS[risk]
+ return {
+ // from https://github.com/beefyfinance/beefy-v2/blob/3690e105c4bb98afcf06f9c3e385d13cc23af5cd/src/features/vault/components/SafetyCard/SafetyCard.tsx#L39
+ // score represents the level of the risk, higher is worse
+ isPositive: score <= 0,
+ title: t(`beefyRisks.${title}`),
+ category: t(`beefyRisks.${category}`),
+ }
+ }),
+ }
+}
diff --git a/src/apps/beefy/safetyConfig.ts b/src/apps/beefy/safetyConfig.ts
new file mode 100644
index 00000000..1ad81df5
--- /dev/null
+++ b/src/apps/beefy/safetyConfig.ts
@@ -0,0 +1,185 @@
+// from https://github.com/beefyfinance/beefy-v2/blob/3690e105c4bb98afcf06f9c3e385d13cc23af5cd/src/config/risk.tsx
+export const MAX_SCORE = 10
+
+type Risk = {
+ category: keyof typeof CATEGORIES
+ score: number
+ title: string
+}
+
+// removed explanation, condition and risks without category / score from the beefy codebase
+export const RISKS: Record = {
+ COMPLEXITY_LOW: {
+ category: 'Categry-Beefy',
+ score: 0,
+ title: 'Complexity-Low-Titl',
+ },
+
+ COMPLEXITY_MID: {
+ category: 'Categry-Beefy',
+ score: 0.3,
+ title: 'Complexity-Mid-Titl',
+ },
+
+ COMPLEXITY_HIGH: {
+ category: 'Categry-Beefy',
+ score: 0.5,
+ title: 'Complexity-Hi-Titl',
+ },
+
+ BATTLE_TESTED: {
+ category: 'Categry-Beefy',
+ score: 0,
+ title: 'Testd-Battle-Titl',
+ },
+
+ NEW_STRAT: {
+ category: 'Categry-Beefy',
+ score: 0.3,
+ title: 'Testd-New-Titl',
+ },
+
+ EXPERIMENTAL_STRAT: {
+ category: 'Categry-Beefy',
+ score: 0.7,
+ title: 'Testd-Experimtl-Titl',
+ },
+
+ IL_NONE: {
+ category: 'Categry-Asset',
+ score: 0,
+ title: 'IL-None-Titl',
+ },
+
+ IL_LOW: {
+ category: 'Categry-Asset',
+ score: 0.2,
+ title: 'IL-Low-Titl',
+ },
+
+ IL_HIGH: {
+ category: 'Categry-Asset',
+ score: 0.5,
+ title: 'IL-High-Titl',
+ },
+
+ ALGO_STABLE: {
+ category: 'Categry-Asset',
+ score: 0.9,
+ title: 'IL-AlgoStable-Titl',
+ },
+
+ PARTIAL_COLLAT_ALGO_STABLECOIN: {
+ category: 'Categry-Asset',
+ score: 0.21,
+ title: 'PartialCollatAlgoStable-Titl',
+ },
+
+ OVER_COLLAT_ALGO_STABLECOIN: {
+ category: 'Categry-Asset',
+ score: 0.15,
+ title: 'OverCollatAlgoStable-Titl',
+ },
+
+ LIQ_HIGH: {
+ category: 'Categry-Asset',
+ score: 0,
+ title: 'Liquidt-High-Titl',
+ },
+
+ LIQ_LOW: {
+ category: 'Categry-Asset',
+ score: 0.3,
+ title: 'Liquidt-Low-Titl',
+ },
+
+ MCAP_LARGE: {
+ category: 'Categry-Asset',
+ score: 0,
+ title: 'MktCap-Large-Titl',
+ },
+
+ MCAP_MEDIUM: {
+ category: 'Categry-Asset',
+ score: 0.1,
+ title: 'MktCap-Mid-Titl',
+ },
+
+ MCAP_SMALL: {
+ category: 'Categry-Asset',
+ score: 0.3,
+ title: 'MktCap-Small-Titl',
+ },
+
+ MCAP_MICRO: {
+ category: 'Categry-Asset',
+ score: 0.5,
+ title: 'MktCap-Micro-Titl',
+ },
+
+ SUPPLY_CENTRALIZED: {
+ category: 'Categry-Asset',
+ score: 1,
+ title: 'Concentrated-Titl',
+ },
+
+ PLATFORM_ESTABLISHED: {
+ category: 'Categry-Platform',
+ score: 0,
+ title: 'Platfrm-Establshd-Titl',
+ },
+
+ PLATFORM_NEW: {
+ category: 'Categry-Platform',
+ score: 0.5,
+ title: 'Platfrm-New-Titl',
+ },
+
+ NO_AUDIT: {
+ category: 'Categry-Platform',
+ score: 0.3,
+ title: 'Platfrm-AuditNo-Titl',
+ },
+
+ AUDIT: {
+ category: 'Categry-Platform',
+ score: 0,
+ title: 'Platfrm-Audit-Titl',
+ },
+
+ CONTRACTS_VERIFIED: {
+ category: 'Categry-Platform',
+ score: 0,
+ title: 'Platfrm-Verified-Titl',
+ },
+
+ CONTRACTS_UNVERIFIED: {
+ category: 'Categry-Platform',
+ score: 1,
+ title: 'Platfrm-VerifiedNo-Titl',
+ },
+
+ ADMIN_WITH_TIMELOCK: {
+ category: 'Categry-Platform',
+ score: 0,
+ title: 'Platfrm-Timelock-Titl',
+ },
+
+ ADMIN_WITH_SHORT_TIMELOCK: {
+ category: 'Categry-Platform',
+ score: 0.5,
+ title: 'Platfrm-TimelockShort-Titl',
+ },
+
+ ADMIN_WITHOUT_TIMELOCK: {
+ category: 'Categry-Platform',
+ score: 1,
+ title: 'Platfrm-TimelockNo-Titl',
+ },
+}
+
+export const CATEGORIES = {
+ 'Categry-Beefy': 0.2,
+ 'Categry-Asset': 0.3,
+ 'Categry-Platform': 0.5,
+}
diff --git a/src/apps/beefy/shortcuts.e2e.ts b/src/apps/beefy/shortcuts.e2e.ts
new file mode 100644
index 00000000..6a763abc
--- /dev/null
+++ b/src/apps/beefy/shortcuts.e2e.ts
@@ -0,0 +1,97 @@
+import hook from './shortcuts'
+import { NetworkId } from '../../types/networkId'
+import { ShortcutDefinition } from '../../types/shortcuts'
+
+describe('getShortcutDefinitions', () => {
+ it('should get the definitions successfully', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ expect(shortcuts.length).toBeGreaterThan(0)
+ expect(shortcuts[0].id).toBe('deposit')
+ })
+
+ describe('deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'deposit')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC
+ tokenDecimals: 6,
+ positionAddress: '0xb9A27ba529634017b12e3cbbbFFb6dB7908a8C8B',
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0xaf88d065e77c8cc2239327c5edb3a432268e5831`,
+ amount: '10',
+ },
+ ],
+ })
+
+ expect(transactions.length).toEqual(2)
+ })
+ })
+
+ describe('withdraw.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'withdraw')
+ expect(shortcut).toBeDefined()
+ expect(shortcuts[1].id).toBe('withdraw')
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokens: [
+ {
+ tokenId: `${NetworkId['arbitrum-one']}:0xb9A27ba529634017b12e3cbbbFFb6dB7908a8C8B`,
+ amount: '1',
+ },
+ ],
+ positionAddress: '0xb9A27ba529634017b12e3cbbbFFb6dB7908a8C8B',
+ tokenDecimals: 3,
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+
+ describe('swap-deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find(
+ (shortcut) => shortcut.id === 'swap-deposit',
+ )
+ expect(shortcut).toBeDefined()
+ expect(shortcut!.category).toEqual('swap-deposit')
+
+ const { transactions, dataProps } = await (
+ shortcut as ShortcutDefinition<'swap-deposit', any>
+ ).onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ positionAddress: '0xb9A27ba529634017b12e3cbbbFFb6dB7908a8C8B',
+ swapFromToken: {
+ decimals: 18,
+ tokenId: `${NetworkId['arbitrum-one']}:native`, // ETH
+ amount: '0.0001',
+ isNative: true,
+ },
+ tokenAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC
+ })
+
+ expect(transactions.length).toEqual(1)
+ expect(dataProps).toBeDefined()
+ expect(dataProps.swapTransaction).toBeDefined()
+ })
+ })
+})
diff --git a/src/apps/beefy/shortcuts.ts b/src/apps/beefy/shortcuts.ts
new file mode 100644
index 00000000..2abae066
--- /dev/null
+++ b/src/apps/beefy/shortcuts.ts
@@ -0,0 +1,270 @@
+import { Address, parseUnits, erc20Abi, encodeFunctionData } from 'viem'
+import { z } from 'zod'
+import { logger } from '../../log'
+import { getClient } from '../../runtime/client'
+import {
+ simulateTransactions,
+ UnsupportedSimulateRequest,
+} from '../../runtime/simulateTransactions'
+import { ZodAddressLowerCased } from '../../types/address'
+import { NetworkId } from '../../types/networkId'
+import {
+ ShortcutsHook,
+ createShortcut,
+ tokenAmounts,
+ Transaction,
+ tokenAmountWithMetadata,
+ ZodEnableAppFee,
+} from '../../types/shortcuts'
+import { vaultAbi } from './abis/vault'
+import { ChainType, SquidCallType } from '@0xsquid/squid-types'
+import { prepareSwapTransactions } from '../../utils/prepareSwapTransactions'
+
+// Hardcoded fallback if simulation isn't enabled
+const DEFAULT_DEPOSIT_GAS = 750_000n
+const DEFAULT_APPROVE_GAS = 200_000n
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId) {
+ return [
+ createShortcut({
+ id: 'deposit',
+ name: 'Deposit',
+ description: 'Lend your assets to earn interest',
+ networkIds: [networkId],
+ category: 'deposit',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ // these three will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ positionAddress: ZodAddressLowerCased,
+ tokenAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ // amount in smallest unit
+ const amountToSupply = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const client = getClient(networkId)
+
+ const approvedAllowanceForSpender = await client.readContract({
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'allowance',
+ args: [walletAddress, positionAddress],
+ })
+
+ if (approvedAllowanceForSpender < amountToSupply) {
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [positionAddress, amountToSupply],
+ })
+
+ const approveTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: tokenAddress,
+ data,
+ }
+ transactions.push(approveTx)
+ }
+
+ const depositTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: vaultAbi,
+ functionName: 'deposit',
+ args: [amountToSupply],
+ }),
+ }
+
+ transactions.push(depositTx)
+
+ // TODO: consider moving this concern to the runtime
+ try {
+ const simulatedTransactions = await simulateTransactions({
+ transactions,
+ networkId,
+ })
+ const supplySimulatedTx =
+ simulatedTransactions[simulatedTransactions.length - 1]
+
+ // 15% buffer on the estimation from the simulation
+ depositTx.gas = (BigInt(supplySimulatedTx.gasNeeded) * 115n) / 100n
+ depositTx.estimatedGasUse = BigInt(supplySimulatedTx.gasUsed)
+ } catch (error) {
+ if (!(error instanceof UnsupportedSimulateRequest)) {
+ logger.warn(error, 'Unexpected error during simulateTransactions')
+ }
+ depositTx.gas = DEFAULT_DEPOSIT_GAS
+ depositTx.estimatedGasUse = DEFAULT_DEPOSIT_GAS / 3n
+ }
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'withdraw',
+ name: 'Withdraw',
+ description: 'Withdraw your assets',
+ networkIds: [networkId],
+ category: 'withdraw',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ // these two will be passed in the shortcutTriggerArgs.
+ positionAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ const amountToWithdraw = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const withdrawTx: Transaction = tokens[0].useMax
+ ? {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: vaultAbi,
+ functionName: 'withdrawAll',
+ args: [],
+ }),
+ }
+ : {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: vaultAbi,
+ functionName: 'withdraw',
+ args: [amountToWithdraw],
+ }),
+ }
+
+ transactions.push(withdrawTx)
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'swap-deposit',
+ name: 'Swap & Deposit',
+ description: 'Swap assets and lend them to earn interest',
+ networkIds: [networkId],
+ category: 'swap-deposit',
+ triggerInputShape: {
+ swapFromToken: tokenAmountWithMetadata,
+ enableAppFee: ZodEnableAppFee,
+ // set via shortcutTriggerArgs, the deposit token's address
+ tokenAddress: ZodAddressLowerCased,
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({
+ positionAddress,
+ swapFromToken,
+ tokenAddress,
+ address,
+ networkId,
+ enableAppFee,
+ }) {
+ const walletAddress = address as Address
+ // use a placeholder non zero amount so tx simulation can succeed.
+ // squid postHook will replace this with the actual amount after swap.
+ const amount = 1n
+ const approveData = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [positionAddress, amount],
+ })
+ const supplyData = encodeFunctionData({
+ abi: vaultAbi,
+ functionName: 'deposit',
+ args: [amount],
+ })
+ const transferData = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'transfer',
+ args: [walletAddress, amount],
+ })
+
+ return await prepareSwapTransactions({
+ networkId,
+ swapFromToken,
+ swapToTokenAddress: tokenAddress,
+ walletAddress,
+ enableAppFee,
+ // based off of https://docs.squidrouter.com/building-with-squid-v2/key-concepts/hooks/build-a-posthook
+ postHook: {
+ chainType: ChainType.EVM,
+ calls: [
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: tokenAddress,
+ callData: approveData,
+ payload: {
+ tokenAddress,
+ inputPos: 1,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_APPROVE_GAS.toString(),
+ },
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: positionAddress,
+ callData: supplyData,
+ payload: {
+ tokenAddress,
+ inputPos: 0,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_DEPOSIT_GAS.toString(),
+ },
+ {
+ chainType: ChainType.EVM,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: positionAddress,
+ callData: transferData,
+ payload: {
+ tokenAddress: positionAddress,
+ inputPos: 1,
+ },
+ // no native token transfer. this is optional per types, but squid request fails without it
+ value: '0',
+ estimatedGas: DEFAULT_DEPOSIT_GAS.toString(),
+ },
+ ],
+ description: 'Deposit into beefy pool',
+ },
+ })
+ },
+ }),
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/compound/abis/CompoundUserPositionMulticall.sol b/src/apps/compound/abis/CompoundUserPositionMulticall.sol
new file mode 100644
index 00000000..aeddf3ed
--- /dev/null
+++ b/src/apps/compound/abis/CompoundUserPositionMulticall.sol
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.2;
+
+interface Comet {
+ struct AssetInfo {
+ uint8 offset;
+ address asset;
+ address priceFeed;
+ uint64 scale;
+ uint64 borrowCollateralFactor;
+ uint64 liquidateCollateralFactor;
+ uint64 liquidationFactor;
+ uint128 supplyCap;
+ }
+
+ function balanceOf(address owner) external view returns (uint256);
+
+ function collateralBalanceOf(
+ address account,
+ address asset
+ ) external view returns (uint128);
+
+ function borrowBalanceOf(address account) external view returns (uint256);
+
+ function baseToken() external view returns (address);
+ function getAssetInfo(uint8 i) external view returns (AssetInfo memory);
+ function numAssets() external view returns (uint8);
+}
+
+contract CompoundUserPositionMulticall {
+ struct MarketInfo {
+ address baseToken;
+ uint256 baseTokenBalance;
+ uint256 borrowBalance;
+ CollateralInfo[] collaterals;
+ }
+
+ struct CollateralInfo {
+ address asset;
+ uint128 balance;
+ }
+
+ function getUserPositions(
+ address owner,
+ address[] memory cometAddresses
+ ) external view returns (MarketInfo[] memory marketInfo) {
+ marketInfo = new MarketInfo[](cometAddresses.length);
+
+ for (uint256 index = 0; index < cometAddresses.length; index++) {
+ Comet comet = Comet(cometAddresses[index]);
+
+ uint8 numAssets = comet.numAssets();
+ CollateralInfo[] memory collaterals = new CollateralInfo[](numAssets);
+
+ for (uint8 collIndex = 0; collIndex < numAssets; collIndex++) {
+ Comet.AssetInfo memory assetInfo = comet.getAssetInfo(collIndex);
+ CollateralInfo memory collateralInfo = CollateralInfo(
+ assetInfo.asset,
+ comet.collateralBalanceOf(owner, assetInfo.asset)
+ );
+ collaterals[collIndex] = collateralInfo;
+ }
+
+ marketInfo[index] = MarketInfo(
+ comet.baseToken(),
+ comet.balanceOf(owner),
+ comet.borrowBalanceOf(owner),
+ collaterals
+ );
+ }
+ }
+}
diff --git a/src/apps/compound/abis/compound-multicall.ts b/src/apps/compound/abis/compound-multicall.ts
new file mode 100644
index 00000000..9dbd4f72
--- /dev/null
+++ b/src/apps/compound/abis/compound-multicall.ts
@@ -0,0 +1,63 @@
+export const compoundMulticallBytecode =
+ '0x6080806040523461001657610bb4908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c63ee3b1eb9146100295750600080fd5b346100fb5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100fb5760043561006481610102565b60243567ffffffffffffffff81116100fe57366023820112156100fe57806004013592610090846101e3565b9361009e6040519586610155565b80855260209260248487019260051b820101923684116100fb5750602401905b8282106100e2576100de6100d2878761067f565b6040519182918261020a565b0390f35b83809183356100f081610102565b8152019101906100be565b80fd5b8280fd5b73ffffffffffffffffffffffffffffffffffffffff81160361012057565b600080fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761019657604052565b61019e610125565b604052565b604051906040820182811067ffffffffffffffff82111761019657604052565b604051906080820182811067ffffffffffffffff82111761019657604052565b60209067ffffffffffffffff81116101fd575b60051b0190565b610205610125565b6101f6565b602080820190808352835180925260409283810182858560051b840101960194600080935b86851061024157505050505050505090565b9091929394887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08383999a9b0301865289519060808360a08284019373ffffffffffffffffffffffffffffffffffffffff9384875116825283870151848301528a8701518b8301526060809701519682015285518095520193019186915b888284106102e357505050505090806001929a01950195019396959492919061022f565b84518051831687528701516fffffffffffffffffffffffffffffffff16868801528c9695019493909301926001909201916102bf565b90610323826101e3565b60409061033282519182610155565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061036082956101e3565b0191600091825b848110610375575050505050565b60209083516080810181811067ffffffffffffffff8211176103b3575b85528581528286818301528686830152606080830152828501015201610367565b6103bb610125565b610392565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461041e570190565b6104266103c0565b0190565b805182101561043e5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b519060ff8216820361012057565b908160209103126101205761048f9061046d565b90565b506040513d6000823e3d90fd5b906104a9826101e3565b60406104b781519283610155565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06104e583956101e3565b0191600090815b8481106104fa575050505050565b602090845185810181811067ffffffffffffffff82111761052c575b86528481528285818301528285010152016104ec565b610534610125565b610516565b60ff6001911660ff811461041e570190565b519061055682610102565b565b519067ffffffffffffffff8216820361012057565b51906fffffffffffffffffffffffffffffffff8216820361012057565b809161010092839103126101205760e06106329160405193840184811067ffffffffffffffff82111761063a575b6040526105c48161046d565b84526105d26020820161054b565b60208501526105e36040820161054b565b60408501526105f460608201610558565b606085015261060560808201610558565b608085015261061660a08201610558565b60a085015261062760c08201610558565b60c08501520161056d565b60e082015290565b610642610125565b6105b8565b908160209103126101205761048f9061056d565b90816020910312610120575161048f81610102565b90816020910312610120575190565b909161068b8351610319565b926000935b8151851015610b77576106df6106c66106c66106ac888661042a565b5173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b946040958651957fa46fe83b00000000000000000000000000000000000000000000000000000000875260209260049484898781875afa988915610b6a575b600099610b3b575b5060ff809916976107368961049f565b9760005b8b81168b81101561091a5790610899828f61089261089f958f8f938f8f908f836108389383926107dd848f8d61088d9a51907fc8c7fe6b00000000000000000000000000000000000000000000000000000000825281806107ab610100958694830191909160ff6020820193169052565b0381895afa91821561090d575b6000926108e0575b5050015173ffffffffffffffffffffffffffffffffffffffff1690565b92517f5c2549ee00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182169b81019b8c5290831660208c01529199919485928391829160400190565b03915afa9182156108d3575b6000926108a4575b506108746108586101a3565b73ffffffffffffffffffffffffffffffffffffffff9098168852565b8601906fffffffffffffffffffffffffffffffff169052565b61042a565b528c61042a565b50610539565b61073a565b816108c59293503d84116108cc575b6108bd8183610155565b810190610647565b903861084c565b503d6108b3565b6108db610492565b610844565b6108ff9250803d10610906575b6108f78183610155565b81019061058a565b38806107c0565b503d6108ed565b610915610492565b6107b8565b505097929594939a9199509750610a8c958151937fc55dae6300000000000000000000000000000000000000000000000000000000855285858381845afa948515610b2e575b600095610afb575b50610a2a9394958c8451927f70a082310000000000000000000000000000000000000000000000000000000084528284806109c28589830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b0381845afa938415610aee575b600094610acf575b5082939486518098819482937f374c49b4000000000000000000000000000000000000000000000000000000008452830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa938415610ac2575b600094610a93575b50610a66610a4a6101c3565b73ffffffffffffffffffffffffffffffffffffffff9097168752565b8501528301526060820152610a7b828761042a565b52610a86818661042a565b506103f0565b9392610690565b81610ab49295503d8611610abb575b610aac8183610155565b810190610670565b9238610a3e565b503d610aa2565b610aca610492565b610a36565b839450610ae890843d8611610abb57610aac8183610155565b936109d7565b610af6610492565b6109cf565b610a2a949550610b2090873d8911610b27575b610b188183610155565b81019061065b565b9493610968565b503d610b0e565b610b36610492565b610960565b610b5c919950853d8711610b63575b610b548183610155565b81019061047b565b9738610726565b503d610b4a565b610b72610492565b61071e565b935050905056fea2646970667358221220d0685fd1b808929d4108dc3b4d233fac1ad06757c5eee260a050a45ea4bc471e64736f6c634300080d0033'
+export const compoundMulticallAbi = [
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address[]',
+ name: 'cometAddresses',
+ type: 'address[]',
+ },
+ ],
+ name: 'getUserPositions',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'baseToken',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'baseTokenBalance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'borrowBalance',
+ type: 'uint256',
+ },
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'uint128',
+ name: 'balance',
+ type: 'uint128',
+ },
+ ],
+ internalType:
+ 'struct CompoundUserPositionMulticall.CollateralInfo[]',
+ name: 'collaterals',
+ type: 'tuple[]',
+ },
+ ],
+ internalType: 'struct CompoundUserPositionMulticall.MarketInfo[]',
+ name: 'marketInfo',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/compound/assets/compound.png b/src/apps/compound/assets/compound.png
new file mode 100644
index 00000000..4222470a
Binary files /dev/null and b/src/apps/compound/assets/compound.png differ
diff --git a/src/apps/compound/positions.e2e.ts b/src/apps/compound/positions.e2e.ts
new file mode 100644
index 00000000..023d03ba
--- /dev/null
+++ b/src/apps/compound/positions.e2e.ts
@@ -0,0 +1,62 @@
+import { t } from '../../../test/i18next'
+import { getConfig } from '../../config'
+import { getBaseTokensInfo, getPositions } from '../../runtime/getPositions'
+import { NetworkId } from '../../types/networkId'
+import { TokensInfo } from '../../types/positions'
+import hook from './positions'
+
+describe('getPositionDefinitions', () => {
+ let baseTokensInfo: TokensInfo = {}
+ beforeAll(async () => {
+ baseTokensInfo = await getBaseTokensInfo(getConfig().GET_TOKENS_INFO_URL)
+ })
+
+ it('should get the address definitions successfully for supply & collateral', async () => {
+ const positions = await getPositions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['compound'],
+ t,
+ baseTokensInfo,
+ })
+
+ const supplyPosition = positions.find((p) =>
+ p.displayProps.title.endsWith(' Supply'),
+ )
+ expect(supplyPosition?.tokens.length).toBeGreaterThan(0)
+
+ const collateralPosition = positions.find((p) =>
+ p.displayProps.title.endsWith(' Collateral'),
+ )
+ expect(collateralPosition?.tokens.length).toBeGreaterThan(0)
+ })
+
+ it('should get the address definitions successfully for debt & collateral', async () => {
+ const positions = await getPositions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['compound'],
+ t,
+ baseTokensInfo,
+ })
+
+ const collateralPosition = positions.find((p) =>
+ p.displayProps.title.endsWith(' Collateral'),
+ )
+ expect(collateralPosition?.tokens.length).toBeGreaterThan(0)
+
+ const debtPosition = positions.find((p) =>
+ p.displayProps.title.endsWith(' Debt'),
+ )
+ expect(debtPosition?.tokens.length).toBeGreaterThan(0)
+ })
+
+ it('should get no definitions for an address with no blockchain interaction', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
+ expect(positions.length).toBe(0)
+ })
+})
diff --git a/src/apps/compound/positions.ts b/src/apps/compound/positions.ts
new file mode 100644
index 00000000..b97959b6
--- /dev/null
+++ b/src/apps/compound/positions.ts
@@ -0,0 +1,180 @@
+import { Address } from 'viem'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { NetworkId } from '../../types/networkId'
+import { toDecimalNumber } from '../../types/numbers'
+import {
+ ContractPositionDefinition,
+ PositionsHook,
+ TokenDefinition,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import {
+ compoundMulticallAbi,
+ compoundMulticallBytecode,
+} from './abis/compound-multicall'
+
+const COMPOUND_NETWORK_NAME: Partial> = {
+ [NetworkId['ethereum-mainnet']]: 'mainnet',
+ [NetworkId['op-mainnet']]: 'op',
+ [NetworkId['polygon-pos-mainnet']]: 'polygon',
+ [NetworkId['base-mainnet']]: 'basemainnet',
+ [NetworkId['arbitrum-one']]: 'arb',
+}
+
+// Data from https://docs.compound.finance/
+const MARKETS: { networkId: NetworkId; address: Address }[] = [
+ {
+ // USDC
+ networkId: NetworkId['op-mainnet'],
+ address: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB',
+ },
+ {
+ // USDT
+ networkId: NetworkId['op-mainnet'],
+ address: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214',
+ },
+ {
+ // USDC
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0xc3d688B66703497DAA19211EEdff47f25384cdc3',
+ },
+ {
+ // WETH
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0xA17581A9E3356d9A858b789D68B4d866e593aE94',
+ },
+ {
+ // USDC
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf',
+ },
+ {
+ // WETH
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486',
+ },
+ {
+ // USDT
+ networkId: NetworkId['arbitrum-one'],
+ address: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07',
+ },
+]
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Compound',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ const markets = MARKETS.filter((market) => market.networkId === networkId)
+ if (!markets.length || !address) {
+ return []
+ }
+
+ const client = getClient(networkId)
+
+ const results = await client.readContract({
+ code: compoundMulticallBytecode,
+ abi: compoundMulticallAbi,
+ functionName: 'getUserPositions',
+ args: [address as Address, markets.map((m) => m.address)],
+ })
+
+ return results.flatMap(
+ ({ baseToken, baseTokenBalance, borrowBalance, collaterals }, index) => {
+ const balances: {
+ token: Address
+ market: Address
+ balance: bigint
+ type: string
+ }[] = [
+ {
+ token: baseToken,
+ market: markets[index].address,
+ balance: baseTokenBalance,
+ type: 'Supply',
+ },
+ {
+ token: baseToken,
+ market: markets[index].address,
+ balance: -borrowBalance,
+ type: 'Debt',
+ },
+ ]
+
+ for (const collateral of collaterals) {
+ balances.push({
+ token: collateral.asset,
+ market: markets[index].address,
+ balance: collateral.balance,
+ type: 'Collateral',
+ })
+ }
+
+ const positions: ContractPositionDefinition[] = []
+
+ for (const { token, balance, market, type } of balances) {
+ if (balance === 0n) {
+ continue
+ }
+ positions.push({
+ type: 'contract-position-definition',
+ networkId,
+ address: market.toLowerCase(),
+ extraId: `${token.toLowerCase()}-${type.toLowerCase()}`,
+ tokens: [
+ {
+ address: token.toLowerCase(),
+ networkId,
+ },
+ ],
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const baseTokenDescription =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: baseToken,
+ })
+ ]
+ const tokenDescription =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token,
+ })
+ ]
+ return {
+ title: `${tokenDescription.symbol} ${type}`,
+ description: `${baseTokenDescription.symbol} Market`,
+ imageUrl:
+ 'https://raw.githubusercontent.com/divvi-xyz/hooks/main/src/apps/compound/assets/compound.png',
+ manageUrl: COMPOUND_NETWORK_NAME[networkId]
+ ? `https://app.compound.finance/markets/${baseTokenDescription.symbol}-${COMPOUND_NETWORK_NAME[networkId]}`
+ : undefined,
+ }
+ },
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const decimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token,
+ })
+ ].decimals
+ return [toDecimalNumber(balance, decimals)]
+ },
+ })
+ }
+
+ return positions
+ },
+ )
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/curve/positions.e2e.ts b/src/apps/curve/positions.e2e.ts
new file mode 100644
index 00000000..054ddded
--- /dev/null
+++ b/src/apps/curve/positions.e2e.ts
@@ -0,0 +1,25 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe.each([
+ NetworkId['ethereum-mainnet'],
+ NetworkId['celo-mainnet'],
+ NetworkId['arbitrum-one'],
+])('getPositionDefinitions for networkId %s', (networkId) => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should get definitions successfully when no address is provided', async () => {
+ const positions = await hook.getPositionDefinitions({ networkId, t })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+})
diff --git a/src/apps/curve/positions.test.ts b/src/apps/curve/positions.test.ts
new file mode 100644
index 00000000..8e68fd78
--- /dev/null
+++ b/src/apps/curve/positions.test.ts
@@ -0,0 +1,40 @@
+import { getAllCurvePools } from './positions'
+import { NetworkId } from '../../types/networkId'
+
+describe('curve positions', () => {
+ // note: curve API response is mocked in test/server.ts
+ describe('getAllCurvePools', () => {
+ it('gives empty list for unknown or unsupported network', async () => {
+ const result = await getAllCurvePools('unknown' as NetworkId)
+ expect(result).toEqual([])
+
+ const result2 = await getAllCurvePools(NetworkId['ethereum-sepolia'])
+ expect(result2).toEqual([])
+ })
+ it.each([
+ [
+ NetworkId['celo-mainnet'],
+ [
+ '0x998395fEd908d33CF27115A1D9Ab6555def6cd45',
+ '0x32fD7e563c6521Ab4D59CE3277bcfBe3317CFd63',
+ '0xAF7Ee5Ba02dC9879D24cb16597cd854e13f3aDa8',
+ ],
+ ],
+ [
+ NetworkId['ethereum-mainnet'],
+ [
+ '0x1F71f05CF491595652378Fe94B7820344A551B8E',
+ '0xe7A3b38c39F97E977723bd1239C3470702568e7B',
+ ],
+ ],
+ ])(
+ 'gives list of pools for networkId %s',
+ async (networkId: NetworkId, expectedPoolAddresses) => {
+ const result = await getAllCurvePools(networkId)
+ expect(result.map((pool) => pool.address)).toEqual(
+ expectedPoolAddresses,
+ )
+ },
+ )
+ })
+})
diff --git a/src/apps/curve/positions.ts b/src/apps/curve/positions.ts
new file mode 100644
index 00000000..b2fcc253
--- /dev/null
+++ b/src/apps/curve/positions.ts
@@ -0,0 +1,213 @@
+import { Address, erc20Abi } from 'viem'
+import got from '../../utils/got'
+import {
+ AppTokenPositionDefinition,
+ PositionsHook,
+ TokenDefinition,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import {
+ DecimalNumber,
+ toDecimalNumber,
+ toSerializedDecimalNumber,
+} from '../../types/numbers'
+import { NetworkId } from '../../types/networkId'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+
+// For now, when getting all positions, we only consider the top pools by USD total
+// otherwise we have too many RPC calls, and get rate limited
+// TODO: update the runtime so it can batch call them
+const TOP_POOLS_COUNT = 20
+
+interface CurveApiResponse {
+ success: boolean
+ data: {
+ // this has more fields, but only including fields we use
+ poolData: {
+ address: Address
+ lpTokenAddress: Address
+ totalSupply: string
+ implementation: string
+ coins: {
+ address: Address
+ usdPrice: number | null
+ poolBalance: string
+ decimals: number
+ symbol: symbol
+ isBasePoolLpToken: boolean
+ }[]
+ poolUrls: {
+ swap: string[]
+ deposit: string[]
+ withdraw: string[]
+ }
+ usdTotal: number
+ }[]
+ }
+}
+
+const NETWORK_ID_TO_CURVE_BLOCKCHAIN_ID: Record = {
+ [NetworkId['celo-mainnet']]: 'celo',
+ [NetworkId['ethereum-mainnet']]: 'ethereum',
+ [NetworkId['arbitrum-one']]: 'arbitrum',
+ [NetworkId['op-mainnet']]: 'optimism',
+ [NetworkId['polygon-pos-mainnet']]: 'polygon',
+ [NetworkId['base-mainnet']]: 'base',
+ [NetworkId['celo-alfajores']]: null,
+ [NetworkId['ethereum-sepolia']]: null,
+ [NetworkId['arbitrum-sepolia']]: null,
+ [NetworkId['op-sepolia']]: null,
+ [NetworkId['polygon-pos-amoy']]: null,
+ [NetworkId['base-sepolia']]: null,
+}
+
+export async function getAllCurvePools(
+ networkId: NetworkId,
+): Promise {
+ const blockchainId = NETWORK_ID_TO_CURVE_BLOCKCHAIN_ID[networkId]
+ if (!blockchainId) {
+ return []
+ }
+ const { data } = await got
+ .get(`https://api.curve.fi/v1/getPools/all/${blockchainId}`)
+ .json()
+
+ // Deduplicate pools with the same lpTokenAddress
+ // For some reason Curve API returns the same pool multiple times
+ const lpTokenAddresses = new Set()
+ return data.poolData.filter((pool) => {
+ if (lpTokenAddresses.has(pool.lpTokenAddress)) {
+ return false
+ }
+ lpTokenAddresses.add(pool.lpTokenAddress)
+ return true
+ })
+}
+
+export async function getPoolPositionDefinitions(
+ networkId: NetworkId,
+ address: Address | undefined,
+) {
+ const pools = await getAllCurvePools(networkId)
+
+ let consideredPools = pools
+ if (address) {
+ // call balanceOf to check if user has balance on a pool
+ const client = getClient(networkId)
+ const result = await client.multicall({
+ contracts: pools.map(
+ (pool) =>
+ ({
+ address: pool.lpTokenAddress,
+ abi: erc20Abi,
+ functionName: 'balanceOf',
+ args: [address],
+ }) as const,
+ ),
+ allowFailure: false,
+ })
+
+ consideredPools = pools
+ .map((pool, i) => ({ ...pool, balance: result[i] }))
+ .filter((pool) => pool.balance > 0)
+ } else {
+ consideredPools = consideredPools
+ .sort((a, b) => b.usdTotal - a.usdTotal)
+ .slice(0, TOP_POOLS_COUNT)
+ }
+
+ return await Promise.all(
+ consideredPools.map((pool) => getPoolPositionDefinition(networkId, pool)),
+ )
+}
+
+async function getPoolPositionDefinition(
+ networkId: NetworkId,
+ pool: CurveApiResponse['data']['poolData'][0],
+) {
+ const tokens = pool.coins.map((coin) => ({
+ address: coin.address.toLowerCase(),
+ networkId,
+ fallbackPriceUsd: coin.usdPrice
+ ? toSerializedDecimalNumber(coin.usdPrice)
+ : undefined,
+ }))
+
+ const position: AppTokenPositionDefinition = {
+ type: 'app-token-definition',
+ networkId,
+ address: pool.lpTokenAddress.toLowerCase(),
+ tokens,
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const tokenSymbols = tokens.map(
+ (token) =>
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token.address,
+ })
+ ].symbol,
+ )
+ return {
+ title: tokenSymbols.join(' / '),
+ description: 'Pool',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/curve.png',
+ manageUrl: pool.poolUrls.withdraw[0],
+ }
+ },
+ pricePerShare: async ({ tokensByTokenId }) => {
+ const totalSupply = BigInt(pool.totalSupply)
+ const balances = pool.coins.map((coin) => BigInt(coin.poolBalance))
+ const poolTokenId = getTokenId({
+ address: pool.lpTokenAddress,
+ isNative: false,
+ networkId,
+ })
+ const poolToken = tokensByTokenId[poolTokenId]
+ const underlyingTokens = tokens.map(
+ (token) =>
+ tokensByTokenId[
+ getTokenId({
+ address: token.address,
+ networkId,
+ })
+ ],
+ )
+ const reserves = balances.map((balance, index) =>
+ toDecimalNumber(balance, underlyingTokens[index].decimals),
+ )
+ const supply = toDecimalNumber(totalSupply, poolToken.decimals)
+ const pricePerShare = reserves.map((r) => r.div(supply) as DecimalNumber)
+ return pricePerShare
+ },
+ }
+
+ return position
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Curve',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ return getPoolPositionDefinitions(
+ networkId,
+ address ? (address as Address) : undefined,
+ )
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ // Assume that the address is a pool address
+ const pools = await getAllCurvePools(networkId)
+ const pool = pools.find((pool) => pool.lpTokenAddress === address)
+ if (!pool) {
+ throw new UnknownAppTokenError({ networkId, address })
+ }
+ return await getPoolPositionDefinition(networkId, pool)
+ },
+}
+
+export default hook
diff --git a/src/apps/example/positions.ts b/src/apps/example/positions.ts
new file mode 100644
index 00000000..a0b3a0c9
--- /dev/null
+++ b/src/apps/example/positions.ts
@@ -0,0 +1,86 @@
+import { Address, parseEther } from 'viem'
+import { toDecimalNumber } from '../../types/numbers'
+import { PositionsHook } from '../../types/positions'
+import { NetworkId } from '../../types/networkId'
+
+const CELO_NATIVE_ADDRESS: Address =
+ '0x471ece3750da237f93b8e339c536989b8978a438'
+const CUSD_ADDRESS: Address = '0x765de816845861e75a25fca122bb6898b8b1282a'
+export const DEFAULT_IMG_URL =
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png'
+
+// Example position for developers
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Example',
+ }
+ },
+
+ async getPositionDefinitions({ networkId }) {
+ //
+ // This example pretend position only exists on Celo.
+ //
+ if (networkId !== NetworkId['celo-mainnet']) {
+ return []
+ }
+
+ //
+ // If you're going to query a blockchain, you should use viem. E.g.,
+ //
+ // const client = createPublicClient({
+ // chain: celo,
+ // transport: http(),
+ // })
+ //
+ // If you're going to query other state served over HTTPS, you should use got.
+ //
+
+ //
+ // Some tokens on Celo that compose this example pretend position...
+ //
+ const tokens = [
+ {
+ address: CELO_NATIVE_ADDRESS,
+ networkId,
+ },
+ {
+ address: CUSD_ADDRESS,
+ networkId,
+ },
+ ]
+
+ //
+ // ...and associated balances for tokens above. The hooks interface uses a
+ // special DecimalNumber type to represent balances.
+ //
+ const balances = [
+ toDecimalNumber(parseEther('1'), 18),
+ toDecimalNumber(parseEther('1'), 18),
+ ]
+
+ return [
+ {
+ // Position Hooks type, see https://docs.divvi.xyz/hooks/
+ type: 'contract-position-definition',
+ networkId,
+ // This serves an ID and by convention it should be the contract holding
+ // the underlying position. The runtime passed this addresses to any
+ // shortcut definitions that might execute on this position.
+ address: `0x${'1'.repeat(40)}`,
+ tokens,
+ balances,
+ displayProps: {
+ title: 'Example position',
+ description: 'See the code!',
+ imageUrl: DEFAULT_IMG_URL,
+ // The URL where the user can view and/or manage the position.
+ // If no URL is available it should be set to undefined
+ manageUrl: 'https://example.com/?pool-id',
+ },
+ },
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/gooddollar/abis/identity.ts b/src/apps/gooddollar/abis/identity.ts
new file mode 100644
index 00000000..48da5282
--- /dev/null
+++ b/src/apps/gooddollar/abis/identity.ts
@@ -0,0 +1,125 @@
+// From https://unpkg.com/browse/@gooddollar/goodprotocol@2.0.6/artifacts/abis/IIdentity.min.json
+
+export const identityAbi = [
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ ],
+ name: 'WhitelistedAdded',
+ type: 'event',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'addBlacklisted',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'addIdentityAdmin',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'account', type: 'address' },
+ { internalType: 'string', name: 'did', type: 'string' },
+ ],
+ name: 'addWhitelistedWithDID',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'addrToDID',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'hash', type: 'bytes32' }],
+ name: 'didHashToAddress',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'isBlacklisted',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'isDAOContract',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'isIdentityAdmin',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'isWhitelisted',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'lastAuthenticated',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'removeBlacklisted',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'removeContract',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'removeWhitelisted',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_avatar', type: 'address' }],
+ name: 'setAvatar',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/gooddollar/abis/ubi-scheme.ts b/src/apps/gooddollar/abis/ubi-scheme.ts
new file mode 100644
index 00000000..c8442318
--- /dev/null
+++ b/src/apps/gooddollar/abis/ubi-scheme.ts
@@ -0,0 +1,623 @@
+// From https://unpkg.com/browse/@gooddollar/goodprotocol@2.0.6/artifacts/abis/UBIScheme.min.json
+
+export const ubiSchemeAbi = [
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'ActivatedUser',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'previousAdmin',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'newAdmin',
+ type: 'address',
+ },
+ ],
+ name: 'AdminChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'beacon',
+ type: 'address',
+ },
+ ],
+ name: 'BeaconUpgraded',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newCycleLength',
+ type: 'uint256',
+ },
+ ],
+ name: 'CycleLengthSet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newDay',
+ type: 'uint256',
+ },
+ ],
+ name: 'DaySet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'caller',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'fished_account',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'claimAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'InactiveUserFished',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint8',
+ name: 'version',
+ type: 'uint8',
+ },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'ShouldWithdrawFromDAO',
+ type: 'bool',
+ },
+ ],
+ name: 'ShouldWithdrawFromDAOSet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'total',
+ type: 'uint256',
+ },
+ ],
+ name: 'TotalFished',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'day',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'dailyUbi',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'blockNumber',
+ type: 'uint256',
+ },
+ ],
+ name: 'UBICalculated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'claimer',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'UBIClaimed',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'day',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'pool',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cycleLength',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'dailyUBIPool',
+ type: 'uint256',
+ },
+ ],
+ name: 'UBICycleCalculated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'implementation',
+ type: 'address',
+ },
+ ],
+ name: 'Upgraded',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'prevBalance',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newBalance',
+ type: 'uint256',
+ },
+ ],
+ name: 'WithdrawFromDao',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'activeUsersCount',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'avatar',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_member', type: 'address' }],
+ name: 'checkEntitlement',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'checkEntitlement',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'claim',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ name: 'claimDay',
+ outputs: [
+ { internalType: 'uint256', name: 'amountOfClaimers', type: 'uint256' },
+ { internalType: 'uint256', name: 'claimAmount', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'currentCycleLength',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'currentDay',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'currentDayInCycle',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'cycleLength',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'dailyCyclePool',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ name: 'dailyUBIHistory',
+ outputs: [
+ { internalType: 'bool', name: 'hasWithdrawn', type: 'bool' },
+ { internalType: 'uint256', name: 'openAmount', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'dailyUbi',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'dao',
+ outputs: [
+ { internalType: 'contract Controller', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'estimateNextDailyUBI',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'firstClaimPool',
+ outputs: [
+ { internalType: 'contract IFirstClaimPool', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_account', type: 'address' }],
+ name: 'fish',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address[]', name: '_accounts', type: 'address[]' },
+ ],
+ name: 'fishMulti',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '', type: 'address' }],
+ name: 'fishedUsersAddresses',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'day', type: 'uint256' }],
+ name: 'getClaimAmount',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'day', type: 'uint256' }],
+ name: 'getClaimerCount',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getDailyStats',
+ outputs: [
+ { internalType: 'uint256', name: '', type: 'uint256' },
+ { internalType: 'uint256', name: '', type: 'uint256' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'hasClaimed',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'contract INameService', name: '_ns', type: 'address' },
+ {
+ internalType: 'contract IFirstClaimPool',
+ name: '_firstClaimPool',
+ type: 'address',
+ },
+ { internalType: 'uint256', name: '_maxInactiveDays', type: 'uint256' },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_account', type: 'address' }],
+ name: 'isActiveUser',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_account', type: 'address' }],
+ name: 'isNotNewUser',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'iterationGasLimit',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '', type: 'address' }],
+ name: 'lastClaimed',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'lastWithdrawDay',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'maxInactiveDays',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'minActiveUsers',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'nameService',
+ outputs: [
+ { internalType: 'contract INameService', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'nativeToken',
+ outputs: [
+ { internalType: 'contract IGoodDollar', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bool', name: '_pause', type: 'bool' }],
+ name: 'pause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'paused',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'periodStart',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'proxiableUUID',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: '_activeUserCount', type: 'uint256' },
+ ],
+ name: 'setActiveUserCount',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '_newLength', type: 'uint256' }],
+ name: 'setCycleLength',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'setDay',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bool', name: '_shouldWithdraw', type: 'bool' }],
+ name: 'setShouldWithdrawFromDAO',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bool', name: '_use', type: 'bool' }],
+ name: 'setUseFirstClaimPool',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'shouldWithdrawFromDAO',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'startOfCycle',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '', type: 'address' }],
+ name: 'totalClaimsPerUser',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'updateAvatar',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'newImplementation', type: 'address' },
+ ],
+ name: 'upgradeTo',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'newImplementation', type: 'address' },
+ { internalType: 'bytes', name: 'data', type: 'bytes' },
+ ],
+ name: 'upgradeToAndCall',
+ outputs: [],
+ stateMutability: 'payable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'useFirstClaimPool',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/gooddollar/positions.e2e.ts b/src/apps/gooddollar/positions.e2e.ts
new file mode 100644
index 00000000..7fe82a51
--- /dev/null
+++ b/src/apps/gooddollar/positions.e2e.ts
@@ -0,0 +1,24 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe('getPositionDefinitions', () => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0xb847ea9e017779bf63947ad72cd6bf06407cd2e1',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should return no positions if the user is new', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
+ expect(positions.length).toBe(0)
+ })
+})
diff --git a/src/apps/gooddollar/positions.ts b/src/apps/gooddollar/positions.ts
new file mode 100644
index 00000000..954c2a27
--- /dev/null
+++ b/src/apps/gooddollar/positions.ts
@@ -0,0 +1,126 @@
+import {
+ PositionsHook,
+ ContractPositionDefinition,
+} from '../../types/positions'
+import { Address, createPublicClient, http } from 'viem'
+import { celo } from 'viem/chains'
+import { toDecimalNumber } from '../../types/numbers'
+import { ubiSchemeAbi } from './abis/ubi-scheme'
+import { identityAbi } from './abis/identity'
+import { NetworkId } from '../../types/networkId'
+
+// From https://github.com/GoodDollar/GoodProtocol/blob/b713457581d7cd7148dea9d5107883779442650e/releases/deployment.json#L480C23-L480C65
+const UBI_ADDRESS = '0x43d72Ff17701B2DA814620735C39C620Ce0ea4A1'
+// From https://github.com/GoodDollar/GoodProtocol/blob/b713457581d7cd7148dea9d5107883779442650e/releases/deployment.json#L468
+const IDENTITY_ADDRESS = '0xC361A6E67822a0EDc17D899227dd9FC50BD62F42'
+
+const G$_ADDRESS = '0x62b8b11039fcfe5ab0c56e502b1c372a3d2a9c7a'
+const G$_DECIMALS = 18
+
+const ONE_SECOND_IN_MS = 1000
+const ONE_HOUR_IN_MS = 60 * 60 * ONE_SECOND_IN_MS
+const ONE_DAY_IN_MS = ONE_HOUR_IN_MS * 24
+
+const client = createPublicClient({
+ chain: celo,
+ transport: http(),
+})
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'GoodDollar',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // hook implementation currently hardcoded to Celo mainnet (contract addresses in particular)
+ return []
+ }
+ const ubiContract = {
+ address: UBI_ADDRESS,
+ abi: ubiSchemeAbi,
+ } as const
+
+ const identityContract = {
+ address: IDENTITY_ADDRESS,
+ abi: identityAbi,
+ } as const
+
+ const [isVerified, isNotNewUser, currentDay, periodStart, claimAmount] =
+ await client.multicall({
+ contracts: [
+ {
+ ...identityContract,
+ functionName: 'isWhitelisted',
+ args: [address as Address],
+ },
+ {
+ ...ubiContract,
+ functionName: 'isNotNewUser',
+ args: [address as Address],
+ },
+ {
+ ...ubiContract,
+ functionName: 'currentDay',
+ },
+ {
+ ...ubiContract,
+ functionName: 'periodStart',
+ },
+ {
+ ...ubiContract,
+ functionName: 'checkEntitlement',
+ args: [address as Address],
+ },
+ ],
+ allowFailure: false,
+ })
+
+ // If the user is not verified and is new, they don't have a position
+ // Note: existing users need to re-verify after some time
+ // in that case, they will have a position but we will tell them to re-verify
+ if (!isVerified && !isNotNewUser) {
+ return []
+ }
+
+ let startDate = new Date(
+ Number(periodStart) * 1000 + Number(currentDay) * ONE_DAY_IN_MS,
+ )
+ if (startDate < new Date()) {
+ startDate = new Date(
+ Number(periodStart) * 1000 + Number(currentDay + 1n) * ONE_DAY_IN_MS,
+ )
+ }
+
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: UBI_ADDRESS,
+ tokens: [{ address: G$_ADDRESS, networkId, category: 'claimable' }],
+ availableShortcutIds: ['claim-reward'],
+ displayProps: {
+ title: 'Daily UBI',
+ description: !isVerified
+ ? 'Re-verify on the dapp to claim'
+ : claimAmount > 0n
+ ? 'Claim now'
+ : // Claim in X hours
+ `Claim ${new Intl.RelativeTimeFormat('en', {
+ style: 'long',
+ }).format(
+ Math.ceil((startDate.getTime() - Date.now()) / ONE_HOUR_IN_MS),
+ 'hour',
+ )}`,
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/gooddollar.png',
+ manageUrl: 'https://gooddapp.org/#/claim',
+ },
+ balances: [toDecimalNumber(claimAmount, G$_DECIMALS)],
+ }
+
+ return [position]
+ },
+}
+
+export default hook
diff --git a/src/apps/gooddollar/shortcuts.ts b/src/apps/gooddollar/shortcuts.ts
new file mode 100644
index 00000000..1cda0925
--- /dev/null
+++ b/src/apps/gooddollar/shortcuts.ts
@@ -0,0 +1,60 @@
+import { Address, createPublicClient, http, encodeFunctionData } from 'viem'
+import { celo } from 'viem/chains'
+import { createShortcut, ShortcutsHook } from '../../types/shortcuts'
+import { ubiSchemeAbi } from './abis/ubi-scheme'
+import { NetworkId } from '../../types/networkId'
+import { ZodAddressLowerCased } from '../../types/address'
+
+const client = createPublicClient({
+ chain: celo,
+ transport: http(),
+})
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId, _address?: string) {
+ if (networkId !== NetworkId['celo-mainnet']) {
+ return []
+ }
+
+ return [
+ createShortcut({
+ id: 'claim-reward',
+ name: 'Claim',
+ description: 'Claim daily UBI rewards',
+ networkIds: [NetworkId['celo-mainnet']],
+ category: 'claim',
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address, positionAddress }) {
+ // This isn't strictly needed, but will help while we're developing shortcuts
+ const { request } = await client.simulateContract({
+ address: positionAddress, // This is the ubi contract address
+ abi: ubiSchemeAbi,
+ functionName: 'claim',
+ account: address as Address,
+ })
+
+ const data = encodeFunctionData({
+ abi: request.abi,
+ args: request.args,
+ functionName: request.functionName,
+ })
+
+ return {
+ transactions: [
+ {
+ networkId,
+ from: address,
+ to: positionAddress,
+ data,
+ },
+ ],
+ }
+ },
+ }),
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/halofi/abis/pool-v205.ts b/src/apps/halofi/abis/pool-v205.ts
new file mode 100644
index 00000000..41c60121
--- /dev/null
+++ b/src/apps/halofi/abis/pool-v205.ts
@@ -0,0 +1,1667 @@
+export const poolV205Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '_inboundCurrency',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: '_maxFlexibleSegmentPaymentAmount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint64',
+ name: '_depositCount',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: '_segmentLength',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: '_waitingRoundSegmentLength',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint256',
+ name: '_segmentPayment',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint64',
+ name: '_earlyWithdrawalFee',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: '_customFee',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: '_maxPlayersCount',
+ type: 'uint64',
+ },
+ {
+ internalType: 'bool',
+ name: '_flexibleSegmentPayment',
+ type: 'bool',
+ },
+ {
+ internalType: 'contract IStrategy',
+ name: '_strategy',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: '_isTransactionalToken',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ inputs: [],
+ name: 'ADMIN_FEE_WITHDRAWN',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'DEPOSIT_NOT_ALLOWED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'EARLY_EXIT_NOT_POSSIBLE',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'GAME_ALREADY_INITIALIZED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'GAME_ALREADY_STARTED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'GAME_COMPLETED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'GAME_NOT_COMPLETED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'GAME_NOT_INITIALIZED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_CUSTOM_FEE',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_DEPOSIT_COUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_EARLY_WITHDRAW_FEE',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_FLEXIBLE_AMOUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_INBOUND_TOKEN',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_INCENTIVE_TOKEN',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_MAX_FLEXIBLE_AMOUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_MAX_PLAYER_COUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_NET_DEPOSIT_AMOUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_OWNER',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_SEGMENT_LENGTH',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_SEGMENT_PAYMENT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_STRATEGY',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_TRANSACTIONAL_TOKEN_AMOUNT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_TRANSACTIONAL_TOKEN_SENDER',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'INVALID_WAITING_ROUND_SEGMENT_LENGTH',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'MAX_PLAYER_COUNT_REACHED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'NOT_PLAYER',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_ALREADY_JOINED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_ALREADY_PAID_IN_CURRENT_SEGMENT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_ALREADY_WITHDREW',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_ALREADY_WITHDREW_EARLY',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_DID_NOT_PAID_PREVIOUS_SEGMENT',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'PLAYER_DOES_NOT_EXIST',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'RENOUNCE_OWNERSHIP_NOT_ALLOWED',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'TOKEN_TRANSFER_FAILURE',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'TRANSACTIONAL_TOKEN_TRANSFER_FAILURE',
+ type: 'error',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'adminFeeAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'AdminFee',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'admin',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGameInterest',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'adminIncentiveAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'adminFeeAmounts',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'AdminWithdrawal',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'currentSegment',
+ type: 'uint64',
+ },
+ ],
+ name: 'ClaimRewardTokensDisabled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'segment',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'netAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'playerIndex',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cumulativePlayerIndexSum',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalWinnerDepositsPerSegment',
+ type: 'uint256',
+ },
+ ],
+ name: 'Deposit',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGamePrincipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'netTotalGamePrincipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'depositedAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'depositedNetAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cumulativePlayerIndexSum',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalWinnerDepositsPerSegment',
+ type: 'uint256',
+ },
+ ],
+ name: 'EarlyWithdrawal',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'currentSegment',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'oldFee',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'newFee',
+ type: 'uint64',
+ },
+ ],
+ name: 'EarlyWithdrawalFeeChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'currentSegment',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'winnerCount',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'depositRoundInterestSharePercentage',
+ type: 'uint64',
+ },
+ ],
+ name: 'EmergencyWithdrawalEnabled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalBalance',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGamePrincipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'netTotalGamePricipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGameInterest',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'grossRewardTokenAmount',
+ type: 'uint256[]',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalIncentiveAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'impermanentLossShare',
+ type: 'uint256',
+ },
+ ],
+ name: 'EndGameStats',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bytes',
+ name: 'reason',
+ type: 'bytes',
+ },
+ ],
+ name: 'ExternalTokenGetBalanceError',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bytes',
+ name: 'reason',
+ type: 'bytes',
+ },
+ ],
+ name: 'ExternalTokenTransferError',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ ],
+ name: 'IncentiveTokenSet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'firstSegmentStart',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'waitingRoundSegmentStart',
+ type: 'uint64',
+ },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'netAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'playerIndex',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cumulativePlayerIndexSum',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalWinnerDepositsPerSegment',
+ type: 'uint256',
+ },
+ ],
+ name: 'JoinedGame',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'previousOwner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'Paused',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'Unpaused',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalBalance',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGamePrincipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'netTotalGamePrincipal',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalGameInterest',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalIncentiveAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'totalRewardAmounts',
+ type: 'uint256[]',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'impermanentLossShare',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cumulativePlayerIndexSum',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalWinnerDepositsPerSegment',
+ type: 'uint256',
+ },
+ ],
+ name: 'UpdateGameStats',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'WithdrawInboundTokens',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'WithdrawIncentiveToken',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'player',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'amounts',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'WithdrawRewardTokens',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'MULTIPLIER',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'activePlayersCount',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adminFee',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'adminFeeAmount',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adminFeeSet',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'adminWithdraw',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'allowRenouncingOwnership',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'cumulativePlayerIndexSum',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'depositCount',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'depositRoundInterestSharePercentage',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'disableRewardTokenClaim',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'earlyWithdrawalFee',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'emergencyWithdraw',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'firstSegmentStart',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'flexibleSegmentPayment',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'impermanentLossShare',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'inboundToken',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'incentiveToken',
+ outputs: [
+ {
+ internalType: 'contract IERC20',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'isTransactionalToken',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'iterablePlayers',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'maxFlexibleSegmentPaymentAmount',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'maxPlayersCount',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'netTotalGamePrincipal',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'paused',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'playerIndex',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'players',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: 'withdrawn',
+ type: 'bool',
+ },
+ {
+ internalType: 'bool',
+ name: 'canRejoin',
+ type: 'bool',
+ },
+ {
+ internalType: 'bool',
+ name: 'isWinner',
+ type: 'bool',
+ },
+ {
+ internalType: 'address',
+ name: 'addr',
+ type: 'address',
+ },
+ {
+ internalType: 'uint64',
+ name: 'withdrawalSegment',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: 'mostRecentSegmentPaid',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amountPaid',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'netAmountPaid',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'depositAmount',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'rewardTokenAmounts',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'rewardTokens',
+ outputs: [
+ {
+ internalType: 'contract IERC20',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'segmentCounter',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'segmentLength',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'segmentPayment',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'strategy',
+ outputs: [
+ {
+ internalType: 'contract IStrategy',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalGameInterest',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalGamePrincipal',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalIncentiveAmount',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'totalWinnerDepositsPerSegment',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'waitingRoundSegmentLength',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'waitingRoundSegmentStart',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'winnerCount',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'winnersLeftToWithdraw',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ stateMutability: 'payable',
+ type: 'receive',
+ },
+ {
+ inputs: [],
+ name: 'isGameCompleted',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '_player',
+ type: 'address',
+ },
+ ],
+ name: 'isWinner',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getNumberOfPlayers',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getCurrentSegment',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'isInitialized',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IERC20',
+ name: '_incentiveToken',
+ type: 'address',
+ },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'enableEmergencyWithdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IERC20',
+ name: '_incentiveToken',
+ type: 'address',
+ },
+ ],
+ name: 'setIncentiveToken',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'disableClaimingRewardTokens',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'pause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'unpause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'unlockRenounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'renounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint64',
+ name: '_newEarlyWithdrawFee',
+ type: 'uint64',
+ },
+ ],
+ name: 'lowerEarlyWithdrawFee',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_minAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'adminFeeWithdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_minAmount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '_depositAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'joinGame',
+ outputs: [],
+ stateMutability: 'payable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_minAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'earlyWithdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_minAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'withdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_minAmount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '_depositAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'makeDeposit',
+ outputs: [],
+ stateMutability: 'payable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/halofi/haloFiApi.ts b/src/apps/halofi/haloFiApi.ts
new file mode 100644
index 00000000..ef937a5a
--- /dev/null
+++ b/src/apps/halofi/haloFiApi.ts
@@ -0,0 +1,80 @@
+import got from '../../utils/got'
+import { celo } from 'viem/chains'
+
+type Game = {
+ strategyController: string
+ displayId: number
+ networkId: string
+ depositToken: string
+ liquidityToken: string
+ gameName: string
+ subgraphId: string
+ roundMeasure: string
+ contractVersion: string
+ isCapped: boolean
+ maxPlayers: string
+ strategyProvider: string
+ paymentAmount: string
+ isWhitelisted: boolean
+ isHidden: boolean
+ ggScore: number
+ gameNameShort: string
+ description: string
+ payments: string
+ riskProfile: string
+ proposer: string
+ calenderUrl: string
+ blogPostUri: string
+ id: string
+ gameStartsAt: string
+ segmentLength: string
+ paymentCount: string
+ totalSegmentCount: string
+ waitingRoundStartsAt: string
+ waitingRoundLength: string
+ earlyWithdrawalFee: string
+ performanceFee: string
+ maxDepositAmount: string
+ tags?: string[]
+ liquidityTokenAddress: string
+ depositTokenAddress: string
+ depositType: string
+ mechanismType: string
+ gameEndsAt: string
+ gameClosesAt: string
+ rewards?: Reward[]
+ currentSegment: string
+ isCompleted: boolean
+}
+
+type Reward = {
+ tokenId: string
+ address: string
+ type: string
+}
+
+export type APIGamesResponse = Record
+
+// User-Agent header is required by the HaloFi API
+const API_USER_AGENT =
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)'
+
+export async function getCompatibleGamesFromAPI(): Promise {
+ const [games] = await Promise.all([
+ got
+ .get('https://goodghosting-api.com/v1/games', {
+ headers: { 'User-Agent': API_USER_AGENT },
+ })
+ .json(),
+ ])
+
+ const compatibleGames = Object.values(games).filter((game) => {
+ const isV2Game = game.contractVersion.startsWith('2.0')
+ const isCeloGame = Number(game.networkId) === celo.id
+ const hasDepositToken = Boolean(game.depositTokenAddress)
+
+ return isV2Game && isCeloGame && hasDepositToken
+ })
+
+ return compatibleGames
+}
diff --git a/src/apps/halofi/haloFiContract.ts b/src/apps/halofi/haloFiContract.ts
new file mode 100644
index 00000000..09ddeaae
--- /dev/null
+++ b/src/apps/halofi/haloFiContract.ts
@@ -0,0 +1,33 @@
+import { Address, createPublicClient, http } from 'viem'
+import { celo } from 'viem/chains'
+import { poolV205Abi } from './abis/pool-v205'
+
+const client = createPublicClient({
+ chain: celo,
+ transport: http(),
+})
+
+export async function getPlayerStructFromGames(
+ games: Address[],
+ playerAddress: Address,
+) {
+ const contractsCalls = games.map((address) => ({
+ address: address,
+ abi: poolV205Abi,
+ functionName: 'players' as const,
+ args: [playerAddress] as readonly [Address],
+ }))
+
+ const haloFiPlayerStructs = await client.multicall({
+ contracts: contractsCalls,
+ allowFailure: false,
+ })
+
+ return haloFiPlayerStructs
+}
+
+export const PlayerStructIndex = {
+ netAmountPaid: 7,
+ playerAddress: 3,
+ withdrawn: 0,
+} as const
diff --git a/src/apps/halofi/positions.e2e.ts b/src/apps/halofi/positions.e2e.ts
deleted file mode 100644
index e2ca6388..00000000
--- a/src/apps/halofi/positions.e2e.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import hook from './positions'
-
-describe('getPositionDefinitions', () => {
- it('should get the address definitions successfully', async () => {
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
- // Simple check to make sure we got some definitions
- expect(positions.length).toBeGreaterThan(0)
- })
-})
diff --git a/src/apps/halofi/positions.ts b/src/apps/halofi/positions.ts
index a4498c33..4bb7eecf 100644
--- a/src/apps/halofi/positions.ts
+++ b/src/apps/halofi/positions.ts
@@ -1,168 +1,84 @@
-import BigNumber from 'bignumber.js'
-import { DecimalNumber } from '../../types/numbers'
import {
- PositionsHook,
ContractPositionDefinition,
- TokenDefinition,
+ PositionsHook,
} from '../../types/positions'
-import got from 'got'
-
-// User-Agent header is required by the HaloFi API
-const USER_AGENT =
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)'
-
-type PlayerGameResponse = {
- playerId: string
- gameId: string
- mostRecentSegmentPaid: number
- paidAmount: string
- netPaidAmount: string
- withdrawn: boolean
- withdrawalSegment: number
- canRejoin: boolean
- isWinner: boolean
- isWaiting: boolean
- gameStartsAt: string
- waitingRoundStartsAt: string
- segmentLength: string
- waitingRoundLength: string
- totalSegmentCount: string
- paymentCount: string
- currentSegment: string
- isGameCompleted: boolean
- gameAPY: string
- totalEarningsConverted: string
- playerTotalEarningsConverted: string
- rewards?: RewardBalance[]
- interestAmount: string
-}
-
-type RewardBalance = {
- tokenId: string
- address: string
- type: string
- balance: string
- convertedBalance: string
-}
+import { Address, zeroAddress } from 'viem'
-type GamesResponse = Record<
- string,
- {
- strategyController: string
- displayId: number
- networkId: string
- depositToken: string
- liquidityToken: string
- gameName: string
- subgraphId: string
- roundMeasure: string
- contractVersion: string
- isCapped: boolean
- maxPlayers: string
- strategyProvider: string
- paymentAmount: string
- isWhitelisted: boolean
- isHidden: boolean
- ggScore: number
- gameNameShort: string
- description: string
- payments: string
- riskProfile: string
- proposer: string
- calenderUrl: string
- blogPostUri: string
- id: string
- gameStartsAt: string
- segmentLength: string
- paymentCount: string
- totalSegmentCount: string
- waitingRoundStartsAt: string
- waitingRoundLength: string
- earlyWithdrawalFee: string
- performanceFee: string
- maxDepositAmount: string
- tags?: string[]
- liquidityTokenAddress: string
- depositTokenAddress: string
- depositType: string
- mechanismType: string
- gameEndsAt: string
- gameClosesAt: string
- rewards?: Reward[]
- currentSegment: string
- isCompleted: boolean
- }
->
-
-type Reward = {
- tokenId: string
- address: string
- type: string
-}
+import { toDecimalNumber } from '../../types/numbers'
+import { getCompatibleGamesFromAPI } from './haloFiApi'
+import { PlayerStructIndex, getPlayerStructFromGames } from './haloFiContract'
+import { NetworkId } from '../../types/networkId'
+import { getTokenId } from '../../runtime/getTokenId'
const hook: PositionsHook = {
getInfo() {
return {
- id: 'halofi',
name: 'HaloFi',
- description: '',
}
},
- async getPositionDefinitions(network, address) {
- const [games, playerGames] = await Promise.all([
- got
- .get('https://goodghosting-api.com/v1/games', {
- headers: { 'User-Agent': USER_AGENT },
- })
- .json(),
- got
- .get('https://goodghosting-api.com/v1/players/active-games', {
- searchParams: {
- networkId: 42220, // Celo mainnet
- playerAddress: address,
- },
- headers: { 'User-Agent': USER_AGENT },
- })
- .json(),
- ])
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // dapp is only on Celo, and implementation is hardcoded to Celo mainnet (contract addresses in particular)
+ return []
+ }
+ const compatibleGames = await getCompatibleGamesFromAPI()
- // console.log({ games, playerGames })
+ const contractAddressList = compatibleGames.map(
+ (game) => game.id as Address,
+ )
+ const haloFiGamesPlayerHasJoined = await getPlayerStructFromGames(
+ contractAddressList,
+ address as Address,
+ ).then((structs) =>
+ structs
+ .map((playerStruct, index) => ({
+ playerStruct,
+ game: compatibleGames[index],
+ }))
+ .filter(
+ ({ playerStruct }) =>
+ playerStruct[PlayerStructIndex.playerAddress] !== zeroAddress,
+ )
+ .filter(
+ ({ playerStruct }) =>
+ playerStruct[PlayerStructIndex.withdrawn] === false,
+ ),
+ )
+
+ return haloFiGamesPlayerHasJoined.map(({ playerStruct, game }) => {
+ const depositTokenAddress = game.depositTokenAddress.toLowerCase()
- return playerGames.map((playerGame) => {
- const game = games[playerGame.gameId]
- const rewards = playerGame.rewards ?? []
const position: ContractPositionDefinition = {
type: 'contract-position-definition',
- network,
+ networkId,
address: game.id.toLowerCase(),
- tokens: [
- { address: game.depositTokenAddress.toLowerCase(), network },
- ...rewards.map((reward) => ({
- address: reward.address.toLowerCase(),
- network,
- })),
- ],
+ tokens: [{ address: depositTokenAddress, networkId }],
displayProps: {
title: game.gameNameShort,
description: 'Challenge',
imageUrl:
'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/halofi.png',
+ manageUrl: undefined,
},
- balances: async () => {
- return [
- playerGame.paidAmount,
- // Some of these are claimable rewards
- ...rewards.map((reward) => reward.balance),
- ].map((value) => new BigNumber(value) as DecimalNumber)
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const depositToken =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: depositTokenAddress,
+ networkId,
+ })
+ ]
+
+ const playerAmountPaid = toDecimalNumber(
+ playerStruct[PlayerStructIndex.netAmountPaid],
+ depositToken.decimals,
+ )
+ return [playerAmountPaid]
},
}
return position
})
},
- getAppTokenDefinition(_context: TokenDefinition) {
- // We don't need this for now, since there are no intermediary tokens
- throw new Error('Not implemented')
- },
}
export default hook
diff --git a/src/apps/hedgey/abis/token-vesting-plans.ts b/src/apps/hedgey/abis/token-vesting-plans.ts
new file mode 100644
index 00000000..9b72ae83
--- /dev/null
+++ b/src/apps/hedgey/abis/token-vesting-plans.ts
@@ -0,0 +1,1298 @@
+export const tokenVestingPlansAbi = [
+ {
+ inputs: [
+ {
+ internalType: 'string',
+ name: 'name',
+ type: 'string',
+ },
+ {
+ internalType: 'string',
+ name: 'symbol',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'approved',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'ApprovalForAll',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'ApprovalForAllDelegation',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ ],
+ name: 'DelegateRemoved',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'delegator',
+ type: 'address',
+ },
+ ],
+ name: 'DelegatorApproved',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'recipient',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'start',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cliff',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'end',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'rate',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'period',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'vestingAdmin',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'adminTransferOBO',
+ type: 'bool',
+ },
+ ],
+ name: 'PlanCreated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amountRedeemed',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'planRemainder',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'resetDate',
+ type: 'uint256',
+ },
+ ],
+ name: 'PlanRedeemed',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amountRedeemed',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'revokedAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'PlanRevoked',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ ],
+ name: 'PlanTransferredByVestingAdmin',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'transferable',
+ type: 'bool',
+ },
+ ],
+ name: 'PlanVestingAdminTransferToggle',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ ],
+ name: 'TokenDelegated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_admin',
+ type: 'address',
+ },
+ ],
+ name: 'URIAdminDeleted',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'string',
+ name: 'newURI',
+ type: 'string',
+ },
+ ],
+ name: 'URISet',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_newVestingAdmin',
+ type: 'address',
+ },
+ ],
+ name: 'VestingPlanAdminChanged',
+ type: 'event',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'approve',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'delegator',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ ],
+ name: 'approveDelegator',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ ],
+ name: 'approveSpenderDelegator',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ ],
+ name: 'balanceOfDelegate',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'baseURI',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'newVestingAdmin',
+ type: 'address',
+ },
+ ],
+ name: 'changeVestingPlanAdmin',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'recipient',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'start',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'cliff',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'rate',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'period',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'vestingAdmin',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'adminTransferOBO',
+ type: 'bool',
+ },
+ ],
+ name: 'createPlan',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'newPlanId',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'delegatee',
+ type: 'address',
+ },
+ ],
+ name: 'delegate',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'delegatee',
+ type: 'address',
+ },
+ ],
+ name: 'delegateAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'planIds',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'address[]',
+ name: 'delegatees',
+ type: 'address[]',
+ },
+ ],
+ name: 'delegatePlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'delegatee',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ ],
+ name: 'delegatedBalances',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'delegatedBalance',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'delegatedTo',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'deleteAdmin',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'planIds',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'uint256',
+ name: 'revokeTime',
+ type: 'uint256',
+ },
+ ],
+ name: 'futureRevokePlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'getApproved',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ ],
+ name: 'getApprovedDelegator',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ ],
+ name: 'isApprovedForAll',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ ],
+ name: 'isApprovedForAllDelegation',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'holder',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ ],
+ name: 'lockedBalances',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'lockedBalance',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'ownerOf',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'planIds',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'uint256',
+ name: 'redemptionTime',
+ type: 'uint256',
+ },
+ ],
+ name: 'partialRedeemPlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'timeStamp',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'redemptionTime',
+ type: 'uint256',
+ },
+ ],
+ name: 'planBalanceOf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'balance',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'remainder',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'latestUnlock',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ ],
+ name: 'planEnd',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'end',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'plans',
+ outputs: [
+ {
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'start',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'cliff',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'rate',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'period',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'vestingAdmin',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'adminTransferOBO',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'redeemAllPlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'planIds',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'redeemPlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'planIds',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'revokePlans',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'safeTransferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'bytes',
+ name: 'data',
+ type: 'bytes',
+ },
+ ],
+ name: 'safeTransferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'setApprovalForAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'setApprovalForAllDelegation',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'approved',
+ type: 'bool',
+ },
+ ],
+ name: 'setApprovalForOperator',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'bytes4',
+ name: 'interfaceId',
+ type: 'bytes4',
+ },
+ ],
+ name: 'supportsInterface',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'planId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'bool',
+ name: 'transferrable',
+ type: 'bool',
+ },
+ ],
+ name: 'toggleAdminTransferOBO',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'tokenByIndex',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'tokenOfDelegateByIndex',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'tokenOfOwnerByIndex',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'tokenURI',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'transferFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'string',
+ name: '_uri',
+ type: 'string',
+ },
+ ],
+ name: 'updateBaseURI',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/hedgey/config.ts b/src/apps/hedgey/config.ts
new file mode 100644
index 00000000..f8027566
--- /dev/null
+++ b/src/apps/hedgey/config.ts
@@ -0,0 +1,10 @@
+// TODO(sbw): there's others we need to add
+// https://github.com/hedgey-finance/Locked_VestingTokenPlans#mainnet-deployments
+export const hedgeyContractNames: Record = {
+ '0xd240f76c57fb18196a864b8b06e9b168c98c4524': 'Vesting Plan',
+ '0x2cde9919e81b20b4b33dd562a48a84b54c48f00c': 'Vesting Plan',
+}
+
+// TODO(sbw): not sure what the right default image URL should be
+export const hedgeyDefaultImageUrl =
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png'
diff --git a/src/apps/hedgey/nfts.ts b/src/apps/hedgey/nfts.ts
new file mode 100644
index 00000000..53613d2c
--- /dev/null
+++ b/src/apps/hedgey/nfts.ts
@@ -0,0 +1,55 @@
+import got from '../../utils/got'
+import { hedgeyContractNames } from './config'
+
+interface Nft {
+ contractAddress: string
+ tokenId: string
+ metadata?: {
+ image: string
+ }
+ media: {
+ raw: string
+ gateway: string
+ }[]
+}
+
+export async function getHedgeyPlanNfts({
+ address,
+ contractAddresses,
+}: {
+ address: string
+ contractAddresses?: Set
+}) {
+ contractAddresses =
+ contractAddresses ?? new Set(Object.keys(hedgeyContractNames))
+
+ const pagination = got.paginate(
+ 'https://api.mainnet.valora.xyz/getNfts',
+ {
+ searchParams: { address },
+ pagination: {
+ transform: (response) => {
+ return JSON.parse(response.body as string).result
+ },
+ paginate: (response) => {
+ const pageKey = JSON.parse(response.body as string).pageKey
+ if (pageKey) {
+ return {
+ searchParams: { address, pageKey },
+ }
+ }
+ return false
+ },
+ },
+ },
+ )
+
+ const result: Nft[] = []
+ for await (const nft of pagination) {
+ if (contractAddresses.has(nft.contractAddress)) {
+ result.push(nft)
+ }
+ }
+
+ return result
+}
diff --git a/src/apps/hedgey/positions.e2e.ts b/src/apps/hedgey/positions.e2e.ts
new file mode 100644
index 00000000..81f73723
--- /dev/null
+++ b/src/apps/hedgey/positions.e2e.ts
@@ -0,0 +1,15 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe('getPositionDefinitions', () => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+})
diff --git a/src/apps/hedgey/positions.ts b/src/apps/hedgey/positions.ts
new file mode 100644
index 00000000..71bdf78d
--- /dev/null
+++ b/src/apps/hedgey/positions.ts
@@ -0,0 +1,106 @@
+import { Address } from 'viem'
+import { toDecimalNumber } from '../../types/numbers'
+import {
+ ContractPositionDefinition,
+ PositionsHook,
+} from '../../types/positions'
+import { hedgeyContractNames, hedgeyDefaultImageUrl } from './config'
+import { erc20Abi } from '../../abis/erc-20'
+import { tokenVestingPlansAbi } from './abis/token-vesting-plans'
+import { getHedgeyPlanNfts } from './nfts'
+import { NetworkId } from '../../types/networkId'
+import { getClient } from '../../runtime/client'
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Hedgey',
+ }
+ },
+
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // hook implementation currently hardcoded to Celo mainnet (nft addresses in particular)
+ return []
+ }
+ const planNfts = await getHedgeyPlanNfts({ address })
+ const now = BigInt(Math.floor(new Date().getTime() / 1000))
+ const client = getClient(networkId)
+ const positions: ContractPositionDefinition[] = await Promise.all(
+ planNfts.map(async (planNft) => {
+ const tokenVestingPlanContract = {
+ address: planNft.contractAddress as Address,
+ abi: tokenVestingPlansAbi,
+ }
+ const planId = planNft.tokenId
+ const [planBalanceOfResult, plansResult] = await client.multicall({
+ contracts: [
+ {
+ ...tokenVestingPlanContract,
+ functionName: 'planBalanceOf',
+ args: [BigInt(planId), now, now],
+ },
+ {
+ ...tokenVestingPlanContract,
+ functionName: 'plans',
+ args: [BigInt(planId)],
+ },
+ ],
+ allowFailure: false,
+ })
+
+ const tokenAddress = plansResult[0].toLowerCase() as Address
+ const [tokenDecimals, tokenSymbol] = await client.multicall({
+ contracts: [
+ {
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'decimals',
+ },
+ {
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'symbol',
+ },
+ ],
+ allowFailure: false,
+ })
+
+ const balance = toDecimalNumber(planBalanceOfResult[0], tokenDecimals)
+ const remainder = toDecimalNumber(planBalanceOfResult[1], tokenDecimals)
+ const contractName = hedgeyContractNames[planNft.contractAddress]
+
+ const imageUrl =
+ planNft.media.find((media) => media.raw === planNft.metadata?.image)
+ ?.gateway ?? hedgeyDefaultImageUrl
+
+ return {
+ type: 'contract-position-definition',
+ networkId,
+ address: planNft.contractAddress,
+ extraId: planNft.tokenId,
+ tokens: [{ address: tokenAddress, networkId, category: 'claimable' }],
+ availableShortcutIds: [
+ `${planNft.contractAddress}:${planNft.tokenId}`,
+ ],
+ balances: [balance],
+ displayProps: {
+ title: `${tokenSymbol} ${contractName} ${planId}`,
+ description: `Claim ${balance.dp(2)} ${tokenSymbol} (${remainder.dp(
+ 2,
+ )} unvested)`,
+ imageUrl,
+ manageUrl: 'https://app.hedgey.finance',
+ },
+ }
+ }),
+ )
+ return positions
+ },
+
+ async getAppTokenDefinition(_) {
+ throw new Error('Not implemented')
+ },
+}
+
+export default hook
diff --git a/src/apps/hedgey/shortcuts.e2e.ts b/src/apps/hedgey/shortcuts.e2e.ts
new file mode 100644
index 00000000..18baeb97
--- /dev/null
+++ b/src/apps/hedgey/shortcuts.e2e.ts
@@ -0,0 +1,32 @@
+import hook from './shortcuts'
+import { NetworkId } from '../../types/networkId'
+
+const POSITION_ADDRESS = '0x2cde9919e81b20b4b33dd562a48a84b54c48f00c'
+
+describe('getShortcutDefinitions', () => {
+ it('should get the address definitions successfully', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['celo-mainnet'],
+ '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ )
+ expect(shortcuts.length).toBeGreaterThan(0)
+ })
+
+ describe('.onTrigger', () => {
+ it('should return a Transaction', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['celo-mainnet'],
+ '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ )
+ const shortcut = shortcuts[0]
+
+ const { transactions } = await shortcut.onTrigger({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ positionAddress: POSITION_ADDRESS,
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+})
diff --git a/src/apps/hedgey/shortcuts.ts b/src/apps/hedgey/shortcuts.ts
new file mode 100644
index 00000000..f22ec1df
--- /dev/null
+++ b/src/apps/hedgey/shortcuts.ts
@@ -0,0 +1,64 @@
+import { Address, createPublicClient, http, encodeFunctionData } from 'viem'
+import { celo } from 'viem/chains'
+import { createShortcut, ShortcutsHook } from '../../types/shortcuts'
+import { getHedgeyPlanNfts } from './nfts'
+import { tokenVestingPlansAbi } from './abis/token-vesting-plans'
+import { NetworkId } from '../../types/networkId'
+import { ZodAddressLowerCased } from '../../types/address'
+
+const client = createPublicClient({
+ chain: celo,
+ transport: http(),
+})
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId, address?: string) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ return []
+ }
+
+ const planNfts = await getHedgeyPlanNfts({ address })
+
+ return planNfts.map((planNft) =>
+ createShortcut({
+ id: `${planNft.contractAddress}:${planNft.tokenId}`,
+ name: 'Claim',
+ description: 'Claim vested rewards',
+ networkIds: [NetworkId['celo-mainnet']],
+ category: 'claim',
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address, positionAddress }) {
+ // positionAddress === planNft.contractAddress
+ const { request } = await client.simulateContract({
+ address: positionAddress,
+ abi: tokenVestingPlansAbi,
+ functionName: 'redeemPlans',
+ args: [[BigInt(planNft.tokenId)]],
+ account: address as Address,
+ })
+
+ const data = encodeFunctionData({
+ abi: request.abi,
+ args: request.args,
+ functionName: request.functionName,
+ })
+
+ return {
+ transactions: [
+ {
+ networkId,
+ from: address,
+ to: positionAddress as Address,
+ data,
+ },
+ ],
+ }
+ },
+ }),
+ )
+ },
+}
+
+export default hook
diff --git a/src/apps/locked-celo/positions.e2e.ts b/src/apps/locked-celo/positions.e2e.ts
index e2ca6388..81f73723 100644
--- a/src/apps/locked-celo/positions.e2e.ts
+++ b/src/apps/locked-celo/positions.e2e.ts
@@ -1,11 +1,14 @@
import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
describe('getPositionDefinitions', () => {
it('should get the address definitions successfully', async () => {
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
// Simple check to make sure we got some definitions
expect(positions.length).toBeGreaterThan(0)
})
diff --git a/src/apps/locked-celo/positions.test.ts b/src/apps/locked-celo/positions.test.ts
index 242815b8..2235a088 100644
--- a/src/apps/locked-celo/positions.test.ts
+++ b/src/apps/locked-celo/positions.test.ts
@@ -1,4 +1,6 @@
import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
jest.mock('viem', () => ({
...jest.requireActual('viem'),
@@ -15,10 +17,11 @@ describe('getPositionDefinitions', () => {
12n * 10n ** 18n, // 12 locked celo
[[], []], // pending withdrawals
])
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
expect(positions.length).toBe(1)
})
@@ -28,10 +31,11 @@ describe('getPositionDefinitions', () => {
0n, // 0 locked celo
[[], []], // pending withdrawals
])
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
expect(positions.length).toBe(0)
})
diff --git a/src/apps/locked-celo/positions.ts b/src/apps/locked-celo/positions.ts
index 527b1b12..dd14a0fd 100644
--- a/src/apps/locked-celo/positions.ts
+++ b/src/apps/locked-celo/positions.ts
@@ -11,6 +11,7 @@ import {
import { celo } from 'viem/chains'
import { LockedGoldAbi } from './abis/locked-gold'
import { toDecimalNumber } from '../../types/numbers'
+import { NetworkId } from '../../types/networkId'
const CELO_ADDRESS = '0x471ece3750da237f93b8e339c536989b8978a438'
const LOCKED_GOLD_ADDRESS = '0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e'
@@ -39,12 +40,14 @@ function zip(as: readonly A[], bs: readonly B[]) {
const hook: PositionsHook = {
getInfo() {
return {
- id: 'locked-celo',
name: 'Locked CELO',
- description: '',
}
},
- async getPositionDefinitions(network, address) {
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // dapp is only on Celo and hook implementation is hardcoded to Celo mainnet (contract addresses in particular)
+ return []
+ }
const lockedGoldContract = {
address: LOCKED_GOLD_ADDRESS,
abi: LockedGoldAbi,
@@ -102,14 +105,15 @@ const hook: PositionsHook = {
const position: ContractPositionDefinition = {
type: 'contract-position-definition',
- network,
+ networkId,
address: LOCKED_GOLD_ADDRESS,
- tokens: [{ address: CELO_ADDRESS, network }],
+ tokens: [{ address: CELO_ADDRESS, networkId }],
displayProps: {
title: 'Locked CELO',
description: '', // TODO
imageUrl:
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
},
balances: async () => {
return [toDecimalNumber(totalCelo, CELO_DECIMALS)]
@@ -118,10 +122,6 @@ const hook: PositionsHook = {
return [position]
},
- getAppTokenDefinition() {
- // We don't need this for now, since there are no intermediary tokens
- throw new Error('Not implemented')
- },
}
export default hook
diff --git a/src/apps/mento/abis/airdrop.ts b/src/apps/mento/abis/airdrop.ts
new file mode 100644
index 00000000..29c0dfab
--- /dev/null
+++ b/src/apps/mento/abis/airdrop.ts
@@ -0,0 +1,377 @@
+// From https://github.com/mento-protocol/airgrab-interface/blob/c1716d82d0fed318773ca0ee10f66c801e13e197/src/abis/Airdrop.ts
+
+export const airdropAbi = [
+ {
+ inputs: [
+ {
+ internalType: 'bytes32',
+ name: 'root_',
+ type: 'bytes32',
+ },
+ {
+ internalType: 'address',
+ name: 'fractalSigner_',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'fractalMaxAge_',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'lockingContract_',
+ type: 'address',
+ },
+ {
+ internalType: 'address payable',
+ name: 'treasury_',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'endTimestamp_',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint32',
+ name: 'cliffPeriod_',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'slopePeriod_',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'previousOwner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'claimer',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'lockId',
+ type: 'uint256',
+ },
+ ],
+ name: 'TokensClaimed',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'token',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'TokensDrained',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'MAX_CLIFF_PERIOD',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_SLOPE_PERIOD',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint96',
+ name: 'amount',
+ type: 'uint96',
+ },
+ {
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ internalType: 'bytes32[]',
+ name: 'merkleProof',
+ type: 'bytes32[]',
+ },
+ {
+ internalType: 'bytes',
+ name: 'fractalProof',
+ type: 'bytes',
+ },
+ {
+ internalType: 'uint256',
+ name: 'fractalProofValidUntil',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'fractalProofApprovedAt',
+ type: 'uint256',
+ },
+ {
+ internalType: 'string',
+ name: 'fractalId',
+ type: 'string',
+ },
+ ],
+ name: 'claim',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'claimed',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'cliffPeriod',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'tokenToDrain',
+ type: 'address',
+ },
+ ],
+ name: 'drain',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'endTimestamp',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'fractalMaxAge',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'fractalSigner',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'token_',
+ type: 'address',
+ },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'lockingContract',
+ outputs: [
+ {
+ internalType: 'contract ILocking',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'renounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'root',
+ outputs: [
+ {
+ internalType: 'bytes32',
+ name: '',
+ type: 'bytes32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'slopePeriod',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'token',
+ outputs: [
+ {
+ internalType: 'contract IERC20',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'treasury',
+ outputs: [
+ {
+ internalType: 'address payable',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/mento/abis/locking.ts b/src/apps/mento/abis/locking.ts
new file mode 100644
index 00000000..84a92303
--- /dev/null
+++ b/src/apps/mento/abis/locking.ts
@@ -0,0 +1,1118 @@
+// From https://github.com/mento-protocol/governance-ui/blob/76c9b64f4029ee582043270bbe80bf9c2e48dcc7/src/lib/abi/Locking.ts
+
+export const lockingAbi = [
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'time',
+ type: 'uint256',
+ },
+ ],
+ name: 'Delegate',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegator',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'fromDelegate',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'toDelegate',
+ type: 'address',
+ },
+ ],
+ name: 'DelegateChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'previousBalance',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newBalance',
+ type: 'uint256',
+ },
+ ],
+ name: 'DelegateVotesChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint8',
+ name: 'version',
+ type: 'uint8',
+ },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'time',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'slopePeriod',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cliff',
+ type: 'uint256',
+ },
+ ],
+ name: 'LockCreate',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256[]',
+ name: 'id',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'Migrate',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'previousOwner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'delegate',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'counter',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'time',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'slopePeriod',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'cliff',
+ type: 'uint256',
+ },
+ ],
+ name: 'Relock',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'newMinCliffPeriod',
+ type: 'uint256',
+ },
+ ],
+ name: 'SetMinCliffPeriod',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'newMinSlopePeriod',
+ type: 'uint256',
+ },
+ ],
+ name: 'SetMinSlopePeriod',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'uint256',
+ name: 'newStartingPointWeek',
+ type: 'uint256',
+ },
+ ],
+ name: 'SetStartingPointWeek',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'StartLocking',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ ],
+ name: 'StartMigration',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'StopLocking',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'WEEK',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IERC20Upgradeable',
+ name: '_token',
+ type: 'address',
+ },
+ {
+ internalType: 'uint32',
+ name: '_startingPointWeek',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: '_minCliffPeriod',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: '_minSlopePeriod',
+ type: 'uint32',
+ },
+ ],
+ name: '__Locking_init',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'counter',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [
+ {
+ internalType: 'uint8',
+ name: '',
+ type: 'uint8',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'delegate',
+ outputs: [],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint8',
+ name: '',
+ type: 'uint8',
+ },
+ {
+ internalType: 'bytes32',
+ name: '',
+ type: 'bytes32',
+ },
+ {
+ internalType: 'bytes32',
+ name: '',
+ type: 'bytes32',
+ },
+ ],
+ name: 'delegateBySig',
+ outputs: [],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'newDelegate',
+ type: 'address',
+ },
+ ],
+ name: 'delegateTo',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'delegates',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ ],
+ name: 'getAccountAndDelegate',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '_account',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: '_delegate',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'getAvailableForWithdraw',
+ outputs: [
+ {
+ internalType: 'uint96',
+ name: '',
+ type: 'uint96',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint96',
+ name: 'amount',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint32',
+ name: 'slopePeriod',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'cliff',
+ type: 'uint32',
+ },
+ ],
+ name: 'getLock',
+ outputs: [
+ {
+ internalType: 'uint96',
+ name: 'lockAmount',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint96',
+ name: 'lockSlope',
+ type: 'uint96',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'blockNumber',
+ type: 'uint256',
+ },
+ ],
+ name: 'getPastTotalSupply',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'blockNumber',
+ type: 'uint256',
+ },
+ ],
+ name: 'getPastVotes',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'getVotes',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getWeek',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: '_delegate',
+ type: 'address',
+ },
+ {
+ internalType: 'uint96',
+ name: 'amount',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint32',
+ name: 'slopePeriod',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'cliff',
+ type: 'uint32',
+ },
+ ],
+ name: 'lock',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'locked',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256[]',
+ name: 'id',
+ type: 'uint256[]',
+ },
+ ],
+ name: 'migrate',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'migrateTo',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'minCliffPeriod',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'minSlopePeriod',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'id',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'newDelegate',
+ type: 'address',
+ },
+ {
+ internalType: 'uint96',
+ name: 'newAmount',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint32',
+ name: 'newSlopePeriod',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'newCliff',
+ type: 'uint32',
+ },
+ ],
+ name: 'relock',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'renounceOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'ts',
+ type: 'uint32',
+ },
+ ],
+ name: 'roundTimestamp',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'newMinCliffPeriod',
+ type: 'uint32',
+ },
+ ],
+ name: 'setMinCliffPeriod',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'newMinSlopePeriod',
+ type: 'uint32',
+ },
+ ],
+ name: 'setMinSlopePeriod',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'newStartingPointWeek',
+ type: 'uint32',
+ },
+ ],
+ name: 'setStartingPointWeek',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'start',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ ],
+ name: 'startMigration',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'startingPointWeek',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'stop',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'stopped',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'token',
+ outputs: [
+ {
+ internalType: 'contract IERC20Upgradeable',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupplyLine',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'uint32',
+ name: 'start',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint96',
+ name: 'bias',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint96',
+ name: 'slope',
+ type: 'uint96',
+ },
+ {
+ internalType: 'uint32',
+ name: 'cliff',
+ type: 'uint32',
+ },
+ ],
+ internalType: 'struct LibBrokenLine.Line',
+ name: 'initial',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ internalType: 'uint32',
+ name: 'time',
+ type: 'uint32',
+ },
+ ],
+ name: 'updateAccountLines',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ internalType: 'uint32',
+ name: 'blockNumber',
+ type: 'uint32',
+ },
+ ],
+ name: 'updateAccountLinesBlockNumber',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'time',
+ type: 'uint32',
+ },
+ ],
+ name: 'updateTotalSupplyLine',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'blockNumber',
+ type: 'uint32',
+ },
+ ],
+ name: 'updateTotalSupplyLineBlockNumber',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'withdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/mento/assets/veMENTO.png b/src/apps/mento/assets/veMENTO.png
new file mode 100644
index 00000000..a8d24383
Binary files /dev/null and b/src/apps/mento/assets/veMENTO.png differ
diff --git a/src/apps/mento/positions.e2e.ts b/src/apps/mento/positions.e2e.ts
new file mode 100644
index 00000000..599f8e17
--- /dev/null
+++ b/src/apps/mento/positions.e2e.ts
@@ -0,0 +1,20 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { DisplayProps } from '../../types/positions'
+import { t } from '../../../test/i18next'
+
+describe('getPositionDefinitions', () => {
+ it('should return the veMENTO position', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ // First address which claimed the airdrop, hopefully will keep the veMENTO position
+ address: '0x7a6f024e8d4a015afd417ddcacedcb98c3976224',
+ t,
+ })
+ expect(positions.length).toBeGreaterThan(0)
+ const veMentoPosition = positions.find(
+ (p) => (p.displayProps as DisplayProps).title === 'veMENTO',
+ )
+ expect(veMentoPosition).toBeDefined()
+ })
+})
diff --git a/src/apps/mento/positions.ts b/src/apps/mento/positions.ts
new file mode 100644
index 00000000..edbdb663
--- /dev/null
+++ b/src/apps/mento/positions.ts
@@ -0,0 +1,115 @@
+import {
+ PositionsHook,
+ ContractPositionDefinition,
+} from '../../types/positions'
+import { Address } from 'viem'
+import { toDecimalNumber } from '../../types/numbers'
+import { NetworkId } from '../../types/networkId'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { lockingAbi } from './abis/locking'
+
+const VE_MENTO_ADDRESS_BY_NETWORK_ID: {
+ [networkId: string]: Address | undefined
+} = {
+ [NetworkId['celo-mainnet']]: '0x001bb66636dcd149a1a2ba8c50e408bddd80279c',
+ [NetworkId['celo-alfajores']]: '0x537cae97c588c6da64a385817f3d3563ddcf0591',
+}
+
+async function getVeMentoPositionDefinition(
+ networkId: NetworkId,
+ address: Address,
+): Promise {
+ const veMentoAddress = VE_MENTO_ADDRESS_BY_NETWORK_ID[networkId]
+ if (!veMentoAddress) {
+ return undefined
+ }
+
+ const client = getClient(networkId)
+ const [mentoTokenAddress, decimals, locked, balance] = await client.multicall(
+ {
+ contracts: [
+ {
+ address: veMentoAddress,
+ abi: lockingAbi,
+ functionName: 'token',
+ args: [],
+ },
+ {
+ address: veMentoAddress,
+ abi: lockingAbi,
+ functionName: 'decimals',
+ args: [],
+ },
+ {
+ address: veMentoAddress,
+ abi: lockingAbi,
+ functionName: 'locked',
+ args: [address],
+ },
+ {
+ address: veMentoAddress,
+ abi: lockingAbi,
+ functionName: 'balanceOf',
+ args: [address],
+ },
+ ],
+ allowFailure: false,
+ },
+ )
+
+ if (locked === 0n) {
+ return undefined
+ }
+
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: veMentoAddress,
+ tokens: [{ address: mentoTokenAddress, networkId }],
+ displayProps: {
+ title: 'veMENTO',
+ description: `Voting power: ${toDecimalNumber(balance, decimals).toFormat(
+ 2,
+ )}`,
+ imageUrl:
+ 'https://raw.githubusercontent.com/divvi-xyz/hooks/main/src/apps/mento/assets/veMENTO.png',
+ manageUrl: undefined,
+ },
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const token =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: mentoTokenAddress,
+ networkId,
+ })
+ ]
+
+ return [toDecimalNumber(locked, token.decimals)]
+ },
+ }
+
+ return position
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Mento',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ if (!address) {
+ return []
+ }
+
+ const positions = await Promise.all([
+ getVeMentoPositionDefinition(networkId, address as Address),
+ ])
+ return positions.filter(
+ (p): p is Exclude => p != null,
+ )
+ },
+}
+
+export default hook
diff --git a/src/apps/moola/positions.e2e.ts b/src/apps/moola/positions.e2e.ts
index e2ca6388..81f73723 100644
--- a/src/apps/moola/positions.e2e.ts
+++ b/src/apps/moola/positions.e2e.ts
@@ -1,11 +1,14 @@
import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
describe('getPositionDefinitions', () => {
it('should get the address definitions successfully', async () => {
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
// Simple check to make sure we got some definitions
expect(positions.length).toBeGreaterThan(0)
})
diff --git a/src/apps/moola/positions.test.ts b/src/apps/moola/positions.test.ts
index 751ba9d6..3eb704a9 100644
--- a/src/apps/moola/positions.test.ts
+++ b/src/apps/moola/positions.test.ts
@@ -1,4 +1,6 @@
import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
jest.mock('viem', () => ({
...jest.requireActual('viem'),
@@ -7,7 +9,7 @@ jest.mock('viem', () => ({
}),
}))
-const mockNetwork = 'celo'
+const mockNetworkId = NetworkId['celo-mainnet']
const mockAddress = '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d'
const mockMulticall = jest.fn()
@@ -24,10 +26,11 @@ describe('getPositionDefinitions', () => {
0n, // 0 cREAL stable debt
2n * 10n ** 18n, // 2 CELO stable debt
])
- const positions = await hook.getPositionDefinitions(
- mockNetwork,
- mockAddress,
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: mockNetworkId,
+ address: mockAddress,
+ t,
+ })
expect(positions.length).toBe(2)
expect(positions.map((p) => p.displayProps)).toMatchInlineSnapshot(`
@@ -35,11 +38,13 @@ describe('getPositionDefinitions', () => {
{
"description": "Moola variable debt",
"imageUrl": "https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/moola.png",
+ "manageUrl": "https://app.moola.market",
"title": "cEUR debt",
},
{
"description": "Moola stable debt",
"imageUrl": "https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/moola.png",
+ "manageUrl": "https://app.moola.market",
"title": "CELO debt",
},
]
@@ -57,10 +62,11 @@ describe('getPositionDefinitions', () => {
0n, // 0 cREAL stable debt
0n, // 0 CELO stable debt
])
- const positions = await hook.getPositionDefinitions(
- mockNetwork,
- mockAddress,
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: mockNetworkId,
+ address: mockAddress,
+ t,
+ })
expect(positions.length).toBe(0)
})
diff --git a/src/apps/moola/positions.ts b/src/apps/moola/positions.ts
index 6641014a..350870e1 100644
--- a/src/apps/moola/positions.ts
+++ b/src/apps/moola/positions.ts
@@ -8,6 +8,7 @@ import { erc20Abi } from '../../abis/erc-20'
import { DecimalNumber } from '../../types/numbers'
import BigNumber from 'bignumber.js'
import { DebtTokenDefinition, MOOLA_DEBT_TOKENS } from './debtTokens'
+import { NetworkId } from '../../types/networkId'
const client = createPublicClient({
chain: celo,
@@ -16,17 +17,18 @@ const client = createPublicClient({
function getAppTokenPositionDefinition(
debtTokenDefinition: DebtTokenDefinition,
- network: string,
+ networkId: NetworkId,
): AppTokenPositionDefinition {
return {
type: 'app-token-definition',
- network: network,
+ networkId,
address: debtTokenDefinition.debtTokenAddress,
- tokens: [{ address: debtTokenDefinition.baseTokenAddress, network }],
+ tokens: [{ address: debtTokenDefinition.baseTokenAddress, networkId }],
displayProps: {
title: debtTokenDefinition.title,
description: debtTokenDefinition.description,
imageUrl: debtTokenDefinition.imageUrl, // Provide an image URL for the debt token
+ manageUrl: 'https://app.moola.market',
},
pricePerShare: [new BigNumber(-1) as DecimalNumber],
}
@@ -35,12 +37,14 @@ function getAppTokenPositionDefinition(
const hook: PositionsHook = {
getInfo() {
return {
- id: 'moola',
name: 'Moola',
- description: 'Moola debt tokens',
}
},
- async getPositionDefinitions(network, address) {
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // dapp is only on Celo, and implementation is hardcoded to Celo mainnet (contract addresses in particular)
+ return []
+ }
const debtTokenBalances = await client.multicall({
contracts: MOOLA_DEBT_TOKENS.map(({ debtTokenAddress }) => ({
address: debtTokenAddress,
@@ -53,13 +57,9 @@ const hook: PositionsHook = {
return MOOLA_DEBT_TOKENS.filter((_, i) => debtTokenBalances[i]).map(
(debtTokenDefinition) =>
- getAppTokenPositionDefinition(debtTokenDefinition, network),
+ getAppTokenPositionDefinition(debtTokenDefinition, networkId),
)
},
- getAppTokenDefinition(_) {
- // We don't need this for now, since there are no intermediary tokens
- throw new Error('Not implemented')
- },
}
export default hook
diff --git a/src/apps/somm/abis/cellar.ts b/src/apps/somm/abis/cellar.ts
new file mode 100644
index 00000000..ebcdf3f4
--- /dev/null
+++ b/src/apps/somm/abis/cellar.ts
@@ -0,0 +1,2174 @@
+// From https://github.com/PeggyJV/sommelier-strangelove/blob/staging/src/abi/types/CellarV0821.ts
+
+export const cellarV0821Abi = [
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '_owner',
+ type: 'address',
+ },
+ {
+ internalType: 'contract Registry',
+ name: '_registry',
+ type: 'address',
+ },
+ {
+ internalType: 'contract ERC20',
+ name: '_asset',
+ type: 'address',
+ },
+ {
+ internalType: 'string',
+ name: '_name',
+ type: 'string',
+ },
+ {
+ internalType: 'string',
+ name: '_symbol',
+ type: 'string',
+ },
+ {
+ internalType: 'uint32',
+ name: '_holdingPosition',
+ type: 'uint32',
+ },
+ {
+ internalType: 'bytes',
+ name: '_holdingPositionConfig',
+ type: 'bytes',
+ },
+ {
+ internalType: 'uint256',
+ name: '_initialDeposit',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint64',
+ name: '_strategistPlatformCut',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint192',
+ name: '_shareSupplyCap',
+ type: 'uint192',
+ },
+ {
+ internalType: 'address',
+ name: '_balancerVault',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'asset',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'expectedAsset',
+ type: 'address',
+ },
+ ],
+ name: 'Cellar__AssetMismatch',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ ],
+ name: 'Cellar__CallToAdaptorNotAllowed',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__CallerNotApprovedToRebalance',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__CallerNotBalancerVault',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ContractNotShutdown',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ContractShutdown',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ ],
+ name: 'Cellar__DebtMismatch',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ExpectedAddressDoesNotMatchActual',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ExternalInitiator',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__FailedToForceOutPosition',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'illiquidPosition',
+ type: 'address',
+ },
+ ],
+ name: 'Cellar__IlliquidWithdraw',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assetsOwed',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__IncompleteWithdraw',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__InvalidFee',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__InvalidFeeCut',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ ],
+ name: 'Cellar__InvalidHoldingPosition',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'requested',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'max',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__InvalidRebalanceDeviation',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__InvalidShareSupplyCap',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__MinimumConstructorMintNotMet',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__OracleFailure',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__Paused',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ ],
+ name: 'Cellar__PositionAlreadyUsed',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'maxPositions',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__PositionArrayFull',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint256',
+ name: 'sharesRemaining',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__PositionNotEmpty',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ ],
+ name: 'Cellar__PositionNotInCatalogue',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ ],
+ name: 'Cellar__PositionNotUsed',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__RemovingHoldingPosition',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__SettingValueToRegistryIdZeroIsProhibited',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ShareSupplyCapExceeded',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'min',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'max',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__TotalAssetDeviatedOutsideRange',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'current',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'expected',
+ type: 'uint256',
+ },
+ ],
+ name: 'Cellar__TotalSharesMustRemainConstant',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ZeroAssets',
+ type: 'error',
+ },
+ {
+ inputs: [],
+ name: 'Cellar__ZeroShares',
+ type: 'error',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bytes',
+ name: 'data',
+ type: 'bytes',
+ },
+ ],
+ name: 'AdaptorCalled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'inCatalogue',
+ type: 'bool',
+ },
+ ],
+ name: 'AdaptorCatalogueAltered',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'newAutomationActions',
+ type: 'address',
+ },
+ ],
+ name: 'Cellar__AutomationActionsUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'caller',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ name: 'Deposit',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'user',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'OwnershipTransferred',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'PositionAdded',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'inCatalogue',
+ type: 'bool',
+ },
+ ],
+ name: 'PositionCatalogueAltered',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint32',
+ name: 'position',
+ type: 'uint32',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index',
+ type: 'uint256',
+ },
+ ],
+ name: 'PositionRemoved',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint32',
+ name: 'newPosition1',
+ type: 'uint32',
+ },
+ {
+ indexed: false,
+ internalType: 'uint32',
+ name: 'newPosition2',
+ type: 'uint32',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index1',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'index2',
+ type: 'uint256',
+ },
+ ],
+ name: 'PositionSwapped',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'oldDeviation',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newDeviation',
+ type: 'uint256',
+ },
+ ],
+ name: 'RebalanceDeviationChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'newOracle',
+ type: 'address',
+ },
+ ],
+ name: 'SharePriceOracleUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'bool',
+ name: 'isShutdown',
+ type: 'bool',
+ },
+ ],
+ name: 'ShutdownChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'oldPayoutAddress',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'newPayoutAddress',
+ type: 'address',
+ },
+ ],
+ name: 'StrategistPayoutAddressChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'oldPlatformCut',
+ type: 'uint64',
+ },
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'newPlatformCut',
+ type: 'uint64',
+ },
+ ],
+ name: 'StrategistPlatformCutChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'caller',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'receiver',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'DOMAIN_SEPARATOR',
+ outputs: [
+ {
+ internalType: 'bytes32',
+ name: '',
+ type: 'bytes32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'GRAVITY_BRIDGE_REGISTRY_SLOT',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_FEE_CUT',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_PLATFORM_FEE',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_POSITIONS',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_REBALANCE_DEVIATION',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: '',
+ type: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ORACLE_DECIMALS',
+ outputs: [
+ {
+ internalType: 'uint8',
+ name: '',
+ type: 'uint8',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'PRICE_ROUTER_REGISTRY_SLOT',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'adaptorCatalogue',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ ],
+ name: 'addAdaptorToCatalogue',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'index',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ {
+ internalType: 'bytes',
+ name: 'configurationData',
+ type: 'bytes',
+ },
+ {
+ internalType: 'bool',
+ name: 'inDebtArray',
+ type: 'bool',
+ },
+ ],
+ name: 'addPosition',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ ],
+ name: 'addPositionToCatalogue',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'allowance',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'allowedRebalanceDeviation',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'approve',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'asset',
+ outputs: [
+ {
+ internalType: 'contract ERC20',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'automationActions',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'balancerVault',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'blockExternalReceiver',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'bool',
+ name: 'checkTotalAssets',
+ type: 'bool',
+ },
+ {
+ internalType: 'uint16',
+ name: 'allowableRange',
+ type: 'uint16',
+ },
+ {
+ internalType: 'address',
+ name: 'expectedPriceRouter',
+ type: 'address',
+ },
+ ],
+ name: 'cachePriceRouter',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ {
+ internalType: 'bytes[]',
+ name: 'callData',
+ type: 'bytes[]',
+ },
+ ],
+ internalType: 'struct Cellar.AdaptorCall[]',
+ name: 'data',
+ type: 'tuple[]',
+ },
+ ],
+ name: 'callOnAdaptor',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ name: 'convertToAssets',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ name: 'convertToShares',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'creditPositions',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'debtPositions',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [
+ {
+ internalType: 'uint8',
+ name: '',
+ type: 'uint8',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint192',
+ name: '_newShareSupplyCap',
+ type: 'uint192',
+ },
+ ],
+ name: 'decreaseShareSupplyCap',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'receiver',
+ type: 'address',
+ },
+ ],
+ name: 'deposit',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'feeData',
+ outputs: [
+ {
+ internalType: 'uint64',
+ name: 'strategistPlatformCut',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: 'platformFee',
+ type: 'uint64',
+ },
+ {
+ internalType: 'uint64',
+ name: 'lastAccrual',
+ type: 'uint64',
+ },
+ {
+ internalType: 'address',
+ name: 'strategistPayoutAddress',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'index',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ {
+ internalType: 'bool',
+ name: 'inDebtArray',
+ type: 'bool',
+ },
+ ],
+ name: 'forcePositionOut',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getCreditPositions',
+ outputs: [
+ {
+ internalType: 'uint32[]',
+ name: '',
+ type: 'uint32[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'getDebtPositions',
+ outputs: [
+ {
+ internalType: 'uint32[]',
+ name: '',
+ type: 'uint32[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ name: 'getPositionData',
+ outputs: [
+ {
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ {
+ internalType: 'bool',
+ name: 'isDebt',
+ type: 'bool',
+ },
+ {
+ internalType: 'bytes',
+ name: 'adaptorData',
+ type: 'bytes',
+ },
+ {
+ internalType: 'bytes',
+ name: 'configurationData',
+ type: 'bytes',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'holdingPosition',
+ outputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ignorePause',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint192',
+ name: '_newShareSupplyCap',
+ type: 'uint192',
+ },
+ ],
+ name: 'increaseShareSupplyCap',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'initiateShutdown',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'isPaused',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ name: 'isPositionUsed',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'isShutdown',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'liftShutdown',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'locked',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'maxDeposit',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'maxMint',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'maxRedeem',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'maxWithdraw',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'receiver',
+ type: 'address',
+ },
+ ],
+ name: 'mint',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'bytes[]',
+ name: 'data',
+ type: 'bytes[]',
+ },
+ ],
+ name: 'multicall',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ name: 'nonces',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ {
+ internalType: 'bytes',
+ name: '',
+ type: 'bytes',
+ },
+ ],
+ name: 'onERC721Received',
+ outputs: [
+ {
+ internalType: 'bytes4',
+ name: '',
+ type: 'bytes4',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [
+ {
+ internalType: 'address',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'deadline',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint8',
+ name: 'v',
+ type: 'uint8',
+ },
+ {
+ internalType: 'bytes32',
+ name: 'r',
+ type: 'bytes32',
+ },
+ {
+ internalType: 'bytes32',
+ name: 's',
+ type: 'bytes32',
+ },
+ ],
+ name: 'permit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: '',
+ type: 'uint32',
+ },
+ ],
+ name: 'positionCatalogue',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ name: 'previewDeposit',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ name: 'previewMint',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ name: 'previewRedeem',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ name: 'previewWithdraw',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'priceRouter',
+ outputs: [
+ {
+ internalType: 'contract PriceRouter',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IERC20[]',
+ name: 'tokens',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'amounts',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'feeAmounts',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'bytes',
+ name: 'userData',
+ type: 'bytes',
+ },
+ ],
+ name: 'receiveFlashLoan',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'receiver',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'redeem',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'registry',
+ outputs: [
+ {
+ internalType: 'contract Registry',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'adaptor',
+ type: 'address',
+ },
+ ],
+ name: 'removeAdaptorFromCatalogue',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'index',
+ type: 'uint32',
+ },
+ {
+ internalType: 'bool',
+ name: 'inDebtArray',
+ type: 'bool',
+ },
+ ],
+ name: 'removePosition',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ ],
+ name: 'removePositionFromCatalogue',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_registryId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: '_expectedAutomationActions',
+ type: 'address',
+ },
+ ],
+ name: 'setAutomationActions',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'positionId',
+ type: 'uint32',
+ },
+ ],
+ name: 'setHoldingPosition',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'newDeviation',
+ type: 'uint256',
+ },
+ ],
+ name: 'setRebalanceDeviation',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: '_registryId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'contract ERC4626SharePriceOracle',
+ name: '_sharePriceOracle',
+ type: 'address',
+ },
+ ],
+ name: 'setSharePriceOracle',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'payout',
+ type: 'address',
+ },
+ ],
+ name: 'setStrategistPayoutAddress',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint64',
+ name: 'cut',
+ type: 'uint64',
+ },
+ ],
+ name: 'setStrategistPlatformCut',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'sharePriceOracle',
+ outputs: [
+ {
+ internalType: 'contract ERC4626SharePriceOracle',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'shareSupplyCap',
+ outputs: [
+ {
+ internalType: 'uint192',
+ name: '',
+ type: 'uint192',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint32',
+ name: 'index1',
+ type: 'uint32',
+ },
+ {
+ internalType: 'uint32',
+ name: 'index2',
+ type: 'uint32',
+ },
+ {
+ internalType: 'bool',
+ name: 'inDebtArray',
+ type: 'bool',
+ },
+ ],
+ name: 'swapPositions',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ internalType: 'string',
+ name: '',
+ type: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'toggleIgnorePause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalAssets',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalAssetsWithdrawable',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: '',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'transfer',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'to',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'transferFrom',
+ outputs: [
+ {
+ internalType: 'bool',
+ name: '',
+ type: 'bool',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'address',
+ name: 'newOwner',
+ type: 'address',
+ },
+ ],
+ name: 'transferOwnership',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'viewPositionBalances',
+ outputs: [
+ {
+ internalType: 'contract ERC20[]',
+ name: 'assets',
+ type: 'address[]',
+ },
+ {
+ internalType: 'uint256[]',
+ name: 'balances',
+ type: 'uint256[]',
+ },
+ {
+ internalType: 'bool[]',
+ name: 'isDebt',
+ type: 'bool[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'uint256',
+ name: 'assets',
+ type: 'uint256',
+ },
+ {
+ internalType: 'address',
+ name: 'receiver',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'withdraw',
+ outputs: [
+ {
+ internalType: 'uint256',
+ name: 'shares',
+ type: 'uint256',
+ },
+ ],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/somm/api.test.ts b/src/apps/somm/api.test.ts
new file mode 100644
index 00000000..f0d2010a
--- /dev/null
+++ b/src/apps/somm/api.test.ts
@@ -0,0 +1,79 @@
+import { calculateApy } from './api'
+import { mockDayDatas, mockDayDatasFixedShareValue } from './testData'
+
+describe('calculateApy', () => {
+ it('should return undefined if apyEnabled is false', () => {
+ const result = calculateApy({
+ data: mockDayDatas,
+ windowSize: 30,
+ apyEnabled: false,
+ })
+
+ expect(result).toBeUndefined()
+ })
+
+ it('should return undefined if data is undefined', () => {
+ const result = calculateApy({
+ data: undefined,
+ windowSize: 30,
+ apyEnabled: true,
+ })
+
+ expect(result).toBeUndefined()
+ })
+
+ it('should return undefined if data length is less than the window size', () => {
+ const result = calculateApy({
+ data: Array.from({ length: 29 }, (_, i) => ({
+ date: i,
+ shareValue: '1.0',
+ })),
+ windowSize: 30,
+ apyEnabled: true,
+ })
+
+ expect(result).toBeUndefined()
+ })
+
+ it('should calculate the correct APY with valid data', () => {
+ const result = calculateApy({
+ data: mockDayDatas,
+ windowSize: 30,
+ apyEnabled: true,
+ })
+
+ expect(result).toBe(9.90525301915644)
+ })
+
+ it('should handle data not sorted by date and still return the correct APY', () => {
+ const result = calculateApy({
+ data: mockDayDatas.slice().sort(() => Math.random() - 0.5), // shuffle the array
+ windowSize: 30,
+ apyEnabled: true,
+ })
+
+ expect(result).toBe(9.90525301915644)
+ })
+
+ it('should return the estimatedApy if the calculated apy from data is 0', () => {
+ const result = calculateApy({
+ data: mockDayDatasFixedShareValue,
+ windowSize: 30,
+ apyEnabled: true,
+ estimatedApy: 1.6,
+ })
+
+ expect(result).toBe(1.6)
+ })
+
+ it('should return estimatedApy if it is provided and there is no data', () => {
+ const result = calculateApy({
+ data: [],
+ windowSize: 30,
+ apyEnabled: true,
+ estimatedApy: 1.6,
+ })
+
+ expect(result).toBe(1.6)
+ })
+})
diff --git a/src/apps/somm/api.ts b/src/apps/somm/api.ts
new file mode 100644
index 00000000..34baf775
--- /dev/null
+++ b/src/apps/somm/api.ts
@@ -0,0 +1,376 @@
+import BigNumber from 'bignumber.js'
+import { Address } from 'viem'
+import { logger } from '../../log'
+import { NetworkId } from '../../types/networkId'
+import got from '../../utils/got'
+
+const NETWORK_ID_TO_SOMM_CHAIN: Record = {
+ [NetworkId['celo-mainnet']]: null,
+ [NetworkId['ethereum-mainnet']]: 'ethereum',
+ [NetworkId['arbitrum-one']]: 'arbitrum',
+ [NetworkId['op-mainnet']]: 'optimism',
+ [NetworkId['polygon-pos-mainnet']]: null,
+ [NetworkId['base-mainnet']]: null,
+ [NetworkId['celo-alfajores']]: null,
+ [NetworkId['ethereum-sepolia']]: null,
+ [NetworkId['arbitrum-sepolia']]: null,
+ [NetworkId['op-sepolia']]: null,
+ [NetworkId['polygon-pos-amoy']]: null,
+ [NetworkId['base-sepolia']]: null,
+}
+
+// The logic for calculating APY values per cellar on the Somm website can be found here:
+// https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/data/actions/common/getStrategyData.ts#L22C14-L22C29
+//
+// The function below is a simplified version of that logic, optimized to calculate
+// only the specific value we require.
+export function calculateApy({
+ data,
+ estimatedApy,
+ apyEnabled,
+ windowSize,
+}: {
+ data?: { date: number; shareValue: string }[]
+ estimatedApy?: number
+ apyEnabled: boolean
+ windowSize: number
+}) {
+ if (!apyEnabled) return undefined
+
+ if (!data || data.length < windowSize) return estimatedApy
+
+ // Sort data by date (ascending)
+ const sortedData = [...data].sort((a, b) => a.date - b.date)
+
+ // Calculate daily APY values
+ const dailyApyValues = sortedData.map((item, index) => {
+ if (index === 0) return 0 // No comparison for the first day
+ const current = new BigNumber(item.shareValue)
+ const previous = new BigNumber(sortedData[index - 1].shareValue)
+ return current
+ .div(previous)
+ .minus(1)
+ .multipliedBy(365)
+ .multipliedBy(100)
+ .toNumber()
+ })
+
+ // Smooth APY values with rolling average over the window size
+ const smoothedApyValues = []
+ for (let i = 0; i < dailyApyValues.length - windowSize + 1; i++) {
+ const window = dailyApyValues.slice(i, i + windowSize)
+ const average = window.reduce((a, b) => a + b, 0) / windowSize
+ smoothedApyValues.push(average)
+ }
+
+ // Get the last smoothed APY value
+ const lastApy = smoothedApyValues[smoothedApyValues.length - 1]
+ return lastApy !== 0 ? lastApy : estimatedApy ?? 0
+}
+
+export async function getSommStrategiesData(networkId: NetworkId) {
+ const { result } = await got
+ .get(`https://app.somm.finance/api/sommelier-api-all-strategies-data`)
+ .json<{
+ result: {
+ data: {
+ cellars: {
+ id: string
+ shareValue: string
+ tvlTotal: number
+ chain: string
+ dayDatas: { date: number; shareValue: string }[]
+ }[]
+ }
+ }
+ }>()
+
+ return result.data.cellars
+ .filter((cellar) => {
+ // We can only return information for known cellars. If a cellar is
+ // encountered without a corresponding configuration, its likely indicates
+ // that a new cellar has been added. Log a warning to notify ourselves to
+ // add the new cellar.
+ const config = cellarConfig[cellar.id]
+ if (cellar.chain === NETWORK_ID_TO_SOMM_CHAIN[networkId] && !config) {
+ logger.warn(
+ `No config found for cellar id ${cellar.id}, this is likely a new cellar that we should add support for`,
+ )
+ }
+
+ return cellar.chain === NETWORK_ID_TO_SOMM_CHAIN[networkId] && !!config
+ })
+ .map((cellar) => {
+ const {
+ slug: strategySlug,
+ estimatedApy,
+ deprecated,
+ apyEnabled,
+ address,
+ } = cellarConfig[cellar.id]
+ if (!strategySlug) {
+ logger.warn(`No strategy slug found for cellar address ${address}`)
+ }
+
+ return {
+ ...cellar,
+ address,
+ strategySlug, // used to generate the manageUrl
+ apy: calculateApy({
+ data: cellar.dayDatas,
+ estimatedApy,
+ apyEnabled,
+ windowSize: 30, // 30 day MA APY
+ }),
+ deprecated,
+ }
+ })
+}
+
+// This configuration is derived from the hardcoded values in the Somm website source code:
+// - Config file containing the slug: https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/utils/config.ts
+// - UI configuration for estimated apy: https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/data/uiConfig.ts#L518-L599
+// - UI configuration for apy enabled: https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/data/uiConfig.ts#L68-L99
+// - The key used in the configuration matches the cellar id defined here: https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/data/cellarDataMap.ts#L87-L95
+//
+// The cellars included are filtered based on the response from the API endpoint:
+// https://app.somm.finance/api/sommelier-api-all-strategies-data
+//
+// Note on deprecated cellars:
+// - Some cellars are marked as deprecated in their individual strategy configuration files (via the `deprecated` field) in the Somm website source code.
+// - For deprecated cellars, the following behavior should be applied:
+// - Allow users to view position data if they already hold a position in the cellar.
+// - Do NOT allow shortcuts or options to acquire new positions in the deprecated cellars.
+// Deprecated cellars are included in the configuration below to enable detection of new cellars
+// in the Strategies API response. By maintaining a copy of all known cellars, we can compare
+// and identify newly added cellars more effectively.
+//
+// Strategy configuration reference:
+// https://github.com/PeggyJV/sommelier-strangelove/tree/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/data/strategies
+const cellarConfig: Record<
+ string,
+ {
+ address: Address
+ slug: string | undefined
+ estimatedApy?: number
+ deprecated: boolean
+ apyEnabled: boolean
+ }
+> = {
+ '0x0274a704a6d9129f90a62ddc6f6024b33ecdad36': {
+ address: '0x0274a704a6d9129f90a62ddc6f6024b33ecdad36',
+ slug: 'Real-Yield-BTC',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x03df2a53cbed19b824347d6a45d09016c2d1676a': {
+ address: '0x03df2a53cbed19b824347d6a45d09016c2d1676a',
+ slug: 'DeFi-Stars',
+ deprecated: false,
+ apyEnabled: false,
+ },
+ '0x05641a27c82799aaf22b436f20a3110410f29652': {
+ address: '0x05641a27c82799aaf22b436f20a3110410f29652',
+ slug: 'Steady-MATIC',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x0c190ded9be5f512bd72827bdad4003e9cc7975c': {
+ address: '0x0c190ded9be5f512bd72827bdad4003e9cc7975c',
+ slug: 'Turbo-GHO',
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0x18ea937aba6053bc232d9ae2c42abe7a8a2be440': {
+ address: '0x18ea937aba6053bc232d9ae2c42abe7a8a2be440',
+ slug: 'Real-Yield-ENS',
+ estimatedApy: 1.9,
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x19b8d8fc682fc56fbb42653f68c7d48dd3fe597e': {
+ address: '0x19b8d8fc682fc56fbb42653f68c7d48dd3fe597e',
+ slug: 'Turbo-ETHx',
+ estimatedApy: 6,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0x1dffb366b5c5a37a12af2c127f31e8e0ed86bdbe': {
+ address: '0x1dffb366b5c5a37a12af2c127f31e8e0ed86bdbe',
+ slug: 'Turbo-rsETH',
+ estimatedApy: 8,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0x27500de405a3212d57177a789e30bb88b0adbec5': {
+ address: '0x27500de405a3212d57177a789e30bb88b0adbec5',
+ slug: 'Turbo-ezETH',
+ estimatedApy: 6,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0x3f07a84ecdf494310d397d24c1c78b041d2fa622': {
+ address: '0x3f07a84ecdf494310d397d24c1c78b041d2fa622',
+ slug: 'Steady-ETH',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x4068bdd217a45f8f668ef19f1e3a1f043e4c4934': {
+ address: '0x4068bdd217a45f8f668ef19f1e3a1f043e4c4934',
+ slug: 'Real-Yield-LINK',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x4986fd36b6b16f49b43282ee2e24c5cf90ed166d': {
+ address: '0x4986fd36b6b16f49b43282ee2e24c5cf90ed166d',
+ slug: 'Steady-BTC',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x6a6af5393dc23d7e3db28d28ef422db7c40932b6': {
+ address: '0x6a6af5393dc23d7e3db28d28ef422db7c40932b6',
+ slug: 'Real-Yield-UNI',
+ estimatedApy: 2.6,
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x6e2dac3b9e9adc0cbbae2d0b9fd81952a8d33872': {
+ address: '0x6e2dac3b9e9adc0cbbae2d0b9fd81952a8d33872',
+ slug: 'ETH-BTC-Momentum',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x6f069f711281618467dae7873541ecc082761b33': {
+ address: '0x6f069f711281618467dae7873541ecc082761b33',
+ slug: 'Steady-UNI',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x6b7f87279982d919bbf85182ddeab179b366d8f2': {
+ address: '0x6b7f87279982d919bbf85182ddeab179b366d8f2',
+ slug: 'ETH-BTC-Trend',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x6c1edce139291af5b84fb1e496c9747f83e876c9': {
+ address: '0x6c1edce139291af5b84fb1e496c9747f83e876c9',
+ slug: 'Turbo-divETH',
+ estimatedApy: 4,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0x6c51041a91c91c86f3f08a72cb4d3f67f1208897': {
+ address: '0x6c51041a91c91c86f3f08a72cb4d3f67f1208897',
+ slug: 'ETH-Trend-Growth',
+ deprecated: false,
+ apyEnabled: false,
+ },
+ '0x7bad5df5e11151dc5ee1a648800057c5c934c0d5': {
+ address: '0x7bad5df5e11151dc5ee1a648800057c5c934c0d5',
+ slug: 'AAVE',
+ deprecated: true,
+ apyEnabled: false,
+ },
+ '0x97e6e0a40a3d02f12d1cec30ebfbae04e37c119e': {
+ address: '0x97e6e0a40a3d02f12d1cec30ebfbae04e37c119e',
+ slug: 'Real-Yield-USD',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x9a7b4980c6f0fcaa50cd5f288ad7038f434c692e': {
+ address: '0x9a7b4980c6f0fcaa50cd5f288ad7038f434c692e',
+ slug: 'Turbo-eETH',
+ estimatedApy: 6,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0xc7b69e15d86c5c1581dacce3cacaf5b68cd6596f': {
+ address: '0xc7b69e15d86c5c1581dacce3cacaf5b68cd6596f',
+ slug: 'Real-Yield-1Inch',
+ estimatedApy: 1.6,
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xdbe19d1c3f21b1bb250ca7bdae0687a97b5f77e6': {
+ address: '0xdbe19d1c3f21b1bb250ca7bdae0687a97b5f77e6',
+ slug: 'Fraximal',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xb5b29320d2dde5ba5bafa1ebcd270052070483ec': {
+ address: '0xb5b29320d2dde5ba5bafa1ebcd270052070483ec',
+ slug: 'Real-Yield-ETH',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xc7372ab5dd315606db799246e8aa112405abaeff': {
+ address: '0xc7372ab5dd315606db799246e8aa112405abaeff',
+ slug: 'Turbo-STETH-(steth-deposit)',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xcbf2250f33c4161e18d4a2fa47464520af5216b5': {
+ address: '0xcbf2250f33c4161e18d4a2fa47464520af5216b5',
+ slug: 'Real-Yield-SNX',
+ estimatedApy: 3.7,
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xcf4b531b4cde95bd35d71926e09b2b54c564f5b6': {
+ address: '0xcf4b531b4cde95bd35d71926e09b2b54c564f5b6',
+ slug: 'Morpho-ETH',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xd33dad974b938744dac81fe00ac67cb5aa13958e': {
+ address: '0xd33dad974b938744dac81fe00ac67cb5aa13958e',
+ slug: 'Turbo-SWETH',
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0xdadc82e26b3739750e036dfd9defd3ed459b877a': {
+ address: '0xdadc82e26b3739750e036dfd9defd3ed459b877a',
+ slug: 'Turbo-eETHV2',
+ estimatedApy: 6,
+ deprecated: true,
+ apyEnabled: true,
+ },
+ '0xfd6db5011b171b05e1ea3b92f9eacaeeb055e971': {
+ address: '0xfd6db5011b171b05e1ea3b92f9eacaeeb055e971',
+ slug: 'Turbo-STETH',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8-arbitrum': {
+ address: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8',
+ slug: 'real-yield-usd-arb',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xa73b0b48e26e4b8b24cead149252cc275dee99a6-arbitrum': {
+ address: '0xa73b0b48e26e4b8b24cead149252cc275dee99a6',
+ slug: 'Real-Yield-USD-Arbitrum',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c-arbitrum': {
+ address: '0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c',
+ slug: 'real-yield-eth-arb',
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c-optimism': {
+ address: '0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c',
+ slug: 'real-yield-eth-opt',
+ estimatedApy: 15,
+ deprecated: false,
+ apyEnabled: true,
+ },
+ '0xd3bb04423b0c98abc9d62f201212f44dc2611200-scroll': {
+ address: '0xd3bb04423b0c98abc9d62f201212f44dc2611200',
+ slug: 'real-yield-eth-scroll',
+ estimatedApy: 15,
+ deprecated: false,
+ apyEnabled: true,
+ },
+}
diff --git a/src/apps/somm/assets/somm.png b/src/apps/somm/assets/somm.png
new file mode 100644
index 00000000..215c3fdc
Binary files /dev/null and b/src/apps/somm/assets/somm.png differ
diff --git a/src/apps/somm/positions.e2e.ts b/src/apps/somm/positions.e2e.ts
new file mode 100644
index 00000000..4367f8f2
--- /dev/null
+++ b/src/apps/somm/positions.e2e.ts
@@ -0,0 +1,53 @@
+import { t } from '../../../test/i18next'
+import { getConfig } from '../../config'
+import { getBaseTokensInfo, getPositions } from '../../runtime/getPositions'
+import { NetworkId } from '../../types/networkId'
+import { TokensInfo } from '../../types/positions'
+import hook from './positions'
+
+describe('getPositionDefinitions', () => {
+ let baseTokensInfo: TokensInfo = {}
+ beforeAll(async () => {
+ baseTokensInfo = await getBaseTokensInfo(getConfig().GET_TOKENS_INFO_URL)
+ })
+
+ it('should get the address definitions successfully', async () => {
+ const positions = await getPositions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['somm'],
+ t,
+ baseTokensInfo,
+ })
+
+ expect(
+ positions.filter((p) => p.type === 'app-token').length,
+ ).toBeGreaterThan(0)
+ expect(positions.filter((p) => p.type === 'contract-position').length).toBe(
+ 0,
+ )
+ })
+
+ it('should get no definitions for an address with no blockchain interaction', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
+ expect(positions.length).toBe(0)
+ })
+
+ it('should get app token definitions when address is not set', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ t,
+ })
+
+ expect(
+ positions.filter((p) => p.type === 'app-token-definition').length,
+ ).toBeGreaterThan(0)
+ expect(
+ positions.filter((p) => p.type === 'contract-position-definition').length,
+ ).toBe(0)
+ })
+})
diff --git a/src/apps/somm/positions.test.ts b/src/apps/somm/positions.test.ts
new file mode 100644
index 00000000..26d2da2e
--- /dev/null
+++ b/src/apps/somm/positions.test.ts
@@ -0,0 +1,228 @@
+import { TFunction } from 'i18next'
+import { NetworkId } from '../../types/networkId'
+import got from '../../utils/got'
+import hook from './positions'
+import { mockDayDatas } from './testData'
+
+const mockT = ((x: string) => x) as TFunction
+
+jest.mock('../../utils/got')
+
+const mockReadContract = jest.fn()
+jest.mock('../../runtime/client', () => ({
+ getClient: jest.fn(() => ({
+ readContract: mockReadContract,
+ })),
+}))
+
+describe('hook', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+
+ mockReadContract.mockImplementation(
+ async ({ functionName, address, args }) => {
+ if (address !== '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8') {
+ throw new Error('Unexpected address')
+ }
+ if (functionName === 'asset') {
+ return '0xUnderlyingAsset'
+ }
+ if (functionName === 'decimals') {
+ return 18
+ }
+ if (functionName === 'symbol') {
+ return 'SYMBOL'
+ }
+ if (functionName === 'name') {
+ return 'Cellar Name'
+ }
+ if (functionName === 'balanceOf') {
+ return args[0] === '0x12345' ? 1n : 0n
+ }
+ throw new Error('Unexpected function')
+ },
+ )
+ })
+
+ it('should return the correct hook info', () => {
+ expect(hook.getInfo()).toEqual({
+ name: 'Somm',
+ })
+ })
+
+ describe('getPositionDefinitions', () => {
+ it('should return expected positions when called with supported networkId and address with position', async () => {
+ jest.mocked(got).get = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ result: {
+ data: {
+ cellars: [
+ {
+ id: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8-arbitrum',
+ shareValue: '1050000',
+ tvlTotal: 10000000,
+ chain: 'arbitrum',
+ dayDatas: mockDayDatas,
+ },
+ ],
+ },
+ },
+ }),
+ })
+
+ const sommPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x12345',
+ t: mockT,
+ })
+
+ expect(mockReadContract).toHaveBeenCalledTimes(5)
+ expect(sommPositions).toEqual([
+ {
+ type: 'app-token-definition',
+ pricePerShare: expect.any(Function),
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8', // cellar address
+ tokens: [
+ {
+ address: '0xunderlyingasset',
+ networkId: NetworkId['arbitrum-one'],
+ },
+ ],
+ displayProps: expect.any(Function),
+ dataProps: {
+ cantSeparateCompoundedInterest: true,
+ depositTokenId: 'arbitrum-one:0xunderlyingasset',
+ earningItems: [],
+ manageUrl:
+ 'https://app.somm.finance/strategies/real-yield-usd-arb/manage',
+ termsUrl: 'https://app.somm.finance/user-terms',
+ tvl: '10000000',
+ withdrawTokenId:
+ 'arbitrum-one:0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8',
+ yieldRates: [
+ {
+ label: 'yieldRates.netApyWithAverage',
+ percentage: 9.90525301915644,
+ tokenId: 'arbitrum-one:0xunderlyingasset',
+ },
+ ],
+ },
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: expect.any(Function),
+ },
+ ])
+ // @ts-expect-error - displayProps can be an object or function but here it is a function and does not require arguments
+ expect(sommPositions[0].displayProps()).toEqual({
+ title: 'Cellar Name',
+ description: 'SYMBOL (APY: 9.91%)',
+ imageUrl:
+ 'https://raw.githubusercontent.com/divvi-xyz/hooks/main/src/apps/somm/assets/somm.png',
+ manageUrl:
+ 'https://app.somm.finance/strategies/real-yield-usd-arb/manage',
+ })
+ })
+
+ it('should return an empty array when called with an unsupported networkId', async () => {
+ const sommPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-alfajores'],
+ address: '0x12345',
+ t: mockT,
+ })
+
+ expect(sommPositions).toEqual([])
+ })
+
+ it('should return an empty array when called with an address that has no balance', async () => {
+ jest.mocked(got).get = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ result: {
+ data: {
+ cellars: [
+ {
+ id: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8-arbitrum',
+ shareValue: '1050000',
+ tvlTotal: 10000000,
+ chain: 'arbitrum',
+ },
+ ],
+ },
+ },
+ }),
+ })
+
+ const sommPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0xabcde',
+ t: mockT,
+ })
+
+ expect(mockReadContract).toHaveBeenCalledTimes(1)
+ expect(sommPositions).toEqual([])
+ })
+
+ it('should return definitions for positions even if some positions cannot be resolved', async () => {
+ jest.mocked(got).get = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ result: {
+ data: {
+ cellars: [
+ {
+ id: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8-arbitrum',
+ shareValue: '1050000',
+ tvlTotal: 10000000,
+ chain: 'arbitrum',
+ },
+ {
+ id: '0xc47bb288178ea40bf520a91826a3dee9e0dbfa4c-unknown', // mockReadContract will fail on this address
+ shareValue: '1050000',
+ tvlTotal: 10000000,
+ chain: 'arbitrum',
+ },
+ ],
+ },
+ },
+ }),
+ })
+
+ const sommPositions = await hook.getPositionDefinitions({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x12345',
+ t: mockT,
+ })
+
+ expect(sommPositions).toEqual([
+ {
+ type: 'app-token-definition',
+ pricePerShare: expect.any(Function),
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8', // cellar address
+ tokens: [
+ {
+ address: '0xunderlyingasset',
+ networkId: NetworkId['arbitrum-one'],
+ },
+ ],
+ displayProps: expect.any(Function),
+ dataProps: {
+ cantSeparateCompoundedInterest: true,
+ depositTokenId: 'arbitrum-one:0xunderlyingasset',
+ earningItems: [],
+ manageUrl:
+ 'https://app.somm.finance/strategies/real-yield-usd-arb/manage',
+ termsUrl: 'https://app.somm.finance/user-terms',
+ tvl: '10000000',
+ withdrawTokenId:
+ 'arbitrum-one:0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8',
+ yieldRates: [], // no yield rates because dayDatas (which is needed to calculate apy) is not provided in the mocked data above
+ },
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: expect.any(Function),
+ },
+ ])
+ })
+ })
+})
diff --git a/src/apps/somm/positions.ts b/src/apps/somm/positions.ts
new file mode 100644
index 00000000..6be114e2
--- /dev/null
+++ b/src/apps/somm/positions.ts
@@ -0,0 +1,182 @@
+import { Address } from 'viem'
+import { logger } from '../../log'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { toDecimalNumber, toSerializedDecimalNumber } from '../../types/numbers'
+import {
+ PositionDefinition,
+ PositionsHook,
+ PricePerShareContext,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import { cellarV0821Abi } from './abis/cellar'
+import { getSommStrategiesData } from './api'
+
+const SOMM_TERMS_URL = 'https://app.somm.finance/user-terms'
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Somm',
+ }
+ },
+ async getPositionDefinitions({ networkId, address, t }) {
+ const client = getClient(networkId)
+ const cellars = await getSommStrategiesData(networkId)
+ const positionDefinitions: PositionDefinition[] = []
+
+ const results = await Promise.allSettled(
+ cellars.map(async (cellar) => {
+ // Note that according to the hard coded config in the Somm website
+ // source code
+ // https://github.com/PeggyJV/sommelier-strangelove/blob/ca7bd6605bc868a1393d820f13b341ae5a5f1ead/src/utils/config.ts,
+ // cellars implement one of 4 ABIs (CellarV0816, CellarV0821,
+ // CellarV0821MultiDeposit, CellarV0815). All of these ABIs have the
+ // 'asset', 'symbol', and 'name' functions so for simplicity, we are
+ // using the CellarV0821 ABI for all cellars in the below rpc calls.
+ if (address) {
+ const balance = await client.readContract({
+ address: cellar.address,
+ abi: cellarV0821Abi,
+ functionName: 'balanceOf',
+ args: [address as Address],
+ })
+
+ if (balance === 0n) {
+ // Only return positions with a non-zero balance when an address is provided
+ return null
+ }
+ }
+
+ const [
+ underlyingAsset,
+ underlyingAssetSymbol,
+ cellarName,
+ cellarDecimals,
+ ] = await Promise.all([
+ client.readContract({
+ address: cellar.address,
+ abi: cellarV0821Abi,
+ functionName: 'asset',
+ }),
+ client.readContract({
+ address: cellar.address,
+ abi: cellarV0821Abi,
+ functionName: 'symbol',
+ }),
+ client.readContract({
+ address: cellar.address,
+ abi: cellarV0821Abi,
+ functionName: 'name',
+ }),
+ client.readContract({
+ address: cellar.address,
+ abi: cellarV0821Abi,
+ functionName: 'decimals',
+ }),
+ ])
+
+ const manageUrl = cellar.strategySlug
+ ? `https://app.somm.finance/strategies/${cellar.strategySlug}/manage`
+ : undefined
+ const underlyingTokenId = getTokenId({
+ address: underlyingAsset.toLowerCase(),
+ networkId,
+ })
+
+ const result = {
+ type: 'app-token-definition' as const,
+ pricePerShare: async ({ tokensByTokenId }: PricePerShareContext) => {
+ const tokenId = getTokenId({
+ address: cellar.address,
+ networkId,
+ })
+ const { decimals } = tokensByTokenId[tokenId]
+ return [toDecimalNumber(BigInt(cellar.shareValue), decimals)]
+ },
+ networkId,
+ address: cellar.address,
+ tokens: [
+ {
+ address: underlyingAsset.toLowerCase(),
+ networkId,
+ },
+ ],
+ displayProps: () => {
+ return {
+ title: cellarName,
+ description: `${underlyingAssetSymbol}${
+ cellar.apy !== undefined
+ ? ` (APY: ${cellar.apy.toFixed(2)}%)`
+ : ''
+ }`,
+ imageUrl:
+ 'https://raw.githubusercontent.com/divvi-xyz/hooks/main/src/apps/somm/assets/somm.png',
+ manageUrl,
+ }
+ },
+ dataProps: {
+ termsUrl: SOMM_TERMS_URL,
+ manageUrl,
+ tvl: toSerializedDecimalNumber(cellar.tvlTotal),
+ yieldRates: [
+ ...(cellar.apy
+ ? [
+ {
+ percentage: cellar.apy,
+ label: t('yieldRates.netApyWithAverage', { numDays: 30 }),
+ tokenId: underlyingTokenId,
+ },
+ ]
+ : []),
+ ],
+ cantSeparateCompoundedInterest: true,
+ earningItems: [],
+ depositTokenId: underlyingTokenId,
+ withdrawTokenId: getTokenId({
+ address: cellar.address,
+ networkId,
+ }),
+ },
+ availableShortcutIds: ['deposit', 'withdraw'],
+ shortcutTriggerArgs: () => {
+ return {
+ deposit: {
+ tokenAddress: underlyingAsset.toLowerCase(),
+ tokenDecimals: cellarDecimals,
+ positionAddress: cellar.address.toLowerCase(),
+ },
+ withdraw: {
+ tokenDecimals: cellarDecimals,
+ positionAddress: cellar.address.toLowerCase(),
+ },
+ }
+ },
+ }
+ return result
+ }),
+ )
+
+ results.forEach((result) => {
+ if (result.status === 'fulfilled') {
+ if (result.value) {
+ positionDefinitions.push(result.value)
+ }
+ } else {
+ logger.error(
+ {
+ error: result.reason,
+ },
+ 'Skipping Somm position that failed to resolve',
+ )
+ }
+ })
+
+ return positionDefinitions
+ },
+ async getAppTokenDefinition({ networkId, address }) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/somm/shortcuts.e2e.ts b/src/apps/somm/shortcuts.e2e.ts
new file mode 100644
index 00000000..ceb6f277
--- /dev/null
+++ b/src/apps/somm/shortcuts.e2e.ts
@@ -0,0 +1,62 @@
+import { NetworkId } from '../../types/networkId'
+import hook from './shortcuts'
+
+describe('getShortcutDefinitions', () => {
+ it('should get the definitions successfully', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ expect(shortcuts.length).toBeGreaterThan(0)
+ })
+
+ describe('deposit.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'deposit')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokenAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC
+ tokenDecimals: 6,
+ positionAddress: '0xa73b0b48e26e4b8b24cead149252cc275dee99a6', // RYUSD
+ tokens: [
+ {
+ tokenId: 'arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
+ amount: '10',
+ },
+ ],
+ })
+
+ expect(transactions.length).toEqual(2)
+ })
+ })
+
+ describe('withdraw.onTrigger', () => {
+ it('should return transactions', async () => {
+ const shortcuts = await hook.getShortcutDefinitions(
+ NetworkId['arbitrum-one'],
+ )
+ const shortcut = shortcuts.find((shortcut) => shortcut.id === 'withdraw')
+ expect(shortcut).toBeDefined()
+
+ const { transactions } = await shortcut!.onTrigger({
+ networkId: NetworkId['arbitrum-one'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ tokens: [
+ {
+ tokenId: 'arbitrum-one:0xb9A27ba529634017b12e3cbbbFFb6dB7908a8C8B',
+ amount: '1',
+ },
+ ],
+ positionAddress: '0xa73b0b48e26e4b8b24cead149252cc275dee99a6', // RYUSD
+ tokenDecimals: 6,
+ })
+
+ expect(transactions.length).toEqual(1)
+ })
+ })
+})
diff --git a/src/apps/somm/shortcuts.ts b/src/apps/somm/shortcuts.ts
new file mode 100644
index 00000000..4ecf4cd1
--- /dev/null
+++ b/src/apps/somm/shortcuts.ts
@@ -0,0 +1,159 @@
+import { Address, encodeFunctionData, erc20Abi, parseUnits } from 'viem'
+import { z } from 'zod'
+import { logger } from '../../log'
+import { getClient } from '../../runtime/client'
+import {
+ simulateTransactions,
+ UnsupportedSimulateRequest,
+} from '../../runtime/simulateTransactions'
+import { ZodAddressLowerCased } from '../../types/address'
+import { NetworkId } from '../../types/networkId'
+import {
+ createShortcut,
+ ShortcutsHook,
+ tokenAmounts,
+ Transaction,
+} from '../../types/shortcuts'
+import { cellarV0821Abi } from './abis/cellar'
+
+// Hardcoded fallback if simulation isn't enabled
+const DEFAULT_DEPOSIT_GAS = 750_000n
+
+const hook: ShortcutsHook = {
+ async getShortcutDefinitions(networkId: NetworkId) {
+ return [
+ createShortcut({
+ id: 'deposit',
+ name: 'Deposit',
+ description: 'Lend your assets to earn interest',
+ networkIds: [networkId],
+ category: 'deposit',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ // these three will be passed in the shortcutTriggerArgs. It's a temporary workaround before we can directly extract these info from the tokenId
+ positionAddress: ZodAddressLowerCased,
+ tokenAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const transactions: Transaction[] = []
+
+ // amount in smallest unit
+ const amountToSupply = parseUnits(tokens[0].amount, tokenDecimals)
+
+ const client = getClient(networkId)
+
+ const approvedAllowanceForSpender = await client.readContract({
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: 'allowance',
+ args: [walletAddress, positionAddress],
+ })
+
+ if (approvedAllowanceForSpender < amountToSupply) {
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [positionAddress, amountToSupply],
+ })
+
+ const approveTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: tokenAddress,
+ data,
+ }
+ transactions.push(approveTx)
+ }
+
+ const depositTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: cellarV0821Abi,
+ functionName: 'deposit',
+ args: [amountToSupply, walletAddress],
+ }),
+ }
+
+ transactions.push(depositTx)
+
+ // TODO: consider moving this concern to the runtime
+ try {
+ const simulatedTransactions = await simulateTransactions({
+ transactions,
+ networkId,
+ })
+ const supplySimulatedTx =
+ simulatedTransactions[simulatedTransactions.length - 1]
+
+ // 15% buffer on the estimation from the simulation
+ depositTx.gas = (BigInt(supplySimulatedTx.gasNeeded) * 115n) / 100n
+ depositTx.estimatedGasUse = BigInt(supplySimulatedTx.gasUsed)
+ } catch (error) {
+ if (!(error instanceof UnsupportedSimulateRequest)) {
+ logger.warn(error, 'Unexpected error during simulateTransactions')
+ }
+ depositTx.gas = DEFAULT_DEPOSIT_GAS
+ depositTx.estimatedGasUse = DEFAULT_DEPOSIT_GAS / 3n
+ }
+
+ return { transactions }
+ },
+ }),
+ createShortcut({
+ id: 'withdraw',
+ name: 'Withdraw',
+ description: 'Withdraw your assets',
+ networkIds: [networkId],
+ category: 'withdraw',
+ triggerInputShape: {
+ tokens: tokenAmounts.length(1),
+ // these two will be passed in the shortcutTriggerArgs.
+ positionAddress: ZodAddressLowerCased,
+ tokenDecimals: z.coerce.number(),
+ },
+ async onTrigger({
+ networkId,
+ address,
+ tokens,
+ positionAddress,
+ tokenDecimals,
+ }) {
+ const walletAddress = address as Address
+ const amountToWithdraw = parseUnits(tokens[0].amount, tokenDecimals)
+
+ // We rely on the client to pass the correct token amount, especially
+ // for liquidation withdrawals. The `maxRedeem` method on the cellar
+ // contract doesn't seem to work as expected (see example:
+ // https://arbiscan.io/tx/0xd4528444960526ca93874ed86c6637b4ca17df079d71f44267f1b6e6ef56868d).
+ // It's also not used in the Somm front-end code.
+ const withdrawTx: Transaction = {
+ networkId,
+ from: walletAddress,
+ to: positionAddress,
+ data: encodeFunctionData({
+ abi: cellarV0821Abi,
+ functionName: 'redeem',
+ args: [amountToWithdraw, walletAddress, walletAddress],
+ }),
+ }
+
+ return { transactions: [withdrawTx] }
+ },
+ }),
+ ]
+ },
+}
+
+export default hook
diff --git a/src/apps/somm/testData.ts b/src/apps/somm/testData.ts
new file mode 100644
index 00000000..544b17a0
--- /dev/null
+++ b/src/apps/somm/testData.ts
@@ -0,0 +1,262 @@
+// the below mock data is from the Somm API on 16/12/24 for cellar
+// 0x392b1e6905bb8449d26af701cdea6ff47bf6e5a8, and the displayed apy is 9.91%
+export const mockDayDatas = [
+ {
+ date: 1734307200,
+ shareValue: '1054885',
+ },
+ {
+ date: 1734220800,
+ shareValue: '1054626',
+ },
+ {
+ date: 1734134400,
+ shareValue: '1054389',
+ },
+ {
+ date: 1734048000,
+ shareValue: '1054135',
+ },
+ {
+ date: 1733961600,
+ shareValue: '1053862',
+ },
+ {
+ date: 1733875200,
+ shareValue: '1053578',
+ },
+ {
+ date: 1733788800,
+ shareValue: '1053252',
+ },
+ {
+ date: 1733702400,
+ shareValue: '1052925',
+ },
+ {
+ date: 1733616000,
+ shareValue: '1052549',
+ },
+ {
+ date: 1733529600,
+ shareValue: '1052199',
+ },
+ {
+ date: 1733443200,
+ shareValue: '1051832',
+ },
+ {
+ date: 1733356800,
+ shareValue: '1051476',
+ },
+ {
+ date: 1733270400,
+ shareValue: '1051187',
+ },
+ {
+ date: 1733184000,
+ shareValue: '1050826',
+ },
+ {
+ date: 1733097600,
+ shareValue: '1050481',
+ },
+ {
+ date: 1733011200,
+ shareValue: '1050109',
+ },
+ {
+ date: 1732924800,
+ shareValue: '1049774',
+ },
+ {
+ date: 1732838400,
+ shareValue: '1049566',
+ },
+ {
+ date: 1732752000,
+ shareValue: '1049451',
+ },
+ {
+ date: 1732665600,
+ shareValue: '1049328',
+ },
+ {
+ date: 1732579200,
+ shareValue: '1049166',
+ },
+ {
+ date: 1732492800,
+ shareValue: '1048916',
+ },
+ {
+ date: 1732406400,
+ shareValue: '1048641',
+ },
+ {
+ date: 1732320000,
+ shareValue: '1048359',
+ },
+ {
+ date: 1732233600,
+ shareValue: '1047892',
+ },
+ {
+ date: 1732147200,
+ shareValue: '1047464',
+ },
+ {
+ date: 1732060800,
+ shareValue: '1047088',
+ },
+ {
+ date: 1731974400,
+ shareValue: '1046773',
+ },
+ {
+ date: 1731888000,
+ shareValue: '1046630',
+ },
+ {
+ date: 1731801600,
+ shareValue: '1046450',
+ },
+ {
+ date: 1731715200,
+ shareValue: '1046333',
+ },
+ {
+ date: 1731628800,
+ shareValue: '1046070',
+ },
+]
+
+// the below mock data is from the Somm API on 16/12/24 for cellar
+// 0x6a6af5393dc23d7e3db28d28ef422db7c40932b6, which is an example of fixed
+// shareValue. In this case, the estimatedApy is used.
+export const mockDayDatasFixedShareValue = [
+ {
+ date: 1734307200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1734220800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1734134400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1734048000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733961600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733875200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733788800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733702400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733616000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733529600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733443200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733356800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733270400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733184000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733097600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1733011200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732924800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732838400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732752000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732665600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732492800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732406400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732320000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732233600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732147200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1732060800,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1731974400,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1731888000,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1731801600,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1731715200,
+ shareValue: '1000000000000000000',
+ },
+ {
+ date: 1731628800,
+ shareValue: '1000000000000000000',
+ },
+]
diff --git a/src/apps/stake-dao/abis/stakeDaoGauge.ts b/src/apps/stake-dao/abis/stakeDaoGauge.ts
new file mode 100644
index 00000000..78cfd4f4
--- /dev/null
+++ b/src/apps/stake-dao/abis/stakeDaoGauge.ts
@@ -0,0 +1,447 @@
+// From https://arbiscan.io/address/0xfbf7b624a7af73ef699ffc09078d17667973f456#code
+export const stakeDaoGaugeAbi = [
+ {
+ name: 'Deposit',
+ inputs: [
+ { name: 'provider', type: 'address', indexed: true },
+ { name: 'value', type: 'uint256', indexed: false },
+ ],
+ anonymous: false,
+ type: 'event',
+ },
+ {
+ name: 'Withdraw',
+ inputs: [
+ { name: 'provider', type: 'address', indexed: true },
+ { name: 'value', type: 'uint256', indexed: false },
+ ],
+ anonymous: false,
+ type: 'event',
+ },
+ {
+ name: 'Transfer',
+ inputs: [
+ { name: '_from', type: 'address', indexed: true },
+ { name: '_to', type: 'address', indexed: true },
+ { name: '_value', type: 'uint256', indexed: false },
+ ],
+ anonymous: false,
+ type: 'event',
+ },
+ {
+ name: 'Approval',
+ inputs: [
+ { name: '_owner', type: 'address', indexed: true },
+ { name: '_spender', type: 'address', indexed: true },
+ { name: '_value', type: 'uint256', indexed: false },
+ ],
+ anonymous: false,
+ type: 'event',
+ },
+ {
+ name: 'RewardDataUpdate',
+ inputs: [
+ { name: '_token', type: 'address', indexed: true },
+ { name: '_amount', type: 'uint256', indexed: false },
+ ],
+ anonymous: false,
+ type: 'event',
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ inputs: [],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'initialize',
+ inputs: [
+ { name: '_registry', type: 'address' },
+ { name: '_staking_token', type: 'address' },
+ { name: '_vault', type: 'address' },
+ { name: '_reward_token', type: 'address' },
+ { name: '_distributor', type: 'address' },
+ { name: '_claimer', type: 'address' },
+ ],
+ outputs: [],
+ gas: 513549,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'decimals',
+ inputs: [],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 2418,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'claimed_reward',
+ inputs: [
+ { name: '_addr', type: 'address' },
+ { name: '_token', type: 'address' },
+ ],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 2946,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'claimable_reward',
+ inputs: [
+ { name: '_user', type: 'address' },
+ { name: '_reward_token', type: 'address' },
+ ],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 20180,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'set_rewards_receiver',
+ inputs: [{ name: '_receiver', type: 'address' }],
+ outputs: [],
+ gas: 35583,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'set_vault',
+ inputs: [{ name: '_vault', type: 'address' }],
+ outputs: [],
+ gas: 42507,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'claim_rewards',
+ inputs: [],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'claim_rewards',
+ inputs: [{ name: '_addr', type: 'address' }],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'claim_rewards',
+ inputs: [
+ { name: '_addr', type: 'address' },
+ { name: '_receiver', type: 'address' },
+ ],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'claim_rewards_for',
+ inputs: [
+ { name: '_addr', type: 'address' },
+ { name: '_receiver', type: 'address' },
+ ],
+ outputs: [],
+ gas: 2762822,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'deposit',
+ inputs: [{ name: '_value', type: 'uint256' }],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'deposit',
+ inputs: [
+ { name: '_value', type: 'uint256' },
+ { name: '_addr', type: 'address' },
+ ],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'deposit',
+ inputs: [
+ { name: '_value', type: 'uint256' },
+ { name: '_addr', type: 'address' },
+ { name: '_claim_rewards', type: 'bool' },
+ ],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'withdraw',
+ inputs: [
+ { name: '_value', type: 'uint256' },
+ { name: '_addr', type: 'address' },
+ ],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'withdraw',
+ inputs: [
+ { name: '_value', type: 'uint256' },
+ { name: '_addr', type: 'address' },
+ { name: '_claim_rewards', type: 'bool' },
+ ],
+ outputs: [],
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'transfer',
+ inputs: [
+ { name: '_to', type: 'address' },
+ { name: '_value', type: 'uint256' },
+ ],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 10954952,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'transferFrom',
+ inputs: [
+ { name: '_from', type: 'address' },
+ { name: '_to', type: 'address' },
+ { name: '_value', type: 'uint256' },
+ ],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 10992902,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'approve',
+ inputs: [
+ { name: '_spender', type: 'address' },
+ { name: '_value', type: 'uint256' },
+ ],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 39391,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'increaseAllowance',
+ inputs: [
+ { name: '_spender', type: 'address' },
+ { name: '_added_value', type: 'uint256' },
+ ],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 41935,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'decreaseAllowance',
+ inputs: [
+ { name: '_spender', type: 'address' },
+ { name: '_subtracted_value', type: 'uint256' },
+ ],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 41959,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'add_reward',
+ inputs: [
+ { name: '_reward_token', type: 'address' },
+ { name: '_distributor', type: 'address' },
+ ],
+ outputs: [],
+ gas: 117879,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'set_reward_distributor',
+ inputs: [
+ { name: '_reward_token', type: 'address' },
+ { name: '_distributor', type: 'address' },
+ ],
+ outputs: [],
+ gas: 45535,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'set_claimer',
+ inputs: [{ name: '_claimer', type: 'address' }],
+ outputs: [],
+ gas: 42964,
+ },
+ {
+ stateMutability: 'nonpayable',
+ type: 'function',
+ name: 'deposit_reward_token',
+ inputs: [
+ { name: '_reward_token', type: 'address' },
+ { name: '_amount', type: 'uint256' },
+ ],
+ outputs: [],
+ gas: 2883978,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'staking_token',
+ inputs: [],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 2958,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'decimal_staking_token',
+ inputs: [],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 2988,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'balanceOf',
+ inputs: [{ name: 'arg0', type: 'address' }],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3233,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'totalSupply',
+ inputs: [],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3048,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'allowance',
+ inputs: [
+ { name: 'arg0', type: 'address' },
+ { name: 'arg1', type: 'address' },
+ ],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3508,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'name',
+ inputs: [],
+ outputs: [{ name: '', type: 'string' }],
+ gas: 13338,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'symbol',
+ inputs: [],
+ outputs: [{ name: '', type: 'string' }],
+ gas: 11091,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'integrate_checkpoint_of',
+ inputs: [{ name: 'arg0', type: 'address' }],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3383,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'reward_count',
+ inputs: [],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3198,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'reward_tokens',
+ inputs: [{ name: 'arg0', type: 'uint256' }],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 3273,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'reward_data',
+ inputs: [{ name: 'arg0', type: 'address' }],
+ outputs: [
+ { name: 'token', type: 'address' },
+ { name: 'distributor', type: 'address' },
+ { name: 'period_finish', type: 'uint256' },
+ { name: 'rate', type: 'uint256' },
+ { name: 'last_update', type: 'uint256' },
+ { name: 'integral', type: 'uint256' },
+ ],
+ gas: 14703,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'rewards_receiver',
+ inputs: [{ name: 'arg0', type: 'address' }],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 3503,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'reward_integral_for',
+ inputs: [
+ { name: 'arg0', type: 'address' },
+ { name: 'arg1', type: 'address' },
+ ],
+ outputs: [{ name: '', type: 'uint256' }],
+ gas: 3748,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'registry',
+ inputs: [],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 3348,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'claimer',
+ inputs: [],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 3378,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'initialized',
+ inputs: [],
+ outputs: [{ name: '', type: 'bool' }],
+ gas: 3408,
+ },
+ {
+ stateMutability: 'view',
+ type: 'function',
+ name: 'vault',
+ inputs: [],
+ outputs: [{ name: '', type: 'address' }],
+ gas: 3438,
+ },
+] as const
diff --git a/src/apps/stake-dao/abis/stakeDaoVault.ts b/src/apps/stake-dao/abis/stakeDaoVault.ts
new file mode 100644
index 00000000..7c11b41a
--- /dev/null
+++ b/src/apps/stake-dao/abis/stakeDaoVault.ts
@@ -0,0 +1,299 @@
+// From https://arbiscan.io/address/0x9bc3c06eb36cf8b942da1b619969759a277631e0#code
+export const stakeDaoVaultAbi = [
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_depositor',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_staker',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: '_amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Deposit',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: false, internalType: 'uint8', name: 'version', type: 'uint8' },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_depositor',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: '_amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'GOVERNANCE',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'STRATEGY',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'active',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
+ ],
+ name: 'decreaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_staker', type: 'address' },
+ { internalType: 'uint256', name: '_amount', type: 'uint256' },
+ ],
+ name: 'deposit',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
+ ],
+ name: 'increaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_token', type: 'address' },
+ { internalType: 'string', name: 'name_', type: 'string' },
+ { internalType: 'string', name: 'symbol_', type: 'string' },
+ { internalType: 'address', name: '_registry', type: 'address' },
+ { internalType: 'address', name: '_sdGauge', type: 'address' },
+ ],
+ name: 'init',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'migrate',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'newVault',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'registry',
+ outputs: [
+ {
+ internalType: 'contract ICommonRegistryXChain',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'sdGauge',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_newVault', type: 'address' }],
+ name: 'setMigration',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'token',
+ outputs: [
+ { internalType: 'contract ERC20Upgradeable', name: '', type: 'address' },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }],
+ name: 'withdraw',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'withdrawAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/stake-dao/positions.e2e.ts b/src/apps/stake-dao/positions.e2e.ts
new file mode 100644
index 00000000..1b0be748
--- /dev/null
+++ b/src/apps/stake-dao/positions.e2e.ts
@@ -0,0 +1,24 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe.each([NetworkId['arbitrum-one']])(
+ 'getPositionDefinitions for networkId %s',
+ (networkId) => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should get definitions successfully when no address is provided', async () => {
+ const positions = await hook.getPositionDefinitions({ networkId, t })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ })
+ },
+)
diff --git a/src/apps/stake-dao/positions.ts b/src/apps/stake-dao/positions.ts
new file mode 100644
index 00000000..330df9f6
--- /dev/null
+++ b/src/apps/stake-dao/positions.ts
@@ -0,0 +1,175 @@
+import {
+ AppTokenPosition,
+ ContractPositionDefinition,
+ PositionDefinition,
+ PositionsHook,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import { NetworkId } from '../../types/networkId'
+import { getClient } from '../../runtime/client'
+import { stakeDaoVaultAbi } from './abis/stakeDaoVault'
+import { Address, zeroAddress } from 'viem'
+import { stakeDaoGaugeAbi } from './abis/stakeDaoGauge'
+import { toDecimalNumber } from '../../types/numbers'
+import { getTokenId } from '../../runtime/getTokenId'
+
+// Each vault has a corresponding gauge contract
+// Unfortunately there's no API yet or public list consumable programmatically
+// So we have to hardcode the addresses for now
+// Though I asked on their discord (2024-06-19) and an SDK/API is in the works.
+const SD_VAULT_ADDRESSES_BY_NETWORK_ID: Record = {
+ [NetworkId['celo-mainnet']]: [],
+ [NetworkId['celo-alfajores']]: [],
+ [NetworkId['ethereum-mainnet']]: [],
+ [NetworkId['ethereum-sepolia']]: [],
+ [NetworkId['arbitrum-one']]: [
+ '0xf82dc74d73bd2e4274fbd087fecb7720f02c3abc',
+ '0x37264bfe5cdbac34177d5a4833f07a7cf81d0543',
+ '0x68ef2cf45cfc155ca5431956f25d7b8c496127bb',
+ '0x0dbd661c988f9a28095ca200a683a082505f441e',
+ '0x9bc3c06eb36cf8b942da1b619969759a277631e0',
+ '0xe331847f990fe68fee41fdb06da307ba67198a83',
+ '0x0f958528718b625c3aebd305dd2917a37570c56a',
+ '0xd9f0d304c45df6f61e45e20481c8d50b9844d8fc',
+ '0xd11f22a5e25462a43efaa6faaee9e620fa420f49',
+ '0x897ab1f979ad31e49dbc9ef8df517b2945a53705',
+ '0x61b7986dd9f1c41747b494680be1d7ef54265d6c',
+ '0xea13469e4d44246bb84ee8765ba5bd70d9f87729',
+ '0x3690d81b426ab51e31265f366b668849652aac45',
+ '0x1d0333263c4837900d1bd7ab9b27cf652ffeb3b4',
+ ],
+ [NetworkId['arbitrum-sepolia']]: [],
+ [NetworkId['op-mainnet']]: [],
+ [NetworkId['op-sepolia']]: [],
+ [NetworkId['polygon-pos-mainnet']]: [],
+ [NetworkId['polygon-pos-amoy']]: [],
+ [NetworkId['base-mainnet']]: [],
+ [NetworkId['base-sepolia']]: [],
+}
+
+async function getVaultPositionDefinitions(
+ networkId: NetworkId,
+ address: Address | undefined,
+): Promise {
+ const client = getClient(networkId)
+
+ const vaultAddresses = SD_VAULT_ADDRESSES_BY_NETWORK_ID[networkId]
+ const vaultsData = await client.multicall({
+ contracts: vaultAddresses.flatMap((vaultAddress) => [
+ {
+ address: vaultAddress,
+ abi: stakeDaoVaultAbi,
+ functionName: 'token',
+ },
+ {
+ address: vaultAddress,
+ abi: stakeDaoVaultAbi,
+ functionName: 'sdGauge',
+ },
+ ]),
+ allowFailure: false,
+ })
+
+ const vaults = vaultAddresses.map((address, i) => ({
+ address,
+ lpTokenAddress: (vaultsData[2 * i] as Address).toLowerCase() as Address,
+ sdGaugeAddress: (vaultsData[2 * i + 1] as Address).toLowerCase() as Address,
+ }))
+
+ // Call balanceOf and totalSupply for each gauge
+ const gaugesData = await client.multicall({
+ contracts: vaults.flatMap((vault) => [
+ {
+ address: vault.sdGaugeAddress,
+ abi: stakeDaoGaugeAbi,
+ functionName: 'balanceOf',
+ args: [address ?? zeroAddress],
+ },
+ {
+ address: vault.sdGaugeAddress,
+ abi: stakeDaoGaugeAbi,
+ functionName: 'totalSupply',
+ },
+ {
+ address: vault.sdGaugeAddress,
+ abi: stakeDaoGaugeAbi,
+ functionName: 'decimals',
+ },
+ ]),
+ allowFailure: false,
+ })
+
+ const consideredVaults = vaults
+ .map((vault, i) => ({
+ ...vault,
+ sdGauge: {
+ // When no address is provided, use 0n (in case zeroAddress has a balance)
+ balance: address ? (gaugesData[3 * i] as bigint) : 0n,
+ totalSupply: gaugesData[3 * i + 1] as bigint,
+ decimals: gaugesData[3 * i + 2] as bigint,
+ },
+ }))
+ .filter((vault) => (address ? vault.sdGauge.balance > 0 : true))
+
+ const positions = await Promise.all(
+ consideredVaults.map(async (vault) => {
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: vault.sdGaugeAddress,
+ tokens: [
+ { address: vault.lpTokenAddress, networkId },
+ // TODO: Add reward tokens
+ ],
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const poolToken = resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: vault.lpTokenAddress,
+ isNative: false,
+ })
+ ] as AppTokenPosition
+ return {
+ // Fallback until we have proper inter-app dependencies working
+ title: poolToken.displayProps?.title || poolToken.symbol,
+ description: 'Strategy',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/stake-dao.png',
+ manageUrl: 'https://www.stakedao.org/yield',
+ }
+ },
+ balances: async () => {
+ return [
+ toDecimalNumber(
+ vault.sdGauge.balance,
+ Number(vault.sdGauge.decimals),
+ ),
+ ]
+ },
+ }
+
+ return position
+ }),
+ )
+
+ return positions
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Stake DAO',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ return await getVaultPositionDefinitions(
+ networkId,
+ address ? (address as Address) : undefined,
+ )
+ },
+ async getAppTokenDefinition({ networkId, address }) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/ubeswap/data/farms.json b/src/apps/ubeswap/data/farms.json
index a84320cf..aeb0de84 100644
--- a/src/apps/ubeswap/data/farms.json
+++ b/src/apps/ubeswap/data/farms.json
@@ -393,5 +393,15 @@
"stakingAddress": "0xbd61DEb4459556d78b2133521AF91A13eB21e20E",
"farmName": "0x504c415354494b2d43454c4f0000000000000000000000000000000000000000",
"lpAddress": "0xC7e9418e0F9B211885457eD3429Bde9E4e830E0E"
+ },
+ {
+ "stakingAddress": "0xb5B6A87434F7a0CCc3DcC0DE60d1Ade3737aD263",
+ "farmName": "0x43454c4f2d574254430000000000000000000000000000000000000000000000",
+ "lpAddress": "0x70b24fE068e60e431792Ea177cCf087BEd2EF5F7"
+ },
+ {
+ "stakingAddress": "0x534408e91D755A0D898E1C508e987e8D0615B52c",
+ "farmName": "0x5542452d43454c4f000000000000000000000000000000000000000000000000",
+ "lpAddress": "0x29cB4536Ee663aCe6f7A5Ca1c3b8Ad68Be398cc0"
}
]
\ No newline at end of file
diff --git a/src/apps/ubeswap/positions.e2e.ts b/src/apps/ubeswap/positions.e2e.ts
index 0f1dcda1..b115ae8d 100644
--- a/src/apps/ubeswap/positions.e2e.ts
+++ b/src/apps/ubeswap/positions.e2e.ts
@@ -1,20 +1,40 @@
+import { t } from '../../../test/i18next'
+import { getPositions } from '../../runtime/getPositions'
+import { NetworkId } from '../../types/networkId'
import hook from './positions'
-describe('getPositionDefinitions', () => {
+// eslint-disable-next-line jest/no-disabled-tests -- disabled temporarily because the api is returning errors
+describe.skip('getPositionDefinitions', () => {
it('should get the address definitions successfully', async () => {
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
- // Simple check to make sure we got some definitions
- expect(positions.length).toBeGreaterThan(0)
+ const positions = await getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['ubeswap'],
+ t,
+ baseTokensInfo: {},
+ })
+
+ // Uniswap v2 farm definitions
+ expect(
+ positions.filter(
+ (position) => position.displayProps.description === 'Farm',
+ ).length,
+ ).toBeGreaterThan(0)
+
+ // Uniswap v3 definitions
+ expect(
+ positions.filter(
+ (position) => position.displayProps.description === 'Pool',
+ ).length,
+ ).toBeGreaterThan(0)
})
it('should get no definitions for an address with no blockchain interaction', async () => {
- const positions = await hook.getPositionDefinitions(
- 'celo',
- '0x0000000000000000000000000000000000007E57',
- )
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
expect(positions.length).toBe(0)
})
})
diff --git a/src/apps/ubeswap/positions.ts b/src/apps/ubeswap/positions.ts
index d7406cf1..68310abb 100644
--- a/src/apps/ubeswap/positions.ts
+++ b/src/apps/ubeswap/positions.ts
@@ -1,26 +1,33 @@
+import BigNumber from 'bignumber.js'
+import got from '../../utils/got'
+import { Address, createPublicClient, http } from 'viem'
+import { celo } from 'viem/chains'
+import { erc20Abi } from '../../abis/erc-20'
+import { getTokenId } from '../../runtime/getTokenId'
+import { NetworkId } from '../../types/networkId'
+import { DecimalNumber, toDecimalNumber } from '../../types/numbers'
import {
- PositionsHook,
AppTokenPosition,
AppTokenPositionDefinition,
ContractPositionDefinition,
PositionDefinition,
+ PositionsHook,
TokenDefinition,
} from '../../types/positions'
-import got from 'got'
-import BigNumber from 'bignumber.js'
-import { uniswapV2PairAbi } from './abis/uniswap-v2-pair'
-import { Address, createPublicClient, http } from 'viem'
-import { celo } from 'viem/chains'
-import { erc20Abi } from '../../abis/erc-20'
-import { DecimalNumber, toDecimalNumber } from '../../types/numbers'
+import { getUniswapV3PositionDefinitions } from '../uniswap/positions'
import { stakingRewardsAbi } from './abis/staking-rewards'
+import { uniswapV2PairAbi } from './abis/uniswap-v2-pair'
import farms from './data/farms.json'
+import { logger } from '../../log'
const client = createPublicClient({
chain: celo,
transport: http(),
})
+const UBESWAP_LOGO =
+ 'https://raw.githubusercontent.com/valora-inc/dapp-list/ab12ab234b4a6e01eff599c6bd0b7d5b44d6f39d/assets/ubeswap.png'
+
const PAIRS_QUERY = `
query getPairs($address: ID!) {
user(id: $address) {
@@ -35,7 +42,7 @@ const PAIRS_QUERY = `
`
async function getPoolPositionDefinition(
- network: string,
+ networkId: NetworkId,
poolAddress: Address,
): Promise {
const poolTokenContract = {
@@ -57,23 +64,35 @@ async function getPoolPositionDefinition(
})
const position: AppTokenPositionDefinition = {
type: 'app-token-definition',
- network,
+ networkId,
address: poolAddress.toLowerCase(),
tokens: [token0Address, token1Address].map((token) => ({
address: token.toLowerCase(),
- network,
+ networkId,
})),
- displayProps: ({ resolvedTokens }) => {
- const token0 = resolvedTokens[token0Address.toLowerCase()]
- const token1 = resolvedTokens[token1Address.toLowerCase()]
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const token0 =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token0Address,
+ })
+ ]
+ const token1 =
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token1Address,
+ })
+ ]
return {
title: `${token0.symbol} / ${token1.symbol}`,
description: 'Pool',
- imageUrl:
- 'https://raw.githubusercontent.com/valora-inc/dapp-list/main/assets/ubeswap.png',
+ imageUrl: UBESWAP_LOGO,
+ manageUrl: 'https://app.ubeswap.org/#/pool',
}
},
- pricePerShare: async ({ tokensByAddress }) => {
+ pricePerShare: async ({ tokensByTokenId }) => {
const [[reserve0, reserve1], totalSupply] = await client.multicall({
contracts: [
{
@@ -87,9 +106,24 @@ async function getPoolPositionDefinition(
],
allowFailure: false,
})
- const poolToken = tokensByAddress[poolAddress.toLowerCase()]
- const token0 = tokensByAddress[token0Address.toLowerCase()]
- const token1 = tokensByAddress[token1Address.toLowerCase()]
+ const poolToken =
+ tokensByTokenId[
+ getTokenId({ networkId, isNative: false, address: poolAddress })
+ ]
+ const token0 =
+ tokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token0Address,
+ })
+ ]
+ const token1 =
+ tokensByTokenId[
+ getTokenId({
+ networkId,
+ address: token1Address,
+ })
+ ]
const reserves = [
toDecimalNumber(reserve0, token0.decimals),
toDecimalNumber(reserve1, token1.decimals),
@@ -104,31 +138,39 @@ async function getPoolPositionDefinition(
}
async function getPoolPositionDefinitions(
- network: string,
+ networkId: NetworkId,
address: string,
): Promise {
// Get the pairs from Ubeswap via The Graph
- const { data } = await got
- .post('https://api.thegraph.com/subgraphs/name/ubeswap/ubeswap', {
- json: {
- query: PAIRS_QUERY,
- variables: {
- address: address.toLowerCase(),
+ const response = await got
+ .post(
+ 'https://gateway-arbitrum.network.thegraph.com/api/3f1b45f0fd92b4f414a3158b0381f482/subgraphs/id/JWDRLCwj4H945xEkbB6eocBSZcYnibqcJPJ8h9davFi',
+ {
+ json: {
+ query: PAIRS_QUERY,
+ variables: {
+ address: address.toLowerCase(),
+ },
},
},
- })
+ )
.json()
+ const data = response.data
+
+ if (!response.data) {
+ logger.warn({ response }, 'Got an invalid response from thegraph endpoint')
+ throw new Error('Failed to get pairs from Ubeswap')
+ }
+
const pairs: Address[] = (data.user?.liquidityPositions ?? [])
.filter((position: any) => Number(position.liquidityTokenBalance) > 0)
.map((position: any) => position.pair.id)
- // console.log({ pairs })
-
// Get all positions
const positions = await Promise.all(
pairs.map(async (pair) => {
- return getPoolPositionDefinition(network, pair)
+ return getPoolPositionDefinition(networkId, pair)
}),
)
@@ -136,7 +178,7 @@ async function getPoolPositionDefinitions(
}
async function getFarmPositionDefinitions(
- network: string,
+ networkId: NetworkId,
address: string,
): Promise {
// Call balanceOf and totalSupply for each farm stakingAddress
@@ -183,35 +225,45 @@ async function getFarmPositionDefinitions(
}))
.filter((farm) => farm.balance > 0)
- // console.log({ userFarms })
-
const positions = await Promise.all(
userFarms.map(async (farm) => {
const position: ContractPositionDefinition = {
type: 'contract-position-definition',
- network,
+ networkId,
address: farm.stakingAddress.toLowerCase(),
tokens: [
- { address: farm.lpAddress.toLowerCase(), network },
+ { address: farm.lpAddress.toLowerCase(), networkId },
{
address: farm.rewardsTokenAddress.toLowerCase(),
- network,
+ networkId,
category: 'claimable',
},
],
- displayProps: ({ resolvedTokens }) => {
- const poolToken = resolvedTokens[
- farm.lpAddress.toLowerCase()
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const poolToken = resolvedTokensByTokenId[
+ getTokenId({
+ networkId,
+ address: farm.lpAddress,
+ isNative: false,
+ })
] as AppTokenPosition
return {
title: poolToken.displayProps.title,
description: 'Farm',
imageUrl: poolToken.displayProps.imageUrl,
+ manageUrl: 'https://app.ubeswap.org/#/earn',
}
},
availableShortcutIds: ['claim-reward'],
- balances: async ({ resolvedTokens }) => {
- const poolToken = resolvedTokens[farm.lpAddress.toLowerCase()]
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const poolToken =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: farm.lpAddress,
+ networkId,
+ isNative: false,
+ })
+ ]
const share = new BigNumber(farm.balance.toString()).div(
farm.totalSupply.toString(),
)
@@ -235,8 +287,11 @@ async function getFarmPositionDefinitions(
toDecimalNumber(poolBalance, poolToken.decimals),
) as DecimalNumber
- const rewardsToken =
- resolvedTokens[farm.rewardsTokenAddress.toLowerCase()]
+ const rewardsTokenId = getTokenId({
+ address: farm.rewardsTokenAddress,
+ networkId,
+ })
+ const rewardsToken = resolvedTokensByTokenId[rewardsTokenId]
const rewardsBalance = toDecimalNumber(
farm.rewardsEarned,
rewardsToken.decimals,
@@ -253,25 +308,45 @@ async function getFarmPositionDefinitions(
return positions
}
+const UBESWAP_V3_NFT_MANAGER = '0x897387c7b996485c3aaa85c94272cd6c506f8c8f'
+const UBESWAP_V3_FACTORY = '0x67FEa58D5a5a4162cED847E13c2c81c73bf8aeC4'
+const UNI_V3_MULTICALL = '0xDD1dC48fEA48B3DE667dD3595624d5af4Fb04694'
+
+async function getV3Positions(networkId: NetworkId, address: Address) {
+ return getUniswapV3PositionDefinitions(
+ networkId,
+ address as Address,
+ UNI_V3_MULTICALL,
+ UBESWAP_V3_NFT_MANAGER,
+ UBESWAP_V3_FACTORY,
+ UBESWAP_LOGO,
+ )
+}
+
const hook: PositionsHook = {
getInfo() {
return {
- id: 'ubeswap',
name: 'Ubeswap',
- description: 'Decentralized exchange on Celo',
}
},
- async getPositionDefinitions(network, address) {
- const [poolDefinitions, farmDefinitions] = await Promise.all([
- getPoolPositionDefinitions(network, address),
- getFarmPositionDefinitions(network, address),
- ])
+ async getPositionDefinitions({ networkId, address }) {
+ if (networkId !== NetworkId['celo-mainnet'] || !address) {
+ // dapp is only on Celo, and implementation is hardcoded to Celo mainnet (contract addresses in particular)
+ return []
+ }
+ const [poolDefinitions, farmDefinitions, v3Definitions] = await Promise.all(
+ [
+ getPoolPositionDefinitions(networkId, address),
+ getFarmPositionDefinitions(networkId, address),
+ getV3Positions(networkId, address as Address),
+ ],
+ )
- return [...poolDefinitions, ...farmDefinitions]
+ return [...poolDefinitions, ...farmDefinitions, ...v3Definitions]
},
- getAppTokenDefinition({ network, address }: TokenDefinition) {
+ getAppTokenDefinition({ networkId, address }: TokenDefinition) {
// Assume that the address is a pool address
- return getPoolPositionDefinition(network, address as Address)
+ return getPoolPositionDefinition(networkId, address as Address)
},
}
diff --git a/src/apps/ubeswap/shortcuts.ts b/src/apps/ubeswap/shortcuts.ts
index a596c325..11e077a9 100644
--- a/src/apps/ubeswap/shortcuts.ts
+++ b/src/apps/ubeswap/shortcuts.ts
@@ -1,7 +1,9 @@
import { Address, createPublicClient, http, encodeFunctionData } from 'viem'
import { celo } from 'viem/chains'
-import { ShortcutsHook } from '../../types/shortcuts'
+import { createShortcut, ShortcutsHook } from '../../types/shortcuts'
import { stakingRewardsAbi } from './abis/staking-rewards'
+import { NetworkId } from '../../types/networkId'
+import { ZodAddressLowerCased } from '../../types/address'
const client = createPublicClient({
chain: celo,
@@ -9,15 +11,22 @@ const client = createPublicClient({
})
const hook: ShortcutsHook = {
- getShortcutDefinitions() {
+ async getShortcutDefinitions(networkId: NetworkId, _address?: string) {
+ if (networkId !== NetworkId['celo-mainnet']) {
+ return []
+ }
+
return [
- {
+ createShortcut({
id: 'claim-reward',
name: 'Claim',
description: 'Claim rewards for staked liquidity',
- networks: ['celo'],
+ networkIds: [NetworkId['celo-mainnet']],
category: 'claim',
- async onTrigger(network, address, positionAddress) {
+ triggerInputShape: {
+ positionAddress: ZodAddressLowerCased,
+ },
+ async onTrigger({ networkId, address, positionAddress }) {
// This isn't strictly needed, but will help while we're developing shortcuts
const { request } = await client.simulateContract({
address: positionAddress as Address, // This is the farm address
@@ -32,16 +41,18 @@ const hook: ShortcutsHook = {
functionName: request.functionName,
})
- return [
- {
- network,
- from: address,
- to: positionAddress,
- data,
- },
- ]
+ return {
+ transactions: [
+ {
+ networkId,
+ from: address,
+ to: positionAddress,
+ data,
+ },
+ ],
+ }
},
- },
+ }),
]
},
}
diff --git a/src/apps/uniswap/abis/user-positions.ts b/src/apps/uniswap/abis/user-positions.ts
new file mode 100644
index 00000000..d1ab6376
--- /dev/null
+++ b/src/apps/uniswap/abis/user-positions.ts
@@ -0,0 +1,118 @@
+export const userPositionsAbi = [
+ {
+ inputs: [],
+ name: 'T',
+ type: 'error',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract INonfungiblePositionManager',
+ name: 'positionsManager',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IUniswapV3Factory',
+ name: 'factory',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ ],
+ name: 'getPositions',
+ outputs: [
+ {
+ components: [
+ {
+ internalType: 'address',
+ name: 'poolAddress',
+ type: 'address',
+ },
+ {
+ internalType: 'uint256',
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint96',
+ name: 'nonce',
+ type: 'uint96',
+ },
+ {
+ internalType: 'address',
+ name: 'operator',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token0',
+ type: 'address',
+ },
+ {
+ internalType: 'address',
+ name: 'token1',
+ type: 'address',
+ },
+ {
+ internalType: 'uint24',
+ name: 'fee',
+ type: 'uint24',
+ },
+ {
+ internalType: 'int24',
+ name: 'tickLower',
+ type: 'int24',
+ },
+ {
+ internalType: 'int24',
+ name: 'tickUpper',
+ type: 'int24',
+ },
+ {
+ internalType: 'uint128',
+ name: 'liquidity',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount0',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'amount1',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'feeGrowthInside0LastX128',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint256',
+ name: 'feeGrowthInside1LastX128',
+ type: 'uint256',
+ },
+ {
+ internalType: 'uint128',
+ name: 'tokensOwed0',
+ type: 'uint128',
+ },
+ {
+ internalType: 'uint128',
+ name: 'tokensOwed1',
+ type: 'uint128',
+ },
+ ],
+ internalType: 'struct UniV3UserPositionsMulticall.UniV3Position[]',
+ name: '',
+ type: 'tuple[]',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/uniswap/positions.e2e.ts b/src/apps/uniswap/positions.e2e.ts
new file mode 100644
index 00000000..27506846
--- /dev/null
+++ b/src/apps/uniswap/positions.e2e.ts
@@ -0,0 +1,24 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe('getPositionDefinitions', () => {
+ it('should get the address definitions successfully', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ t,
+ })
+
+ expect(positions.length).toBeGreaterThan(0)
+ })
+
+ it('should get no definitions for an address with no blockchain interaction', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ t,
+ })
+ expect(positions.length).toBe(0)
+ })
+})
diff --git a/src/apps/uniswap/positions.ts b/src/apps/uniswap/positions.ts
new file mode 100644
index 00000000..e8782d26
--- /dev/null
+++ b/src/apps/uniswap/positions.ts
@@ -0,0 +1,175 @@
+import { Address } from 'viem'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { NetworkId } from '../../types/networkId'
+import { toDecimalNumber } from '../../types/numbers'
+import {
+ ContractPositionDefinition,
+ PositionsHook,
+ TokenDefinition,
+ UnknownAppTokenError,
+} from '../../types/positions'
+import { userPositionsAbi } from './abis/user-positions'
+
+const UNI_V3_ADDRESSES_BY_NETWORK_ID: {
+ [networkId in NetworkId]:
+ | {
+ factory: Address
+ nftPositions: Address
+ // Custom read-only contract. Code:
+ // https://github.com/celo-tracker/celo-tracker-contracts/blob/main/contracts/multicall/UniV3UserPositionsMulticall.sol
+ userPositionsMulticall: Address
+ }
+ | undefined
+} = {
+ // polygon not enabled yet
+ // [NetworkId.polygon]: {
+ // factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
+ // nftPositions: '0xc36442b4a4522e871399cd717abdd847ab11fe88',
+ // userPositionsMulticall: '',
+ // },
+ [NetworkId['celo-mainnet']]: {
+ factory: '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc',
+ nftPositions: '0x3d79EdAaBC0EaB6F08ED885C05Fc0B014290D95A',
+ userPositionsMulticall: '0xDD1dC48fEA48B3DE667dD3595624d5af4Fb04694',
+ },
+ [NetworkId['arbitrum-one']]: {
+ factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
+ nftPositions: '0xc36442b4a4522e871399cd717abdd847ab11fe88',
+ userPositionsMulticall: '0xd3E0fd14a7d2a2f0E89D99bfc004eAcccfbEB2C1',
+ },
+ [NetworkId['op-mainnet']]: {
+ factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
+ nftPositions: '0xc36442b4a4522e871399cd717abdd847ab11fe88',
+ userPositionsMulticall: '0xd3E0fd14a7d2a2f0E89D99bfc004eAcccfbEB2C1',
+ },
+ [NetworkId['ethereum-mainnet']]: {
+ factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
+ nftPositions: '0xc36442b4a4522e871399cd717abdd847ab11fe88',
+ userPositionsMulticall: '0xd983fe1235a4c9006ef65eceed7c33069ad35ad0',
+ },
+ [NetworkId['polygon-pos-mainnet']]: undefined, // TODO: ask Gonza to deploy the multicall
+ [NetworkId['base-mainnet']]: undefined, // TODO: ask Gonza to deploy the multicall
+
+ [NetworkId['ethereum-sepolia']]: undefined,
+ [NetworkId['arbitrum-sepolia']]: undefined,
+ [NetworkId['op-sepolia']]: undefined,
+ [NetworkId['celo-alfajores']]: undefined,
+ [NetworkId['polygon-pos-amoy']]: undefined,
+ [NetworkId['base-sepolia']]: undefined,
+}
+
+const UNISWAP_NETWORK_NAME: Partial> = {
+ [NetworkId['ethereum-mainnet']]: 'ethereum',
+ [NetworkId['op-mainnet']]: 'optimism',
+ [NetworkId['polygon-pos-mainnet']]: 'polygon',
+ [NetworkId['base-mainnet']]: 'base',
+ [NetworkId['arbitrum-one']]: 'arbitrum',
+ [NetworkId['celo-mainnet']]: 'celo',
+}
+
+export async function getUniswapV3PositionDefinitions(
+ networkId: NetworkId,
+ address: Address,
+ userPositionsMulticall: Address,
+ nftPositions: Address,
+ factory: Address,
+ imageUrl: string = 'https://raw.githubusercontent.com/valora-inc/dapp-list/ab12ab234b4a6e01eff599c6bd0b7d5b44d6f39d/assets/uniswap.png',
+): Promise {
+ const client = getClient(networkId)
+ const userPools = await client.readContract({
+ abi: userPositionsAbi,
+ address: userPositionsMulticall,
+ functionName: 'getPositions',
+ args: [nftPositions, factory, address as Address],
+ })
+
+ return userPools
+ .map((pool) => ({
+ ...pool,
+ token0: pool.token0.toLowerCase(),
+ token1: pool.token1.toLowerCase(),
+ }))
+ .filter((pool) => pool.liquidity > 0)
+ .map((pool) => {
+ return {
+ type: 'contract-position-definition',
+ networkId,
+ address: pool.poolAddress,
+ extraId: pool.tokenId.toString(),
+ tokens: [
+ { address: pool.token0, networkId },
+ { address: pool.token1, networkId },
+ ],
+ displayProps: ({ resolvedTokensByTokenId }) => ({
+ title: `${
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: pool.token0,
+ networkId,
+ })
+ ].symbol
+ } / ${
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: pool.token1,
+ networkId,
+ })
+ ].symbol
+ }`,
+ description: 'Pool',
+ imageUrl,
+ manageUrl: UNISWAP_NETWORK_NAME[networkId]
+ ? `https://app.uniswap.org/explore/pools/${UNISWAP_NETWORK_NAME[networkId]}/${pool.poolAddress}`
+ : undefined,
+ }),
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const token0Decimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: pool.token0,
+ networkId,
+ })
+ ].decimals
+ const token1Decimals =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: pool.token1,
+ networkId,
+ })
+ ].decimals
+ return [
+ toDecimalNumber(pool.amount0, token0Decimals),
+ toDecimalNumber(pool.amount1, token1Decimals),
+ ]
+ },
+ }
+ })
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Uniswap',
+ }
+ },
+ async getPositionDefinitions({ networkId, address }) {
+ const addresses = UNI_V3_ADDRESSES_BY_NETWORK_ID[networkId]
+ if (!addresses || !address) {
+ return []
+ }
+ const { factory, nftPositions, userPositionsMulticall } = addresses
+ return getUniswapV3PositionDefinitions(
+ networkId,
+ address as Address,
+ userPositionsMulticall,
+ nftPositions,
+ factory,
+ )
+ },
+ async getAppTokenDefinition({ networkId, address }: TokenDefinition) {
+ throw new UnknownAppTokenError({ networkId, address })
+ },
+}
+
+export default hook
diff --git a/src/apps/walletconnect/abis/staking.ts b/src/apps/walletconnect/abis/staking.ts
new file mode 100644
index 00000000..152d55ce
--- /dev/null
+++ b/src/apps/walletconnect/abis/staking.ts
@@ -0,0 +1,734 @@
+// From https://optimistic.etherscan.io/address/0xcf8c18bb67e18fc28d8ee48901b27f259bf40ba4#code
+
+export const stakingAbi = [
+ { inputs: [], name: 'AccessControlBadConfirmation', type: 'error' },
+ {
+ inputs: [
+ { internalType: 'address', name: 'account', type: 'address' },
+ { internalType: 'bytes32', name: 'neededRole', type: 'bytes32' },
+ ],
+ name: 'AccessControlUnauthorizedAccount',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'target', type: 'address' }],
+ name: 'AddressEmptyCode',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'AddressInsufficientBalance',
+ type: 'error',
+ },
+ { inputs: [], name: 'AlreadyCreatedLock', type: 'error' },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'currentTime', type: 'uint256' },
+ { internalType: 'uint256', name: 'lockEndTime', type: 'uint256' },
+ ],
+ name: 'ExpiredLock',
+ type: 'error',
+ },
+ { inputs: [], name: 'FailedInnerCall', type: 'error' },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'currentBlock', type: 'uint256' },
+ { internalType: 'uint256', name: 'requestedBlock', type: 'uint256' },
+ ],
+ name: 'FutureBlockNumber',
+ type: 'error',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'actualLockedAmount', type: 'uint256' },
+ {
+ internalType: 'uint256',
+ name: 'requiredLockedAmount',
+ type: 'uint256',
+ },
+ ],
+ name: 'InsufficientLockedAmount',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'addr', type: 'address' }],
+ name: 'InvalidAddress',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
+ name: 'InvalidAmount',
+ type: 'error',
+ },
+ { inputs: [], name: 'InvalidInitialization', type: 'error' },
+ {
+ inputs: [{ internalType: 'uint256', name: 'maxLock', type: 'uint256' }],
+ name: 'InvalidMaxLock',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'unlockTime', type: 'uint256' }],
+ name: 'InvalidUnlockTime',
+ type: 'error',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'attemptedDuration', type: 'uint256' },
+ { internalType: 'uint256', name: 'maxDuration', type: 'uint256' },
+ ],
+ name: 'LockMaxDurationExceeded',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'lockEndTime', type: 'uint256' }],
+ name: 'LockStillActive',
+ type: 'error',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'currentDuration', type: 'uint256' },
+ { internalType: 'uint256', name: 'attemptedDuration', type: 'uint256' },
+ ],
+ name: 'LockTimeNotIncreased',
+ type: 'error',
+ },
+ { inputs: [], name: 'NonExistentLock', type: 'error' },
+ { inputs: [], name: 'NotInitializing', type: 'error' },
+ { inputs: [], name: 'Paused', type: 'error' },
+ { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' },
+ {
+ inputs: [
+ { internalType: 'uint8', name: 'bits', type: 'uint8' },
+ { internalType: 'int256', name: 'value', type: 'int256' },
+ ],
+ name: 'SafeCastOverflowedIntDowncast',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'int256', name: 'value', type: 'int256' }],
+ name: 'SafeCastOverflowedIntToUint',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'token', type: 'address' }],
+ name: 'SafeERC20FailedOperation',
+ type: 'error',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'provider',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'amount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'locktime',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'type_',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'transferredAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'timestamp',
+ type: 'uint256',
+ },
+ ],
+ name: 'Deposit',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'provider',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'transferredAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'timestamp',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'endTimestamp',
+ type: 'uint256',
+ },
+ ],
+ name: 'ForcedWithdraw',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint64',
+ name: 'version',
+ type: 'uint64',
+ },
+ ],
+ name: 'Initialized',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'previousMaxLock',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newMaxLock',
+ type: 'uint256',
+ },
+ ],
+ name: 'MaxLockUpdated',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ {
+ indexed: true,
+ internalType: 'bytes32',
+ name: 'previousAdminRole',
+ type: 'bytes32',
+ },
+ {
+ indexed: true,
+ internalType: 'bytes32',
+ name: 'newAdminRole',
+ type: 'bytes32',
+ },
+ ],
+ name: 'RoleAdminChanged',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'sender',
+ type: 'address',
+ },
+ ],
+ name: 'RoleGranted',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'sender',
+ type: 'address',
+ },
+ ],
+ name: 'RoleRevoked',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'previousSupply',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'newSupply',
+ type: 'uint256',
+ },
+ ],
+ name: 'Supply',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'provider',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'totalAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'transferredAmount',
+ type: 'uint256',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'timestamp',
+ type: 'uint256',
+ },
+ ],
+ name: 'Withdraw',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'ACTION_CREATE_LOCK',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ACTION_DEPOSIT_FOR',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ACTION_INCREASE_LOCK_AMOUNT',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ACTION_INCREASE_UNLOCK_TIME',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'ACTION_UPDATE_LOCK',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'DEFAULT_ADMIN_ROLE',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'LOCKED_TOKEN_STAKER_ROLE',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MAX_LOCK_CAP',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'MULTIPLIER',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'blockNumber', type: 'uint256' },
+ ],
+ name: 'balanceOfAt',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'timestamp', type: 'uint256' },
+ ],
+ name: 'balanceOfAtTime',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'checkpoint',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'config',
+ outputs: [
+ {
+ internalType: 'contract WalletConnectConfig',
+ name: '',
+ type: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'unlockTime', type: 'uint256' },
+ ],
+ name: 'createLock',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'for_', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'unlockTime', type: 'uint256' },
+ ],
+ name: 'createLockFor',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'for_', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'depositFor',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'epoch',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'to', type: 'address' }],
+ name: 'forceWithdrawAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: 'role', type: 'bytes32' }],
+ name: 'getRoleAdmin',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ { internalType: 'address', name: 'account', type: 'address' },
+ ],
+ name: 'grantRole',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ { internalType: 'address', name: 'account', type: 'address' },
+ ],
+ name: 'hasRole',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
+ name: 'increaseLockAmount',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'for_', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'increaseLockAmountFor',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'newUnlockTime', type: 'uint256' },
+ ],
+ name: 'increaseUnlockTime',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ components: [
+ { internalType: 'address', name: 'admin', type: 'address' },
+ { internalType: 'address', name: 'config', type: 'address' },
+ ],
+ internalType: 'struct StakeWeight.Init',
+ name: 'init',
+ type: 'tuple',
+ },
+ ],
+ name: 'initialize',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'locks',
+ outputs: [
+ {
+ components: [
+ { internalType: 'int128', name: 'amount', type: 'int128' },
+ { internalType: 'uint256', name: 'end', type: 'uint256' },
+ {
+ internalType: 'uint256',
+ name: 'transferredAmount',
+ type: 'uint256',
+ },
+ ],
+ internalType: 'struct StakeWeight.LockedBalance',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'maxLock',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'epoch_', type: 'uint256' }],
+ name: 'pointHistory',
+ outputs: [
+ {
+ components: [
+ { internalType: 'int128', name: 'bias', type: 'int128' },
+ { internalType: 'int128', name: 'slope', type: 'int128' },
+ { internalType: 'uint256', name: 'timestamp', type: 'uint256' },
+ { internalType: 'uint256', name: 'blockNumber', type: 'uint256' },
+ ],
+ internalType: 'struct StakeWeight.Point',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ { internalType: 'address', name: 'callerConfirmation', type: 'address' },
+ ],
+ name: 'renounceRole',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'bytes32', name: 'role', type: 'bytes32' },
+ { internalType: 'address', name: 'account', type: 'address' },
+ ],
+ name: 'revokeRole',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'newMaxLock', type: 'uint256' }],
+ name: 'setMaxLock',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'timestamp', type: 'uint256' }],
+ name: 'slopeChanges',
+ outputs: [{ internalType: 'int128', name: '', type: 'int128' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'supply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }],
+ name: 'supportsInterface',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'blockNumber', type: 'uint256' }],
+ name: 'totalSupplyAt',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'timestamp', type: 'uint256' }],
+ name: 'totalSupplyAtTime',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ { internalType: 'uint256', name: 'unlockTime', type: 'uint256' },
+ ],
+ name: 'updateLock',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'userPointEpoch',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'user', type: 'address' },
+ { internalType: 'uint256', name: 'epoch_', type: 'uint256' },
+ ],
+ name: 'userPointHistory',
+ outputs: [
+ {
+ components: [
+ { internalType: 'int128', name: 'bias', type: 'int128' },
+ { internalType: 'int128', name: 'slope', type: 'int128' },
+ { internalType: 'uint256', name: 'timestamp', type: 'uint256' },
+ { internalType: 'uint256', name: 'blockNumber', type: 'uint256' },
+ ],
+ internalType: 'struct StakeWeight.Point',
+ name: '',
+ type: 'tuple',
+ },
+ ],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'withdrawAll',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],
+ name: 'withdrawAllFor',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+] as const
diff --git a/src/apps/walletconnect/positions.e2e.ts b/src/apps/walletconnect/positions.e2e.ts
new file mode 100644
index 00000000..d0501939
--- /dev/null
+++ b/src/apps/walletconnect/positions.e2e.ts
@@ -0,0 +1,14 @@
+import hook from './positions'
+import { NetworkId } from '../../types/networkId'
+import { t } from '../../../test/i18next'
+
+describe('getPositionDefinitions', () => {
+ it('should return the staked WCT position', async () => {
+ const positions = await hook.getPositionDefinitions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0xccc9576f841de93cd32bee7b98fe8b9bd3070e3d',
+ t,
+ })
+ expect(positions.length).toBeGreaterThan(0)
+ })
+})
diff --git a/src/apps/walletconnect/positions.ts b/src/apps/walletconnect/positions.ts
new file mode 100644
index 00000000..961565c3
--- /dev/null
+++ b/src/apps/walletconnect/positions.ts
@@ -0,0 +1,116 @@
+import {
+ PositionsHook,
+ ContractPositionDefinition,
+} from '../../types/positions'
+import { Address } from 'viem'
+import { toDecimalNumber } from '../../types/numbers'
+import { NetworkId } from '../../types/networkId'
+import { getClient } from '../../runtime/client'
+import { getTokenId } from '../../runtime/getTokenId'
+import { stakingAbi } from './abis/staking'
+import { TFunction } from 'i18next'
+
+const WCT_STAKING_CONFIG_BY_NETWORK_ID: {
+ [networkId: string]:
+ | {
+ stakingAddress: Address
+ tokenAddress: Address
+ }
+ | undefined
+} = {
+ [NetworkId['op-mainnet']]: {
+ stakingAddress: '0x521b4c065bbdbe3e20b3727340730936912dfa46',
+ tokenAddress: '0xef4461891dfb3ac8572ccf7c794664a8dd927945',
+ },
+}
+
+async function getStakedWctPositionDefinition(
+ networkId: NetworkId,
+ address: Address,
+ t: TFunction<'translation', undefined>,
+): Promise {
+ const wctStakingConfig = WCT_STAKING_CONFIG_BY_NETWORK_ID[networkId]
+ if (!wctStakingConfig) {
+ return undefined
+ }
+
+ const client = getClient(networkId)
+ const locks = await client.readContract({
+ address: wctStakingConfig.stakingAddress,
+ abi: stakingAbi,
+ functionName: 'locks',
+ args: [address],
+ })
+
+ if (locks.amount === 0n) {
+ return undefined
+ }
+
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: wctStakingConfig.stakingAddress,
+ tokens: [{ address: wctStakingConfig.tokenAddress, networkId }],
+ displayProps: ({ resolvedTokensByTokenId }) => {
+ const token =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: wctStakingConfig.tokenAddress,
+ networkId,
+ })
+ ]
+ return {
+ title: t('walletconnect.stakedWct.title'),
+ description: t('walletconnect.stakedWct.description', {
+ amount: toDecimalNumber(locks.amount, token.decimals).toFormat(2),
+ date: new Date(Number(locks.end * 1000n)).toLocaleDateString(
+ undefined,
+ {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ },
+ ),
+ }),
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/WCT.png',
+ manageUrl: 'https://profile.walletconnect.network',
+ }
+ },
+ balances: async ({ resolvedTokensByTokenId }) => {
+ const token =
+ resolvedTokensByTokenId[
+ getTokenId({
+ address: wctStakingConfig.tokenAddress,
+ networkId,
+ })
+ ]
+
+ return [toDecimalNumber(locks.amount, token.decimals)]
+ },
+ }
+
+ return position
+}
+
+const hook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'WalletConnect',
+ }
+ },
+ async getPositionDefinitions({ networkId, address, t }) {
+ if (!address) {
+ return []
+ }
+
+ const position = await getStakedWctPositionDefinition(
+ networkId,
+ address as Address,
+ t,
+ )
+ return position ? [position] : []
+ },
+}
+
+export default hook
diff --git a/src/config/index.test.ts b/src/config/index.test.ts
new file mode 100644
index 00000000..fb3f85cc
--- /dev/null
+++ b/src/config/index.test.ts
@@ -0,0 +1,31 @@
+import { networkIdToRpcUrlTransform } from '.'
+
+describe('config', () => {
+ describe('networkIdToRpcUrlTransform', () => {
+ it('parses network id/rpc url pairs joined by |, and pairs separated by spaces', () => {
+ const input =
+ 'ethereum-mainnet|https://my-endpoint-name.quiknode.pro/my-api-key celo-mainnet|https://forno.celo.org'
+ const expected = {
+ 'ethereum-mainnet': 'https://my-endpoint-name.quiknode.pro/my-api-key',
+ 'celo-mainnet': 'https://forno.celo.org',
+ }
+ expect(networkIdToRpcUrlTransform(input)).toStrictEqual(expected)
+ })
+ it('throws an error if the network id is invalid', () => {
+ const input =
+ 'invalid-network-id|https://my-endpoint-name.quiknode.pro/my-api-key'
+ expect(() => networkIdToRpcUrlTransform(input)).toThrow(
+ 'Invalid network id: invalid-network-id',
+ )
+ })
+ it('throws an error if the rpc url is empty', () => {
+ const input = 'ethereum-mainnet|'
+ expect(() => networkIdToRpcUrlTransform(input)).toThrow(
+ 'Invalid rpc url for network id: ethereum-mainnet',
+ )
+ })
+ it('returns an empty object if the input is empty', () => {
+ expect(networkIdToRpcUrlTransform('')).toStrictEqual({})
+ })
+ })
+})
diff --git a/src/config/index.ts b/src/config/index.ts
new file mode 100644
index 00000000..5708fa47
--- /dev/null
+++ b/src/config/index.ts
@@ -0,0 +1,92 @@
+import { z } from 'zod'
+import * as dotenv from 'dotenv'
+import { NetworkId } from '../types/networkId'
+
+export interface Config {
+ GET_TOKENS_INFO_URL: string
+ NETWORK_ID_TO_RPC_URL: Partial>
+ GOOGLE_CLOUD_PROJECT: string
+ POSITION_IDS: string[]
+ SHORTCUT_IDS: string[]
+ EARN_SUPPORTED_NETWORK_IDS: NetworkId[]
+ SIMULATE_TRANSACTIONS_URL?: string
+ GET_SWAP_QUOTE_URL: string
+ ALLBRIDGE_API_KEY?: string
+}
+
+export function networkIdToRpcUrlTransform(val: string | undefined) {
+ if (!val) {
+ return {}
+ }
+ // expected format: network id/rpc url pairs joined by |, and pairs separated by spaces
+ // example: 'ethereum-mainnet|https://my-endpoint-name.quiknode.pro/my-api-key celo-mainnet|https://forno.celo.org'
+ const pairs: [networkId: NetworkId, rpcUrl: string][] = val
+ .split(' ')
+ .map((pairString: string) => {
+ const [networkIdString, rpcUrl] = pairString.split('|')
+ if (rpcUrl === '') {
+ throw new Error(`Invalid rpc url for network id: ${networkIdString}`)
+ }
+ if (!(networkIdString in NetworkId)) {
+ throw new Error(`Invalid network id: ${networkIdString}`)
+ }
+ return [networkIdString as NetworkId, rpcUrl]
+ })
+ return Object.fromEntries(pairs)
+}
+
+export function getConfig(): Config {
+ dotenv.config()
+ const sharedSchema = z.object({
+ GET_TOKENS_INFO_URL: z.string(),
+ NETWORK_ID_TO_RPC_URL: z
+ .string()
+ .optional()
+ .transform(networkIdToRpcUrlTransform),
+ SIMULATE_TRANSACTIONS_URL: z.string().optional(),
+ GET_SWAP_QUOTE_URL: z.string(),
+ })
+
+ const productionSchema = sharedSchema.extend({
+ GOOGLE_CLOUD_PROJECT: z.string().min(1),
+ POSITION_IDS: z.string().transform((val) => val.split(',')),
+ SHORTCUT_IDS: z.string().transform((val) => val.split(',')),
+ EARN_SUPPORTED_NETWORK_IDS: z
+ .string()
+ .transform((val) => val.split(',') as NetworkId[]),
+ ALLBRIDGE_API_KEY: z.string().optional(),
+ })
+
+ // Provide defaults in development
+ // TODO: consider providing a default .env.development file instead
+ const developmentSchema = sharedSchema.extend({
+ GET_TOKENS_INFO_URL: z
+ .string()
+ .default('https://api.mainnet.valora.xyz/getTokensInfoWithPrices'),
+ GOOGLE_CLOUD_PROJECT: z.string().default('dev-project'),
+ POSITION_IDS: z
+ .string()
+ .default('')
+ .transform((val) => (val === '' ? [] : val.split(','))),
+ SHORTCUT_IDS: z
+ .string()
+ .default('')
+ .transform((val) => (val === '' ? [] : val.split(','))),
+ EARN_SUPPORTED_NETWORK_IDS: z
+ .string()
+ .default('')
+ .transform((val) =>
+ val === '' ? ([] as NetworkId[]) : (val.split(',') as NetworkId[]),
+ ),
+ SIMULATE_TRANSACTIONS_URL: z
+ .string()
+ .default('https://api.mainnet.valora.xyz/simulateTransactions'),
+ GET_SWAP_QUOTE_URL: z
+ .string()
+ .default('https://api.mainnet.valora.xyz/getSwapQuote'),
+ })
+
+ return process.env.NODE_ENV === 'production'
+ ? productionSchema.parse(process.env)
+ : developmentSchema.parse(process.env)
+}
diff --git a/src/log/index.ts b/src/log/index.ts
new file mode 100644
index 00000000..2483032c
--- /dev/null
+++ b/src/log/index.ts
@@ -0,0 +1,7 @@
+import { createLogger } from '@valora/logging'
+
+export const logger = createLogger({
+ redact: {
+ paths: ['req.headers.authorization', 'req.headers.cookie'],
+ },
+})
diff --git a/src/runtime/client.ts b/src/runtime/client.ts
new file mode 100644
index 00000000..fdd9140a
--- /dev/null
+++ b/src/runtime/client.ts
@@ -0,0 +1,64 @@
+import { Chain, createPublicClient, http, PublicClient } from 'viem'
+import {
+ arbitrum,
+ arbitrumSepolia,
+ celo,
+ celoAlfajores,
+ mainnet,
+ optimism,
+ optimismSepolia,
+ sepolia,
+ polygon,
+ polygonAmoy,
+ base,
+ baseSepolia,
+} from 'viem/chains'
+import { NetworkId } from '../types/networkId'
+import { getConfig } from '../config'
+
+const networkIdToViemChain: Record = {
+ [NetworkId['celo-mainnet']]: celo,
+ [NetworkId['ethereum-mainnet']]: mainnet,
+ [NetworkId['arbitrum-one']]: arbitrum,
+ [NetworkId['op-mainnet']]: optimism,
+ [NetworkId['celo-alfajores']]: celoAlfajores,
+ [NetworkId['ethereum-sepolia']]: sepolia,
+ [NetworkId['arbitrum-sepolia']]: arbitrumSepolia,
+ [NetworkId['op-sepolia']]: optimismSepolia,
+ [NetworkId['polygon-pos-mainnet']]: polygon,
+ [NetworkId['polygon-pos-amoy']]: polygonAmoy,
+ [NetworkId['base-mainnet']]: base,
+ [NetworkId['base-sepolia']]: baseSepolia,
+}
+
+const clientsCache = new Map<
+ NetworkId,
+ PublicClient, Chain> | undefined
+>()
+
+export function getClient(
+ networkId: NetworkId,
+): PublicClient, Chain> {
+ let client = clientsCache.get(networkId)
+ if (client) {
+ return client
+ }
+ const rpcUrl = getConfig().NETWORK_ID_TO_RPC_URL[networkId]
+ client = createPublicClient({
+ chain: networkIdToViemChain[networkId],
+ transport: http(rpcUrl),
+ // This enables call batching via multicall
+ // meaning client.call, client.readContract, etc. will batch calls (using multicall)
+ // when the promises are scheduled in the same event loop tick (or within `wait` ms)
+ // for instance when Promise.all is used
+ // Note: directly calling multiple client.multicall won't batch, they are sent separately
+ // See https://viem.sh/docs/clients/public.html#eth_call-aggregation-via-multicall
+ batch: {
+ multicall: {
+ wait: 0,
+ },
+ },
+ })
+ clientsCache.set(networkId, client)
+ return client
+}
diff --git a/src/runtime/getPositionId.test.ts b/src/runtime/getPositionId.test.ts
new file mode 100644
index 00000000..cf3de917
--- /dev/null
+++ b/src/runtime/getPositionId.test.ts
@@ -0,0 +1,84 @@
+import { NetworkId } from '../types/networkId'
+import { toDecimalNumber } from '../types/numbers'
+import { getPositionId } from './getPositionId'
+
+describe('getPositionId', () => {
+ it('returns the token ID for app-token-definition', () => {
+ expect(
+ getPositionId({
+ type: 'app-token-definition',
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0xda7f463c27ec862cfbf2369f3f74c364d050d93f',
+ tokens: [
+ {
+ address: '0x1e593f1fe7b61c53874b54ec0c59fd0d5eb8621e',
+ networkId: NetworkId['ethereum-mainnet'],
+ },
+ ],
+ displayProps: {
+ title: 'Test Hook',
+ description: '',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
+ },
+ pricePerShare: async () => {
+ return [toDecimalNumber(5n, 1)]
+ },
+ }),
+ ).toBe('ethereum-mainnet:0xda7f463c27ec862cfbf2369f3f74c364d050d93f')
+ })
+ it('returns the token ID with extra ID for contract-position-definition', () => {
+ expect(
+ getPositionId({
+ type: 'contract-position-definition',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e',
+ extraId: 'locked-celo',
+ tokens: [
+ {
+ address: '0x471ece3750da237f93b8e339c536989b8978a438',
+ networkId: NetworkId['celo-mainnet'],
+ },
+ ],
+ displayProps: {
+ title: 'Locked CELO Test',
+ description: '',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
+ },
+ balances: async () => {
+ return [toDecimalNumber(10n, 18)]
+ },
+ }),
+ ).toBe(
+ 'celo-mainnet:0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e:locked-celo',
+ )
+ })
+ it('returns the token ID for contract-position-definition if no extra ID is set', () => {
+ expect(
+ getPositionId({
+ type: 'contract-position-definition',
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e',
+ tokens: [
+ {
+ address: '0x471ece3750da237f93b8e339c536989b8978a438',
+ networkId: NetworkId['celo-mainnet'],
+ },
+ ],
+ displayProps: {
+ title: 'Locked CELO Test',
+ description: '',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
+ },
+ balances: async () => {
+ return [toDecimalNumber(10n, 18)]
+ },
+ }),
+ ).toBe('celo-mainnet:0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e')
+ })
+})
diff --git a/src/runtime/getPositionId.ts b/src/runtime/getPositionId.ts
new file mode 100644
index 00000000..bd62e0f2
--- /dev/null
+++ b/src/runtime/getPositionId.ts
@@ -0,0 +1,21 @@
+import { PositionDefinition } from '../types/positions'
+import { getTokenId } from './getTokenId'
+
+export function getPositionId(positionDefinition: PositionDefinition): string {
+ const tokenId = getTokenId({
+ networkId: positionDefinition.networkId,
+ address: positionDefinition.address,
+ })
+ switch (positionDefinition.type) {
+ case 'app-token-definition':
+ return tokenId
+ case 'contract-position-definition':
+ return (
+ tokenId +
+ (positionDefinition.extraId ? `:${positionDefinition.extraId}` : '')
+ )
+ default:
+ const assertNever: never = positionDefinition
+ return assertNever
+ }
+}
diff --git a/src/runtime/getPositions.e2e.ts b/src/runtime/getPositions.e2e.ts
index aaf044d2..9ceb19d2 100644
--- a/src/runtime/getPositions.e2e.ts
+++ b/src/runtime/getPositions.e2e.ts
@@ -1,33 +1,68 @@
-import { getPositions } from './getPositions'
+import { getBaseTokensInfo, getPositions } from './getPositions'
+import { NetworkId } from '../types/networkId'
+import { t } from '../../test/i18next'
+import { TokensInfo } from '../types/positions'
+import { getConfig } from '../config'
describe('getPositions', () => {
- it('should get the address positions successfully', async () => {
- const positions = await getPositions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- )
- // Simple check to make sure we got some definitions
- expect(positions.length).toBeGreaterThan(0)
+ let baseTokensInfo: TokensInfo = {}
+ beforeAll(async () => {
+ baseTokensInfo = await getBaseTokensInfo(getConfig().GET_TOKENS_INFO_URL)
})
- it('should get the address positions successfully for a specific app', async () => {
- const positions = await getPositions(
- 'celo',
- '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
- ['halofi'],
- )
- // Simple check to make sure we got some definitions
- expect(positions.length).toBeGreaterThan(0)
- for (const position of positions) {
- expect(position.appId).toBe('halofi')
- }
- })
+ it.each([NetworkId['celo-mainnet'], NetworkId['ethereum-mainnet']])(
+ 'should get the address positions successfully for networkId %s',
+ async (networkId) => {
+ const positions = await getPositions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ },
+ )
+
+ it.each([[NetworkId['ethereum-mainnet'], 'curve']])(
+ 'should get the address positions successfully for a specific app for networkId %s',
+ async (networkId: NetworkId, appId: string) => {
+ const positions = await getPositions({
+ networkId,
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: [appId],
+ t,
+ baseTokensInfo,
+ })
+ // Simple check to make sure we got some definitions
+ expect(positions.length).toBeGreaterThan(0)
+ for (const position of positions) {
+ expect(position.appId).toBe(appId)
+ }
+ },
+ )
it("should throw an error if the app doesn't exist", async () => {
await expect(
- getPositions('celo', '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d', [
- 'does-not-exist',
- ]),
+ getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['does-not-exist'],
+ t,
+ baseTokensInfo,
+ }),
+ ).rejects.toThrow(
+ /No app with id 'does-not-exist' found, available apps: \w+/,
+ )
+ await expect(
+ getPositions({
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ appIds: ['does-not-exist'],
+ t,
+ baseTokensInfo,
+ }),
).rejects.toThrow(
/No app with id 'does-not-exist' found, available apps: \w+/,
)
diff --git a/src/runtime/getPositions.test.ts b/src/runtime/getPositions.test.ts
new file mode 100644
index 00000000..f66fc99b
--- /dev/null
+++ b/src/runtime/getPositions.test.ts
@@ -0,0 +1,383 @@
+import { getPositions } from './getPositions'
+import * as hooks from './getHooks'
+import {
+ AppTokenPosition,
+ AppTokenPositionDefinition,
+ ContractPositionDefinition,
+ PositionsHook,
+ TokensInfo,
+ UnknownAppTokenError,
+} from '../types/positions'
+import { toDecimalNumber, toSerializedDecimalNumber } from '../types/numbers'
+import { logger } from '../log'
+import { NetworkId } from '../types/networkId'
+import * as mockTokensInfo from './mockTokensInfo.json'
+import { t } from '../../test/i18next'
+
+jest.mock('viem', () => ({
+ ...jest.requireActual('viem'),
+ createPublicClient: () => ({
+ readContract: (...args: any) => mockReadContract(...args),
+ }),
+}))
+
+const mockReadContract = jest.fn()
+
+const getHooksSpy = jest.spyOn(hooks, 'getHooks')
+const baseTokensInfo: TokensInfo = {}
+
+for (const [tokenId, tokenInfo] of Object.entries(mockTokensInfo)) {
+ baseTokensInfo[tokenId] = {
+ ...tokenInfo,
+ priceUsd: toSerializedDecimalNumber(tokenInfo.priceUsd ?? 0),
+ // We don't have this info here but it's not yet needed for base tokens anyway
+ balance: toDecimalNumber(0n, 0),
+ totalSupply: toDecimalNumber(0n, 0),
+ networkId: tokenInfo.networkId as NetworkId,
+ }
+}
+
+const lockedCeloTestHook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Locked CELO Test',
+ }
+ },
+ async getPositionDefinitions({ networkId }) {
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: '0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e',
+ tokens: [
+ { address: '0x471ece3750da237f93b8e339c536989b8978a438', networkId },
+ ],
+ displayProps: {
+ title: 'Locked CELO Test',
+ description: '',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
+ },
+ balances: async () => {
+ return [toDecimalNumber(10n, 18)]
+ },
+ }
+
+ return [position]
+ },
+}
+
+const failingTestHook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Failing Hook',
+ }
+ },
+ async getPositionDefinitions({ networkId: _networkId }) {
+ throw new Error('This hook fails')
+ },
+}
+
+const loggerErrorSpy = jest.spyOn(logger, 'error')
+const loggerWarnSpy = jest.spyOn(logger, 'warn')
+
+beforeEach(() => {
+ jest.clearAllMocks()
+})
+
+describe(getPositions, () => {
+ it('should ignore positions for hooks that throw errors', async () => {
+ getHooksSpy.mockResolvedValue({
+ 'locked-celo-test': lockedCeloTestHook,
+ 'failing-hook': failingTestHook,
+ })
+ const positions = await getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ expect(positions.length).toBe(1)
+ expect(positions.map((p) => p.appId)).toEqual(['locked-celo-test'])
+ expect(loggerErrorSpy).toHaveBeenCalledTimes(1)
+ expect(loggerErrorSpy).toHaveBeenCalledWith(
+ { err: new Error('This hook fails') },
+ 'Failed to get position definitions for failing-hook',
+ )
+ })
+
+ it('should throw an error when getAppTokenDefinition is needed but not implemented', async () => {
+ const testHook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Test Hook',
+ }
+ },
+ async getPositionDefinitions({ networkId }) {
+ const position: AppTokenPositionDefinition = {
+ type: 'app-token-definition',
+ networkId,
+ address: '0xda7f463c27ec862cfbf2369f3f74c364d050d93f',
+ tokens: [
+ // Intermediary token that would need to be resolved
+ {
+ address: '0x1e593f1fe7b61c53874b54ec0c59fd0d5eb8621e',
+ networkId,
+ },
+ ],
+ displayProps: {
+ title: 'Test Hook',
+ description: '',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ manageUrl: undefined,
+ },
+ pricePerShare: async () => {
+ return [toDecimalNumber(5n, 1)]
+ },
+ }
+
+ return [position]
+ },
+ }
+ getHooksSpy.mockResolvedValue({
+ 'test-hook': testHook,
+ })
+ await expect(
+ getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ }),
+ ).rejects.toThrow(
+ "Positions hook for app 'test-hook' does not implement 'getAppTokenDefinition'. Please implement it to resolve the intermediary app token definition for 0x1e593f1fe7b61c53874b54ec0c59fd0d5eb8621e (celo-mainnet)",
+ )
+ })
+
+ it("should use the fallbackPriceUsd if the token can't be found", async () => {
+ const testHook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Beefy Price Escape',
+ }
+ },
+
+ async getPositionDefinitions({ networkId }) {
+ if (networkId !== NetworkId['op-mainnet']) {
+ return []
+ }
+
+ return [
+ {
+ type: 'app-token-definition',
+ networkId,
+ // Beefy crvUSD/WBTC/WETH Vault
+ // https://app.beefy.com/vault/curve-op-tricrypto-crvusd
+ address: '0xf82160Bad52C235102174aE5E7f36d5099DEEad3',
+ tokens: [
+ {
+ // Underlying Curve LP token
+ address: '0x4456d13Fc6736e8e8330394c0C622103E06ea419',
+ networkId,
+ // Fallback until we can properly decompose the token into base tokens
+ fallbackPriceUsd: toSerializedDecimalNumber(0.5),
+ },
+ ],
+ // Meaning that 1 share of the vault is worth 2 underlying tokens
+ pricePerShare: [toDecimalNumber(2n, 0)],
+ displayProps: {
+ title: 'Beefy crvUSD/WBTC/WETH Vault',
+ description: 'Vault',
+ imageUrl: '',
+ manageUrl: undefined,
+ },
+ },
+ ]
+ },
+
+ async getAppTokenDefinition(tokenDefinition) {
+ throw new UnknownAppTokenError(tokenDefinition)
+ },
+ }
+
+ mockReadContract.mockImplementation(async ({ address, functionName }) => {
+ switch (functionName) {
+ case 'symbol':
+ switch (address) {
+ case '0x4456d13Fc6736e8e8330394c0C622103E06ea419':
+ return '3c-crvUSD'
+ case '0xf82160Bad52C235102174aE5E7f36d5099DEEad3':
+ return 'mooCurveTriCrypto-crvUSD'
+ default:
+ throw new Error(`Unexpected token address: ${address}`)
+ }
+ case 'decimals':
+ return 18
+ case 'totalSupply':
+ return 1000n * 10n ** 18n
+ case 'balanceOf':
+ return 30n * 10n ** 18n
+ default:
+ throw new Error(`Unexpected functionName called: ${functionName}`)
+ }
+ })
+ getHooksSpy.mockResolvedValue({
+ 'beefy-price-escape': testHook,
+ })
+ const positions = await getPositions({
+ networkId: NetworkId['op-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ expect(positions.length).toBe(1)
+ const beefyPosition = positions[0] as AppTokenPosition
+ expect(beefyPosition.appId).toBe('beefy-price-escape')
+ expect(beefyPosition.tokens.length).toBe(1)
+ expect(beefyPosition.tokens[0].tokenId).toBe(
+ 'op-mainnet:0x4456d13fc6736e8e8330394c0c622103e06ea419',
+ )
+ expect(beefyPosition.tokens[0].balance).toBe('60')
+ expect(beefyPosition.tokens[0].priceUsd).toBe('0.5') // Fallback price, since the token can't be found
+ expect(beefyPosition.balance).toBe('30')
+ expect(beefyPosition.priceUsd).toBe('1')
+ expect(beefyPosition.supply).toBe('1000')
+ })
+
+ it('should get tokens info for unlisted tokens once per unique token address and networkId', async () => {
+ const testHook: PositionsHook = {
+ getInfo() {
+ return {
+ name: 'Test Hook',
+ }
+ },
+ async getPositionDefinitions({ networkId }) {
+ const position: ContractPositionDefinition = {
+ type: 'contract-position-definition',
+ networkId,
+ address: '0x0000000000000000000000000000000000000001',
+ tokens: [
+ {
+ address: '0x000000000000000000000000000000000000000a',
+ networkId,
+ },
+ ],
+ displayProps: {
+ title: 'Test position',
+ description: '',
+ imageUrl: '',
+ manageUrl: undefined,
+ },
+ balances: async () => {
+ return [toDecimalNumber(10n, 18)]
+ },
+ }
+
+ return [
+ position,
+ {
+ ...position,
+ address: '0x0000000000000000000000000000000000000002',
+ tokens: [
+ {
+ // Same as the first position but with uppercase address
+ address: '0x000000000000000000000000000000000000000A',
+ networkId,
+ },
+ ],
+ },
+ ]
+ },
+ async getAppTokenDefinition(tokenDefinition) {
+ throw new UnknownAppTokenError(tokenDefinition)
+ },
+ }
+
+ mockReadContract.mockImplementation(async ({ functionName }) => {
+ switch (functionName) {
+ case 'symbol':
+ return 'T1'
+ case 'decimals':
+ return 18
+ case 'totalSupply':
+ return 1000n * 10n ** 18n
+ default:
+ throw new Error(`Unexpected functionName called: ${functionName}`)
+ }
+ })
+ getHooksSpy.mockResolvedValue({
+ 'test-hook': testHook,
+ })
+ const positions = await getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ // Just 3 calls to readContract, one for each unique token address and networkId
+ expect(mockReadContract).toHaveBeenCalledTimes(3)
+ expect(positions.length).toBe(2)
+ })
+
+ it('should warn and omit positions with the same address and networkId', async () => {
+ // testHook and testHook2 both return positions with the same address
+ // this should result in a warning and only one position being returned
+ getHooksSpy.mockResolvedValue({
+ 'test-hook': lockedCeloTestHook,
+ 'test-hook2': lockedCeloTestHook,
+ })
+ const positions = await getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ expect(positions.length).toBe(1)
+ expect(loggerWarnSpy).toHaveBeenCalledTimes(1)
+ expect(loggerWarnSpy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ duplicateDefinition: expect.objectContaining({
+ appId: 'test-hook2',
+ }),
+ initialDefinition: expect.objectContaining({
+ appId: 'test-hook',
+ }),
+ }),
+ 'Duplicate position definition detected in app test-hook2 for 0x6cc083aed9e3ebe302a6336dbc7c921c9f03349e (celo-mainnet). test-hook already defined it. Skipping it. If this is unexpected and the position is a contract-position-definition, please specify a unique extraId.',
+ )
+ })
+
+ it('should not warn about duplicates if the positions specify different extraIds', async () => {
+ getHooksSpy.mockResolvedValue({
+ 'test-hook': lockedCeloTestHook,
+ 'test-hook2': {
+ ...lockedCeloTestHook,
+ async getPositionDefinitions({ networkId }) {
+ return lockedCeloTestHook
+ .getPositionDefinitions({ networkId, t })
+ .then((positions) =>
+ positions.map((p) => ({
+ ...p,
+ extraId: 'unique-id',
+ })),
+ )
+ },
+ },
+ })
+ const positions = await getPositions({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x0000000000000000000000000000000000007e57',
+ appIds: [],
+ t,
+ baseTokensInfo,
+ })
+ expect(positions.length).toBe(2)
+ expect(loggerWarnSpy).toHaveBeenCalledTimes(0)
+ })
+})
diff --git a/src/runtime/getPositions.ts b/src/runtime/getPositions.ts
index 393aae74..296ec1a7 100644
--- a/src/runtime/getPositions.ts
+++ b/src/runtime/getPositions.ts
@@ -1,27 +1,22 @@
-// Allow console logs for now, since we're early in development
-/* eslint-disable no-console */
-import got from 'got'
+import got from '../utils/got'
import BigNumber from 'bignumber.js'
-import {
- Address,
- ContractFunctionExecutionError,
- createPublicClient,
- http,
-} from 'viem'
-import { celo } from '@wagmi/chains'
+import { Address, ContractFunctionExecutionError } from 'viem'
import { erc20Abi } from '../abis/erc-20'
import {
- AbstractToken,
AppInfo,
AppTokenPosition,
AppTokenPositionDefinition,
ContractPosition,
ContractPositionDefinition,
+ DataProps,
DisplayProps,
Position,
PositionDefinition,
- PricePerShareContext,
+ ShortcutTriggerArgs,
Token,
+ TokenInfo,
+ TokensInfo,
+ UnknownAppTokenError,
} from '../types/positions'
import {
DecimalNumber,
@@ -29,83 +24,127 @@ import {
toSerializedDecimalNumber,
} from '../types/numbers'
import { getHooks } from './getHooks'
+import { logger } from '../log'
+import { NetworkId } from '../types/networkId'
+import { getClient } from './client'
+import { getTokenId } from './getTokenId'
+import { isNative } from './isNative'
+import { TFunction } from 'i18next'
+import { getPositionId } from './getPositionId'
interface RawTokenInfo {
- address: string
- name?: string
+ address?: string
+ name: string
symbol: string
decimals: number
- usdPrice?: string
imageUrl: string
+ tokenId: string
+ networkId: NetworkId
+ isNative?: boolean
+ priceUsd?: string
}
-interface TokenInfo extends Omit {
- imageUrl: string
-}
-
-type TokensInfo = Record
-
-type DefinitionsByAddress = Record
+type DefinitionsByPositionId = Record
type AppPositionDefinition = PositionDefinition & {
appId: string
}
-const client = createPublicClient({
- chain: celo,
- transport: http(),
-})
-
-async function getBaseTokensInfo(): Promise {
+export async function getBaseTokensInfo(
+ getTokensInfoUrl: string,
+ networkIds: NetworkId[] = [],
+): Promise {
// Get base tokens
- const data = await got
- .get(
- 'https://us-central1-celo-mobile-mainnet.cloudfunctions.net/getTokensInfo',
- )
- .json<{ tokens: Record }>()
+ const url = networkIds.length
+ ? `${getTokensInfoUrl}?networkIds=${networkIds.join(',')}`
+ : getTokensInfoUrl
+ const data = await got.get(url).json>()
// Map to TokenInfo
const tokensInfo: TokensInfo = {}
- for (const [address, tokenInfo] of Object.entries(data.tokens)) {
- const addressLowerCase = address.toLowerCase()
- tokensInfo[addressLowerCase] = {
- network: 'celo', // TODO: adjust for other networks
- address: addressLowerCase,
- symbol: tokenInfo.symbol,
- decimals: tokenInfo.decimals,
- imageUrl: tokenInfo.imageUrl,
- priceUsd: toSerializedDecimalNumber(tokenInfo.usdPrice ?? 0),
+ for (const [tokenId, tokenInfo] of Object.entries(data)) {
+ tokensInfo[tokenId] = {
+ ...tokenInfo,
+ priceUsd: toSerializedDecimalNumber(tokenInfo.priceUsd ?? 0),
+ // We don't have this info here but it's not yet needed for base tokens anyway
+ balance: toDecimalNumber(0n, 0),
+ totalSupply: toDecimalNumber(0n, 0),
}
}
return tokensInfo
}
-async function getERC20TokenInfo(address: Address): Promise {
+async function getERC20TokenInfo(
+ contractAddress: Address,
+ networkId: NetworkId,
+ address?: Address,
+): Promise {
+ const imageUrl = ''
+ const priceUsd = toSerializedDecimalNumber(0)
+
+ if (isNative({ address: contractAddress, networkId })) {
+ return {
+ address: undefined,
+ networkId,
+ symbol: 'ETH',
+ decimals: 18,
+ imageUrl,
+ priceUsd,
+ tokenId: getTokenId({
+ networkId: networkId,
+ isNative: true,
+ address: undefined, // address isn't used for native assets' token id at this time, but even if it was, we would probably not use 0xeee... because it is misleading and bug prone (no actual smart contract with that address exists) and not universal
+ }),
+ // TODO: get real values if we actually need them, but for now it's not needed
+ balance: toDecimalNumber(0n, 0),
+ totalSupply: toDecimalNumber(0n, 0),
+ }
+ }
+
+ const client = getClient(networkId)
const erc20Contract = {
- address: address,
+ address: contractAddress,
abi: erc20Abi,
} as const
- const [symbol, decimals] = await client.multicall({
- contracts: [
- {
- ...erc20Contract,
- functionName: 'symbol',
- },
- {
- ...erc20Contract,
- functionName: 'decimals',
- },
- ],
- allowFailure: false,
- })
+ // Intentionally NOT using multicall here
+ // so we benefit from multicall batching happening in the client
+ // when this function is called in Promise.all
+ const [symbol, decimals, totalSupply, balance] = await Promise.all([
+ client.readContract({
+ ...erc20Contract,
+ functionName: 'symbol',
+ }),
+ client.readContract({
+ ...erc20Contract,
+ functionName: 'decimals',
+ }),
+ client.readContract({
+ ...erc20Contract,
+ functionName: 'totalSupply',
+ }),
+ address
+ ? client.readContract({
+ ...erc20Contract,
+ functionName: 'balanceOf',
+ args: [address],
+ })
+ : undefined,
+ ])
return {
- network: 'celo',
- address: address,
- symbol: symbol,
- decimals: decimals,
- imageUrl: '',
- priceUsd: toSerializedDecimalNumber(0), // Should we use undefined?
+ tokenId: getTokenId({
+ networkId: networkId,
+ isNative: false,
+ address: contractAddress,
+ }),
+ networkId,
+ address: contractAddress,
+ symbol,
+ decimals,
+ priceUsd,
+ imageUrl,
+ balance: toDecimalNumber(balance ?? 0n, decimals),
+ totalSupply: toDecimalNumber(totalSupply, decimals),
}
}
@@ -142,27 +181,49 @@ function tokenWithUnderlyingBalance(
function getDisplayProps(
positionDefinition: PositionDefinition,
- resolvedTokens: Record>,
+ resolvedTokensByTokenId: Record>,
): DisplayProps {
if (typeof positionDefinition.displayProps === 'function') {
- return positionDefinition.displayProps({ resolvedTokens })
+ return positionDefinition.displayProps({ resolvedTokensByTokenId })
} else {
return positionDefinition.displayProps
}
}
+function getDataProps(
+ positionDefinition: PositionDefinition,
+ resolvedTokensByTokenId: Record>,
+): DataProps | undefined {
+ if (typeof positionDefinition.dataProps === 'function') {
+ return positionDefinition.dataProps({ resolvedTokensByTokenId })
+ } else {
+ return positionDefinition.dataProps
+ }
+}
+
+function getShortcutTriggerArgs(
+ positionDefinition: PositionDefinition,
+ tokensByTokenId: TokensInfo,
+): ShortcutTriggerArgs | undefined {
+ if (typeof positionDefinition.shortcutTriggerArgs === 'function') {
+ return positionDefinition.shortcutTriggerArgs({ tokensByTokenId })
+ } else {
+ return positionDefinition.shortcutTriggerArgs
+ }
+}
+
async function resolveAppTokenPosition(
- address: string,
+ _address: string | undefined,
positionDefinition: AppTokenPositionDefinition & { appId: string },
- tokensByAddress: TokensInfo,
- resolvedTokens: Record>,
+ tokensByTokenId: TokensInfo,
+ resolvedTokensByTokenId: Record>,
appInfo: AppInfo,
): Promise {
let pricePerShare: DecimalNumber[]
if (typeof positionDefinition.pricePerShare === 'function') {
pricePerShare = await positionDefinition.pricePerShare({
- tokensByAddress,
- } as PricePerShareContext)
+ tokensByTokenId,
+ })
} else {
pricePerShare = positionDefinition.pricePerShare
}
@@ -170,75 +231,84 @@ async function resolveAppTokenPosition(
let priceUsd = new BigNumber(0)
for (let i = 0; i < positionDefinition.tokens.length; i++) {
const token = positionDefinition.tokens[i]
- const tokenInfo = tokensByAddress[token.address]!
- priceUsd = priceUsd.plus(tokenInfo.priceUsd).times(pricePerShare[i])
+ const tokenInfo =
+ tokensByTokenId[
+ getTokenId({
+ networkId: token.networkId,
+ address: token.address,
+ })
+ ]
+ priceUsd = priceUsd.plus(pricePerShare[i].times(tokenInfo.priceUsd))
}
- const positionTokenInfo = tokensByAddress[positionDefinition.address]!
-
- const appTokenContract = {
- address: positionDefinition.address as Address,
- abi: erc20Abi,
- } as const
- const [balance, totalSupply] = await client.multicall({
- contracts: [
- {
- ...appTokenContract,
- functionName: 'balanceOf',
- args: [address as Address], // TODO: this is incorrect for intermediary app tokens
- },
- {
- ...appTokenContract,
- functionName: 'totalSupply',
- },
- ],
- allowFailure: false,
- })
-
- const displayProps = getDisplayProps(positionDefinition, resolvedTokens)
+ const positionTokenInfo =
+ tokensByTokenId[
+ getTokenId({
+ networkId: positionDefinition.networkId,
+ isNative: false,
+ address: positionDefinition.address,
+ })
+ ]!
+
+ const displayProps = getDisplayProps(
+ positionDefinition,
+ resolvedTokensByTokenId,
+ )
+ const dataProps = getDataProps(positionDefinition, resolvedTokensByTokenId)
+ const shortcutTriggerArgs =
+ getShortcutTriggerArgs(positionDefinition, tokensByTokenId) ?? {}
const position: AppTokenPosition = {
type: 'app-token',
- network: positionDefinition.network,
+ networkId: positionDefinition.networkId,
address: positionDefinition.address,
+ tokenId: getTokenId({
+ networkId: positionDefinition.networkId,
+ isNative: false,
+ address: positionDefinition.address,
+ }),
+ positionId: getPositionId(positionDefinition),
appId: positionDefinition.appId,
appName: appInfo.name,
symbol: positionTokenInfo.symbol,
decimals: positionTokenInfo.decimals,
label: displayProps.title,
displayProps,
+ dataProps,
tokens: positionDefinition.tokens.map((token, i) =>
tokenWithUnderlyingBalance(
- resolvedTokens[token.address],
- toDecimalNumber(balance, positionTokenInfo.decimals),
+ resolvedTokensByTokenId[
+ getTokenId({
+ networkId: token.networkId,
+ address: token.address,
+ })
+ ],
+ positionTokenInfo.balance,
pricePerShare[i],
),
),
pricePerShare: pricePerShare.map(toSerializedDecimalNumber),
priceUsd: toSerializedDecimalNumber(priceUsd),
- balance: toSerializedDecimalNumber(
- toDecimalNumber(balance, positionTokenInfo.decimals),
- ),
- supply: toSerializedDecimalNumber(
- toDecimalNumber(totalSupply, positionTokenInfo.decimals),
- ),
+ balance: toSerializedDecimalNumber(positionTokenInfo.balance),
+ supply: toSerializedDecimalNumber(positionTokenInfo.totalSupply),
availableShortcutIds: positionDefinition.availableShortcutIds ?? [],
+ shortcutTriggerArgs,
}
return position
}
async function resolveContractPosition(
- _address: string,
+ _address: string | undefined,
positionDefinition: ContractPositionDefinition & { appId: string },
- _tokensByAddress: TokensInfo,
- resolvedTokens: Record>,
+ tokensByTokenId: TokensInfo,
+ resolvedTokensByTokenId: Record>,
appInfo: AppInfo,
): Promise {
let balances: DecimalNumber[]
if (typeof positionDefinition.balances === 'function') {
balances = await positionDefinition.balances({
- resolvedTokens,
+ resolvedTokensByTokenId,
})
} else {
balances = positionDefinition.balances
@@ -247,7 +317,12 @@ async function resolveContractPosition(
const tokens = positionDefinition.tokens.map((token, i) =>
tokenWithUnderlyingBalance(
{
- ...resolvedTokens[token.address],
+ ...resolvedTokensByTokenId[
+ getTokenId({
+ networkId: token.networkId,
+ address: token.address,
+ })
+ ],
...(token.category && { category: token.category }),
},
balances[i],
@@ -258,23 +333,36 @@ async function resolveContractPosition(
let balanceUsd = new BigNumber(0)
for (let i = 0; i < positionDefinition.tokens.length; i++) {
const token = positionDefinition.tokens[i]
- const tokenInfo = resolvedTokens[token.address]
+ const tokenId = getTokenId({
+ networkId: token.networkId,
+ address: token.address,
+ })
+ const tokenInfo = resolvedTokensByTokenId[tokenId]
balanceUsd = balanceUsd.plus(balances[i].times(tokenInfo.priceUsd))
}
- const displayProps = getDisplayProps(positionDefinition, resolvedTokens)
+ const displayProps = getDisplayProps(
+ positionDefinition,
+ resolvedTokensByTokenId,
+ )
+ const dataProps = getDataProps(positionDefinition, resolvedTokensByTokenId)
+ const shortcutTriggerArgs =
+ getShortcutTriggerArgs(positionDefinition, tokensByTokenId) ?? {}
const position: ContractPosition = {
type: 'contract-position',
address: positionDefinition.address,
- network: positionDefinition.network,
+ networkId: positionDefinition.networkId,
+ positionId: getPositionId(positionDefinition),
appId: positionDefinition.appId,
appName: appInfo.name,
label: displayProps.title,
displayProps,
+ dataProps,
tokens: tokens,
balanceUsd: toSerializedDecimalNumber(balanceUsd),
availableShortcutIds: positionDefinition.availableShortcutIds ?? [],
+ shortcutTriggerArgs,
}
return position
@@ -295,41 +383,62 @@ function addSourceAppId(definition: T, sourceAppId: string) {
}
// This is the main logic to get positions
-export async function getPositions(
- network: string,
- address: string,
- appIds: string[] = [],
-) {
+export async function getPositions({
+ networkId,
+ address,
+ appIds = [],
+ t,
+ baseTokensInfo,
+}: {
+ networkId: NetworkId
+ address: string | undefined
+ appIds: string[]
+ t: TFunction<'translation', undefined>
+ baseTokensInfo: TokensInfo
+}) {
const hooksByAppId = await getHooks(appIds, 'positions')
// First get all position definitions for the given address
const definitions = await Promise.all(
- Object.entries(hooksByAppId).map(([appId, plugin]) =>
- plugin.getPositionDefinitions(network, address).then((definitions) => {
- return definitions.map((definition) => addAppId(definition, appId))
- }),
+ Object.entries(hooksByAppId).map(([appId, hook]) =>
+ hook.getPositionDefinitions({ networkId, address, t }).then(
+ (definitions) => {
+ return definitions.map((definition) => addAppId(definition, appId))
+ },
+ (err) => {
+ // In case of an error, log and return an empty array
+ // so other positions can still be resolved
+ logger.error(
+ { err },
+ `Failed to get position definitions for ${appId}`,
+ )
+ return []
+ },
+ ),
),
).then((definitions) => definitions.flat())
- console.log('positions definitions', JSON.stringify(definitions, null, ' '))
-
- // Get the base tokens info
- const baseTokensInfo = await getBaseTokensInfo()
+ logger.debug(
+ { definitions, count: definitions.length },
+ 'positions definitions',
+ )
let unlistedBaseTokensInfo: TokensInfo = {}
let definitionsToResolve: AppPositionDefinition[] = definitions
- const visitedDefinitions: DefinitionsByAddress = {}
+ const visitedDefinitions: DefinitionsByPositionId = {}
while (true) {
// Visit each definition we haven't visited yet
definitionsToResolve = definitionsToResolve.filter((definition) => {
- if (visitedDefinitions[definition.address]) {
+ const definitionPositionId = getPositionId(definition)
+
+ if (visitedDefinitions[definitionPositionId]) {
return false
}
- visitedDefinitions[definition.address] = definition
+ visitedDefinitions[definitionPositionId] = definition
return true
})
if (definitionsToResolve.length === 0) {
- console.log('No more positions to resolve')
+ logger.debug('No more positions to resolve')
break
}
@@ -338,22 +447,39 @@ export async function getPositions(
position.tokens.map((token) => addSourceAppId(token, position.appId)),
)
- console.log(
+ logger.debug(
+ { allTokenDefinitions, count: allTokenDefinitions.length },
'allTokenDefinitions',
- JSON.stringify(allTokenDefinitions, null, ' '),
)
// Get the tokens definitions for which we don't have the base token info or position definition
- const unresolvedTokenDefinitions = allTokenDefinitions.filter(
- (tokenDefinition) =>
- !{ ...baseTokensInfo, ...unlistedBaseTokensInfo }[
- tokenDefinition.address
- ] && !visitedDefinitions[tokenDefinition.address],
+ const unresolvedTokenDefinitionsByTokenId: Record<
+ string,
+ (typeof allTokenDefinitions)[number]
+ > = {}
+ for (const tokenDefinition of allTokenDefinitions) {
+ const definitionTokenId = getTokenId({
+ networkId: tokenDefinition.networkId,
+ address: tokenDefinition.address,
+ })
+ if (
+ baseTokensInfo[definitionTokenId] ||
+ unlistedBaseTokensInfo[definitionTokenId] ||
+ visitedDefinitions[definitionTokenId]?.type ===
+ 'app-token-definition' ||
+ unresolvedTokenDefinitionsByTokenId[definitionTokenId]
+ ) {
+ continue
+ }
+ unresolvedTokenDefinitionsByTokenId[definitionTokenId] = tokenDefinition
+ }
+ const unresolvedTokenDefinitions = Object.values(
+ unresolvedTokenDefinitionsByTokenId,
)
- console.log(
+ logger.debug(
+ { unresolvedTokenDefinitions, count: unresolvedTokenDefinitions.length },
'unresolvedTokenDefinitions',
- JSON.stringify(unresolvedTokenDefinitions, null, ' '),
)
// Get the token info for the unresolved token definitions
@@ -362,22 +488,37 @@ export async function getPositions(
await Promise.all(
unresolvedTokenDefinitions.map(async (tokenDefinition) => {
try {
- // Assume the token is an app token from the plugin
- // TODO: We'll probably need to allow plugins to specify the app id themselves
+ // Assume the token is an app token from the hook
+ // TODO: We'll probably need to allow hooks to specify the app id themselves
const { sourceAppId } = tokenDefinition
- const plugin = hooksByAppId[sourceAppId]
- const appTokenDefinition = await plugin
+ const hook = hooksByAppId[sourceAppId]
+ if (!hook.getAppTokenDefinition) {
+ throw new Error(
+ `Positions hook for app '${sourceAppId}' does not implement 'getAppTokenDefinition'. Please implement it to resolve the intermediary app token definition for ${tokenDefinition.address} (${tokenDefinition.networkId}).`,
+ )
+ }
+ const appTokenDefinition = await hook
.getAppTokenDefinition(tokenDefinition)
.then((definition) => addAppId(definition, sourceAppId))
return appTokenDefinition
} catch (e) {
- if (e instanceof ContractFunctionExecutionError) {
+ if (
+ e instanceof ContractFunctionExecutionError ||
+ e instanceof UnknownAppTokenError
+ ) {
// Assume the token is an ERC20 token
const erc20TokenInfo = await getERC20TokenInfo(
tokenDefinition.address as Address,
+ networkId,
)
- newUnlistedBaseTokensInfo[tokenDefinition.address] =
- erc20TokenInfo
+ newUnlistedBaseTokensInfo[erc20TokenInfo.tokenId] = {
+ ...erc20TokenInfo,
+ // TODO: remove the need for this fallback
+ // and implement the apps to resolve the tokens
+ ...(tokenDefinition.fallbackPriceUsd && {
+ priceUsd: tokenDefinition.fallbackPriceUsd,
+ }),
+ }
return
}
throw e
@@ -386,13 +527,13 @@ export async function getPositions(
)
).filter((p): p is Exclude => p != null)
- console.log(
+ logger.debug(
+ { appTokenDefinitions, count: appTokenDefinitions.length },
'appTokenDefinitions',
- JSON.stringify(appTokenDefinitions, null, ' '),
)
- console.log(
+ logger.debug(
+ { newUnlistedBaseTokensInfo, count: newUnlistedBaseTokensInfo.length },
'newUnlistedBaseTokensInfo',
- JSON.stringify(newUnlistedBaseTokensInfo, null, ' '),
)
unlistedBaseTokensInfo = {
@@ -404,32 +545,37 @@ export async function getPositions(
definitionsToResolve = appTokenDefinitions
}
- console.log({
+ logger.debug({
unlistedBaseTokensInfo,
visitedPositions: visitedDefinitions,
})
- const baseTokensByAddress: TokensInfo = {
+ const baseTokensByTokenId: TokensInfo = {
...baseTokensInfo,
...unlistedBaseTokensInfo,
}
const appTokensInfo = await Promise.all(
Object.values(visitedDefinitions)
.filter(
- (position) =>
- position?.type === 'app-token-definition' &&
- !baseTokensByAddress[position.address],
+ (position): position is AppPositionDefinition =>
+ position?.type === 'app-token-definition',
)
- .map((definition) => getERC20TokenInfo(definition!.address as Address)),
+ .map((definition) =>
+ getERC20TokenInfo(
+ definition.address as Address,
+ definition.networkId,
+ address ? (address as Address) : undefined,
+ ),
+ ),
)
- const appTokensByAddress: TokensInfo = {}
+ const appTokensByTokenId: TokensInfo = {}
for (const tokenInfo of appTokensInfo) {
- appTokensByAddress[tokenInfo.address] = tokenInfo
+ appTokensByTokenId[tokenInfo.tokenId] = tokenInfo
}
- const tokensByAddress = {
- ...baseTokensByAddress,
- ...appTokensByAddress,
+ const tokensByTokenId: TokensInfo = {
+ ...baseTokensByTokenId,
+ ...appTokensByTokenId,
}
// We now have all the base tokens info and position definitions
@@ -437,12 +583,12 @@ export async function getPositions(
// We can now resolve the positions
// Start with the base tokens
- const resolvedTokens: Record> = {}
- for (const token of Object.values(baseTokensByAddress)) {
+ const resolvedTokensByTokenId: Record> = {}
+ for (const token of Object.values(baseTokensByTokenId)) {
if (!token) {
continue
}
- resolvedTokens[token.address] = {
+ resolvedTokensByTokenId[token.tokenId] = {
...token,
type: 'base-token',
}
@@ -467,7 +613,7 @@ export async function getPositions(
const type = positionDefinition.type
- console.log('Resolving definition', type, positionDefinition.address)
+ logger.debug('Resolving definition', type, positionDefinition.address)
const appInfo = hooksByAppId[positionDefinition.appId].getInfo()
@@ -477,18 +623,18 @@ export async function getPositions(
position = await resolveAppTokenPosition(
address,
positionDefinition,
- tokensByAddress,
- resolvedTokens,
+ tokensByTokenId,
+ resolvedTokensByTokenId,
appInfo,
)
- resolvedTokens[positionDefinition.address] = position
+ resolvedTokensByTokenId[position.tokenId] = position
break
case 'contract-position-definition':
position = await resolveContractPosition(
address,
positionDefinition,
- tokensByAddress,
- resolvedTokens,
+ tokensByTokenId,
+ resolvedTokensByTokenId,
appInfo,
)
break
@@ -497,17 +643,32 @@ export async function getPositions(
return assertNever
}
- resolvedPositions[positionDefinition.address] = position
+ resolvedPositions[getPositionId(positionDefinition)] = position
}
- return definitions.map((definition) => {
- const resolvedPosition = resolvedPositions[definition.address]
- // Sanity check
- if (!resolvedPosition) {
- throw new Error(
- `Could not resolve ${definition.type}: ${definition.address}`,
- )
- }
- return resolvedPosition
- })
+ const returnedPositionIds = new Set()
+ return definitions
+ .map((definition) => {
+ const positionId = getPositionId(definition)
+ const resolvedPosition = resolvedPositions[positionId]
+ // Sanity check
+ if (!resolvedPosition) {
+ throw new Error(
+ `Could not resolve ${definition.type} with position id ${positionId}`,
+ )
+ }
+ if (returnedPositionIds.has(positionId)) {
+ logger.warn(
+ {
+ duplicateDefinition: definition,
+ initialDefinition: visitedDefinitions[positionId],
+ },
+ `Duplicate position definition detected in app ${definition.appId} for ${definition.address} (${definition.networkId}). ${resolvedPosition.appId} already defined it. Skipping it. If this is unexpected and the position is a contract-position-definition, please specify a unique extraId.`,
+ )
+ return undefined
+ }
+ returnedPositionIds.add(positionId)
+ return resolvedPosition
+ })
+ .filter((p) => p !== undefined)
}
diff --git a/src/runtime/getShortcuts.e2e.ts b/src/runtime/getShortcuts.e2e.ts
index f90e32ff..219908b7 100644
--- a/src/runtime/getShortcuts.e2e.ts
+++ b/src/runtime/getShortcuts.e2e.ts
@@ -1,14 +1,17 @@
+import { NetworkId } from '../types/networkId'
import { getShortcuts } from './getShortcuts'
describe('getShortcuts', () => {
it('should get shortcuts successfully', async () => {
- const shortcuts = await getShortcuts()
+ const shortcuts = await getShortcuts(NetworkId['celo-mainnet'])
// Simple check to make sure we got some definitions
expect(shortcuts.length).toBeGreaterThan(0)
})
it('should get shortcuts successfully for a specific app', async () => {
- const shortcuts = await getShortcuts(['ubeswap'])
+ const shortcuts = await getShortcuts(NetworkId['celo-mainnet'], undefined, [
+ 'ubeswap',
+ ])
// Simple check to make sure we got some definitions
expect(shortcuts.length).toBeGreaterThan(0)
for (const shortcut of shortcuts) {
@@ -17,7 +20,9 @@ describe('getShortcuts', () => {
})
it("should throw an error if the app doesn't exist", async () => {
- await expect(getShortcuts(['does-not-exist'])).rejects.toThrow(
+ await expect(
+ getShortcuts(NetworkId['celo-mainnet'], undefined, ['does-not-exist']),
+ ).rejects.toThrow(
/No app with id 'does-not-exist' found, available apps: \w+/,
)
})
diff --git a/src/runtime/getShortcuts.ts b/src/runtime/getShortcuts.ts
index 6c10cd66..5092f66c 100644
--- a/src/runtime/getShortcuts.ts
+++ b/src/runtime/getShortcuts.ts
@@ -1,10 +1,15 @@
import { getHooks } from './getHooks'
+import { NetworkId } from '../types/networkId'
-export async function getShortcuts(appIds: string[] = []) {
+export async function getShortcuts(
+ networkId: NetworkId,
+ address?: string,
+ appIds: string[] = [],
+) {
const hooks = await getHooks(appIds, 'shortcuts')
const shortcuts = await Promise.all(
Object.entries(hooks).map(async ([appId, hook]) => {
- const appShortcuts = await hook.getShortcutDefinitions()
+ const appShortcuts = await hook.getShortcutDefinitions(networkId, address)
return appShortcuts.map((shortcut) => ({
...shortcut,
appId,
diff --git a/src/runtime/getTokenId.test.ts b/src/runtime/getTokenId.test.ts
new file mode 100644
index 00000000..ea96500b
--- /dev/null
+++ b/src/runtime/getTokenId.test.ts
@@ -0,0 +1,40 @@
+import { getTokenId } from './getTokenId'
+import { NetworkId } from '../types/networkId'
+import { isNative } from './isNative'
+import mocked = jest.mocked
+
+jest.mock('./isNative')
+
+describe('getTokenId', () => {
+ it('uses `native` if native', () => {
+ expect(
+ getTokenId({
+ isNative: true,
+ address: '0x123',
+ networkId: NetworkId['celo-mainnet'],
+ }),
+ ).toBe('celo-mainnet:native')
+ })
+ it('lower cases the address in the ID', () => {
+ expect(
+ getTokenId({
+ isNative: false,
+ address: '0xABC',
+ networkId: NetworkId['ethereum-mainnet'],
+ }),
+ ).toBe('ethereum-mainnet:0xabc')
+ })
+ it('checks if native if it is not clear at the consumer level one way or the other', () => {
+ mocked(isNative).mockReturnValueOnce(true)
+ expect(
+ getTokenId({
+ address: 'mock-native-address',
+ networkId: NetworkId['celo-mainnet'],
+ }),
+ ).toBe('celo-mainnet:native')
+ expect(isNative).toHaveBeenCalledWith({
+ address: 'mock-native-address',
+ networkId: NetworkId['celo-mainnet'],
+ })
+ })
+})
diff --git a/src/runtime/getTokenId.ts b/src/runtime/getTokenId.ts
new file mode 100644
index 00000000..f5b43af7
--- /dev/null
+++ b/src/runtime/getTokenId.ts
@@ -0,0 +1,27 @@
+import { NetworkId } from '../types/networkId'
+import { isNative as tokenIsNative } from './isNative'
+
+/**
+ * Get a unique identifier for a crypto asset
+ *
+ * Standard across Valora repos
+ *
+ * @param networkId
+ * @param isNative: should be defined if the token is known to be native, like CELO or ETH on their respective chains,
+ * or not, like the address of a generic ERC-20 or other kind of smart contract
+ * @param address
+ */
+export function getTokenId({
+ networkId,
+ isNative,
+ address,
+}: {
+ networkId: NetworkId
+ isNative?: boolean
+ address?: string
+}) {
+ if (isNative === undefined) {
+ isNative = tokenIsNative({ networkId, address })
+ }
+ return `${networkId}:${isNative ? 'native' : address?.toLowerCase()}`
+}
diff --git a/src/runtime/isNative.test.ts b/src/runtime/isNative.test.ts
new file mode 100644
index 00000000..2ef5e410
--- /dev/null
+++ b/src/runtime/isNative.test.ts
@@ -0,0 +1,37 @@
+import { NetworkId } from '../types/networkId'
+import { isNative } from './isNative'
+
+describe('isNative', () => {
+ it('recognizes the curve identifier for ETH as native', () => {
+ expect(
+ isNative({
+ networkId: NetworkId['ethereum-mainnet'],
+ address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
+ }),
+ ).toBe(true)
+ })
+ it('recognizes celo mainnet CELO as native', () => {
+ expect(
+ isNative({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x471EcE3750Da237f93B8E339c536989b8978a438',
+ }),
+ ).toBe(true)
+ })
+ it('recognizes celo alfajores CELO as native', () => {
+ expect(
+ isNative({
+ networkId: NetworkId['celo-alfajores'],
+ address: '0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9',
+ }),
+ ).toBe(true)
+ })
+ it('recognizes other addresses as non-native', () => {
+ expect(
+ isNative({
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x123',
+ }),
+ ).toBe(false)
+ })
+})
diff --git a/src/runtime/isNative.ts b/src/runtime/isNative.ts
new file mode 100644
index 00000000..21930d8a
--- /dev/null
+++ b/src/runtime/isNative.ts
@@ -0,0 +1,34 @@
+import { NetworkId } from '../types/networkId'
+
+const ETHER_HEX_IDENTIFIER = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' // curve and some other dapps use this address as an identifier for the native asset
+
+export const networkIdToNativeAssetAddress: Record = {
+ [NetworkId['arbitrum-one']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['arbitrum-sepolia']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['op-mainnet']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['op-sepolia']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['ethereum-mainnet']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['ethereum-sepolia']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['celo-mainnet']]: '0x471ece3750da237f93b8e339c536989b8978a438',
+ [NetworkId['celo-alfajores']]: '0xf194afdf50b03e69bd7d057c1aa9e10c9954e4c9',
+ [NetworkId['polygon-pos-mainnet']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['polygon-pos-amoy']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['base-mainnet']]: ETHER_HEX_IDENTIFIER,
+ [NetworkId['base-sepolia']]: ETHER_HEX_IDENTIFIER,
+}
+
+export function isNative({
+ networkId,
+ address,
+}: {
+ networkId: NetworkId
+ address: string | undefined
+}): boolean {
+ if (!address) {
+ return true
+ }
+ return (
+ address.toLowerCase() ===
+ networkIdToNativeAssetAddress[networkId].toLowerCase()
+ )
+}
diff --git a/src/runtime/mockTokensInfo.json b/src/runtime/mockTokensInfo.json
new file mode 100644
index 00000000..3c64a53a
--- /dev/null
+++ b/src/runtime/mockTokensInfo.json
@@ -0,0 +1,165 @@
+{
+ "celo-mainnet:native": {
+ "address": "0x471ece3750da237f93b8e339c536989b8978a438",
+ "decimals": 18,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png",
+ "isFeeCurrency": true,
+ "canTransferWithComment": true,
+ "name": "Celo",
+ "symbol": "CELO",
+ "isSwappable": true,
+ "isNative": true,
+ "showZeroBalance": true,
+ "isCashInEligible": true,
+ "isCashOutEligible": true,
+ "infoUrl": "https://www.coingecko.com/en/coins/celo",
+ "networkId": "celo-mainnet",
+ "tokenId": "celo-mainnet:native",
+ "isCoreToken": true,
+ "priceUsd": "1.46418973149988",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "1.49688524807471",
+ "at": 1710290227589
+ }
+ }
+ },
+ "celo-mainnet:0x00400fcbf0816bebb94654259de7273f4a05c762": {
+ "address": "0x00400fcbf0816bebb94654259de7273f4a05c762",
+ "decimals": 18,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/POOF.png",
+ "name": "PoofCash",
+ "symbol": "POOF",
+ "infoUrl": "https://www.coingecko.com/en/coins/poofcash",
+ "networkId": "celo-mainnet",
+ "tokenId": "celo-mainnet:0x00400fcbf0816bebb94654259de7273f4a05c762",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png",
+ "priceUsd": "0.000432413252926883",
+ "priceFetchedAt": 1710375191184
+ },
+ "ethereum-mainnet:native": {
+ "name": "Ether",
+ "symbol": "ETH",
+ "decimals": 18,
+ "isNative": true,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png",
+ "showZeroBalance": true,
+ "infoUrl": "https://www.coingecko.com/en/coins/ethereum",
+ "minimumAppVersionToSwap": "1.72.0",
+ "isCashInEligible": true,
+ "networkId": "ethereum-mainnet",
+ "tokenId": "ethereum-mainnet:native",
+ "priceUsd": "3992.64",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "3976.27",
+ "at": 1710290227589
+ }
+ }
+ },
+ "ethereum-mainnet:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": {
+ "name": "Wrapped Ether",
+ "symbol": "WETH",
+ "decimals": 18,
+ "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/WETH.png",
+ "infoUrl": "https://www.coingecko.com/en/coins/ethereum",
+ "minimumAppVersionToSwap": "1.72.0",
+ "networkId": "ethereum-mainnet",
+ "tokenId": "ethereum-mainnet:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png",
+ "priceUsd": "4000.1615795126",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "3990.81686263612",
+ "at": 1710290227589
+ }
+ }
+ },
+ "arbitrum-one:native": {
+ "name": "Ether",
+ "symbol": "ETH",
+ "decimals": 18,
+ "isNative": true,
+ "isL2Native": true,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png",
+ "infoUrl": "https://www.coingecko.com/en/coins/ethereum",
+ "minimumAppVersionToSwap": "1.77.0",
+ "isCashInEligible": true,
+ "networkId": "arbitrum-one",
+ "tokenId": "arbitrum-one:native",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ARB.png",
+ "priceUsd": "3992.64",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "3976.27",
+ "at": 1710290227589
+ }
+ }
+ },
+ "arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831": {
+ "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
+ "decimals": 6,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/USDC.png",
+ "name": "USD Coin",
+ "symbol": "USDC",
+ "minimumAppVersionToSwap": "1.77.0",
+ "isCashInEligible": true,
+ "networkId": "arbitrum-one",
+ "tokenId": "arbitrum-one:0xaf88d065e77c8cc2239327c5edb3a432268e5831",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ARB.png",
+ "priceUsd": "1.00206954673564",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "1.00286398082106",
+ "at": 1710290227589
+ }
+ }
+ },
+ "op-mainnet:native": {
+ "name": "Ether",
+ "symbol": "ETH",
+ "decimals": 18,
+ "isNative": true,
+ "isL2Native": true,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png",
+ "infoUrl": "https://www.coingecko.com/en/coins/ethereum",
+ "minimumAppVersionToSwap": "1.77.0",
+ "isCashInEligible": true,
+ "networkId": "op-mainnet",
+ "tokenId": "op-mainnet:native",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/OP.png",
+ "priceUsd": "3992.64",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "3976.27",
+ "at": 1710290227589
+ }
+ }
+ },
+ "op-mainnet:0x4200000000000000000000000000000000000042": {
+ "name": "Optimism",
+ "symbol": "OP",
+ "address": "0x4200000000000000000000000000000000000042",
+ "decimals": 18,
+ "imageUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/OP.png",
+ "minimumAppVersionToSwap": "1.77.0",
+ "networkId": "op-mainnet",
+ "tokenId": "op-mainnet:0x4200000000000000000000000000000000000042",
+ "networkIconUrl": "https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/OP.png",
+ "priceUsd": "4.38916401440895",
+ "priceFetchedAt": 1710377278942,
+ "historicalPricesUsd": {
+ "lastDay": {
+ "price": "4.39150296828038",
+ "at": 1710290227589
+ }
+ }
+ }
+}
diff --git a/src/runtime/simulateTransactions.test.ts b/src/runtime/simulateTransactions.test.ts
new file mode 100644
index 00000000..a9fcc403
--- /dev/null
+++ b/src/runtime/simulateTransactions.test.ts
@@ -0,0 +1,76 @@
+import { NetworkId } from '../types/networkId'
+import { simulateTransactions } from './simulateTransactions'
+import { Transaction } from '../types/shortcuts'
+import got from '../utils/got'
+
+jest.mock('../utils/got')
+
+describe('simulateTransactions', () => {
+ // Doesn't matter what the transactions are
+ const mockTransactions = [{}, {}] as Transaction[]
+
+ beforeAll(() => {
+ process.env.SIMULATE_TRANSACTIONS_URL = 'http://foo.com/simulate'
+ })
+
+ afterAll(() => {
+ delete process.env.SIMULATE_TRANSACTIONS_URL
+ })
+
+ it('returns successfully', async () => {
+ const mockedGot = jest.mocked(got)
+ mockedGot.post = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ status: 'OK',
+ simulatedTransactions: mockTransactions.map((_) => ({
+ status: 'success',
+ })),
+ }),
+ })
+
+ await expect(
+ simulateTransactions({
+ transactions: mockTransactions,
+ networkId: NetworkId['ethereum-mainnet'],
+ }),
+ ).resolves.not.toThrow()
+ })
+
+ it("throws if status isn't OK", async () => {
+ const mockedGot = jest.mocked(got)
+ mockedGot.post = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ status: 'not ok',
+ }),
+ })
+
+ await expect(
+ simulateTransactions({
+ transactions: mockTransactions,
+ networkId: NetworkId['ethereum-mainnet'],
+ }),
+ ).rejects.toThrow()
+ })
+
+ it('throws if transaction simulation fails', async () => {
+ const mockedGot = jest.mocked(got)
+ mockedGot.post = jest.fn().mockReturnValue({
+ json: () =>
+ Promise.resolve({
+ status: 'OK',
+ simulatedTransactions: mockTransactions.map((_) => ({
+ status: 'failures',
+ })),
+ }),
+ })
+
+ await expect(
+ simulateTransactions({
+ transactions: mockTransactions,
+ networkId: NetworkId['ethereum-mainnet'],
+ }),
+ ).rejects.toThrow()
+ })
+})
diff --git a/src/runtime/simulateTransactions.ts b/src/runtime/simulateTransactions.ts
new file mode 100644
index 00000000..4ef199ac
--- /dev/null
+++ b/src/runtime/simulateTransactions.ts
@@ -0,0 +1,87 @@
+import { RequestError } from 'got'
+import got from '../utils/got'
+import { NetworkId } from '../types/networkId'
+import { Transaction } from '../types/shortcuts'
+import { getConfig } from '../config'
+
+type SimulatedTransactionResponse = {
+ status: 'OK'
+ simulatedTransactions: {
+ status: 'success' | 'failure'
+ blockNumber: string
+ gasNeeded: number
+ gasUsed: number
+ gasPrice: string
+ }[]
+}
+
+export class UnsupportedSimulateRequest extends Error {
+ constructor(json: any) {
+ super(JSON.stringify(json))
+ }
+}
+
+export async function simulateTransactions({
+ transactions,
+ networkId,
+}: {
+ transactions: Transaction[]
+ networkId: NetworkId
+}) {
+ const url = getConfig().SIMULATE_TRANSACTIONS_URL
+ if (!url) {
+ throw new Error('No SIMULATE_TRANSACTIONS_URL value set')
+ }
+
+ let response
+
+ try {
+ response = await got
+ .post(url, {
+ json: {
+ transactions,
+ networkId,
+ },
+ })
+ .json()
+ } catch (error) {
+ if (error instanceof RequestError) {
+ const requestError = error as RequestError
+ // Assume all 400s are basically "valid, but unsupported request" (e.g.,
+ // networkId isn't supported) vs "invalid request because the simulate
+ // transaction integration is broken".
+ if (requestError?.response?.statusCode === 400) {
+ throw new UnsupportedSimulateRequest(requestError.options.json)
+ }
+ }
+ throw error
+ }
+
+ if (response.status !== 'OK') {
+ throw new Error(
+ `Unexpected simulateTransactions status: ${JSON.stringify(response)}`,
+ )
+ }
+
+ const { simulatedTransactions } = response
+
+ if (simulatedTransactions.length !== transactions.length) {
+ throw new Error(
+ `Expected ${transactions.length} simulated transactions, got ${
+ simulatedTransactions.length
+ }, response: ${JSON.stringify(simulatedTransactions)}`,
+ )
+ }
+
+ simulatedTransactions.forEach((tx, i) => {
+ if (tx.status !== 'success') {
+ throw new Error(
+ `Failed to simulate transaction for base transaction ${JSON.stringify(
+ transactions[i],
+ )}. response: ${JSON.stringify(tx)}`,
+ )
+ }
+ })
+
+ return simulatedTransactions
+}
diff --git a/src/types/address.ts b/src/types/address.ts
new file mode 100644
index 00000000..3eb67e24
--- /dev/null
+++ b/src/types/address.ts
@@ -0,0 +1,9 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { Address as ZodAddress } from 'abitype/zod'
+import { Address } from 'viem'
+
+export type { Address } from 'viem'
+
+export const ZodAddressLowerCased = ZodAddress.transform((val) => {
+ return val.toLowerCase() as Address
+})
diff --git a/src/types/networkId.ts b/src/types/networkId.ts
new file mode 100644
index 00000000..0ac21144
--- /dev/null
+++ b/src/types/networkId.ts
@@ -0,0 +1,24 @@
+export enum LegacyNetwork {
+ celo = 'celo',
+ celoAlfajores = 'celoAlfajores',
+}
+
+export enum NetworkId {
+ 'celo-mainnet' = 'celo-mainnet',
+ 'celo-alfajores' = 'celo-alfajores',
+ 'ethereum-mainnet' = 'ethereum-mainnet',
+ 'ethereum-sepolia' = 'ethereum-sepolia',
+ 'arbitrum-one' = 'arbitrum-one',
+ 'arbitrum-sepolia' = 'arbitrum-sepolia',
+ 'op-mainnet' = 'op-mainnet',
+ 'op-sepolia' = 'op-sepolia',
+ 'polygon-pos-mainnet' = 'polygon-pos-mainnet',
+ 'polygon-pos-amoy' = 'polygon-pos-amoy',
+ 'base-mainnet' = 'base-mainnet',
+ 'base-sepolia' = 'base-sepolia',
+}
+
+export const legacyNetworkToNetworkId: Record = {
+ [LegacyNetwork.celo]: NetworkId['celo-mainnet'],
+ [LegacyNetwork.celoAlfajores]: NetworkId['celo-alfajores'],
+}
diff --git a/src/types/positions.ts b/src/types/positions.ts
index 83bedb98..401ff892 100644
--- a/src/types/positions.ts
+++ b/src/types/positions.ts
@@ -1,49 +1,147 @@
import { DecimalNumber, SerializedDecimalNumber } from './numbers'
+import { NetworkId } from './networkId'
+import { TFunction } from 'i18next'
-// Plugin interface that authors will implement
+// Interface that authors will implement
export interface PositionsHook {
getInfo(): AppInfo
- // Get position definitions for a given address
- getPositionDefinitions(
- network: string,
- address: string,
- ): Promise
+
+ // Get position definitions
+ // Note: it can be called with or without an address
+ // If called without an address, it should return all positions available for the network
+ getPositionDefinitions({
+ networkId,
+ address,
+ t,
+ }: {
+ networkId: NetworkId
+ address?: string
+ t: TFunction<'translation', undefined>
+ }): Promise
+
// Get an app token definition from a token definition
- getAppTokenDefinition(
+ // This is needed when a position definition has one ore more intermediary app tokens, which are not base tokens.
+ // For instance a farm position composed of a LP token.
+ // The runtime needs to call this function to resolve such intermediary tokens.
+ getAppTokenDefinition?(
tokenDefinition: TokenDefinition,
): Promise
}
export interface TokenDefinition {
address: string
- network: string
+ networkId: NetworkId
+ // Escape hatch for priceUsd in case the token is not in our list of base tokens
+ // and it's difficult to decompose the token into base token
+ // Ideally we should add apps to resolve such tokens
+ // For example: Beefy vault depends on Aave, Curve, etc.
+ // but we don't yet have all these apps implemented
+ // Note: there's also a limitation in the runtime as it can't yet always resolve tokens between apps
+ // This will be fixed "soon"
+ fallbackPriceUsd?: SerializedDecimalNumber
+}
+
+// To be returned when `getAppTokenDefinition` can't resolve a token
+export class UnknownAppTokenError extends Error {
+ constructor({ networkId, address }: TokenDefinition) {
+ super(`Unknown app token: ${networkId}:${address}`)
+ }
}
export type TokenCategory = 'claimable' // We could add more categories later
export interface DisplayPropsContext {
- resolvedTokens: Record>
+ resolvedTokensByTokenId: Record>
}
export interface DisplayProps {
title: string // Example: CELO / cUSD
description: string // Example: Pool
imageUrl: string // Example: https://...
+ manageUrl: string | undefined // Example: https://
+}
+
+export interface DataPropsContext {
+ resolvedTokensByTokenId: Record>
+}
+
+// For now list all the data props we need
+// But in the future we could parameterize this
+export type DataProps = EarnDataProps
+
+export interface YieldRate {
+ percentage: number
+ label: string
+ tokenId: string
+}
+
+export interface EarningItem {
+ amount: DecimalNumber
+ label: string
+ tokenId: string
+ includedInPoolBalance?: boolean
+}
+
+export enum ClaimType {
+ Earnings = 'earnings',
+ Rewards = 'rewards',
+}
+
+export interface SafetyRisk {
+ isPositive: boolean
+ title: string
+ category: string
+}
+
+export interface Safety {
+ level: 'low' | 'medium' | 'high'
+ risks: SafetyRisk[]
+}
+
+export interface EarnDataProps {
+ contractCreatedAt?: string // ISO string
+ manageUrl?: string
+ termsUrl?: string
+ cantSeparateCompoundedInterest?: boolean
+ tvl?: SerializedDecimalNumber // In USD
+ yieldRates: YieldRate[] // List of components of yield for a pool that, summed up, give the total yield rate
+ earningItems: EarningItem[]
+ depositTokenId: string
+ withdrawTokenId: string
+ rewardsPositionIds?: string[]
+ claimType?: ClaimType
+ withdrawalIncludesClaim?: boolean
+ dailyYieldRatePercentage?: number // The daily yield rate percentage
+ safety?: Safety
+ // We'll add more fields here as needed
+}
+
+interface ShortcutTriggerArgsContext {
+ tokensByTokenId: TokensInfo
+}
+
+export type ShortcutTriggerArgs = {
+ // A map of shortcutId to trigger args
+ [shortcutId in string]?: Record
}
export interface AbstractPositionDefinition {
- network: string
+ networkId: NetworkId
address: string
displayProps: ((context: DisplayPropsContext) => DisplayProps) | DisplayProps
+ dataProps?: ((context: DataPropsContext) => DataProps) | DataProps
tokens: (TokenDefinition & {
category?: TokenCategory
})[]
availableShortcutIds?: string[] // Allows to apply shortcuts to positions
+ shortcutTriggerArgs?:
+ | ((context: ShortcutTriggerArgsContext) => ShortcutTriggerArgs)
+ | ShortcutTriggerArgs
}
export interface PricePerShareContext {
- tokensByAddress: Record>
+ tokensByTokenId: Record>
}
export interface AppTokenPositionDefinition extends AbstractPositionDefinition {
@@ -54,11 +152,14 @@ export interface AppTokenPositionDefinition extends AbstractPositionDefinition {
}
export interface BalancesContext {
- resolvedTokens: Record>
+ resolvedTokensByTokenId: Record>
}
export interface ContractPositionDefinition extends AbstractPositionDefinition {
type: 'contract-position-definition'
+ // Needed in some cases to differentiate between different positions of the same contract
+ // for instance Uniswap V3 positions on a given liquidity pool but at different ranges
+ extraId?: string
balances:
| ((context: BalancesContext) => Promise)
| DecimalNumber[]
@@ -71,14 +172,15 @@ export type PositionDefinition =
// Generic info about the app
// Note: this could be used for dapp listing too
export interface AppInfo {
- id: string // Example: ubeswap
name: string // Example: Ubeswap
- description: string // Example: Decentralized exchange on Celo
}
export interface AbstractPosition {
+ // Should be unique across all positions
+ // And treated as an opaque identifier by consumers
+ positionId: string // Example: celo-mainnet:0x...
address: string // Example: 0x...
- network: string // Example: celo
+ networkId: NetworkId // Example: celo-mainnet
appId: string // Example: ubeswap
appName: string // Example: Ubeswap
/**
@@ -86,13 +188,16 @@ export interface AbstractPosition {
*/
label: string // Example: Pool
displayProps: DisplayProps
+ dataProps?: DataProps
tokens: (Token & { category?: TokenCategory })[]
availableShortcutIds: string[] // Allows to apply shortcuts to positions
+ shortcutTriggerArgs: ShortcutTriggerArgs
}
export interface AbstractToken {
- address: string // Example: 0x...
- network: string // Example: celo
+ tokenId: string // Example: celo-mainnet:0x123...
+ address?: string // Example: 0x...
+ networkId: NetworkId // Example: celo-mainnet
// These would be resolved dynamically
symbol: string // Example: cUSD
@@ -105,13 +210,34 @@ export interface BaseToken extends AbstractToken {
type: 'base-token'
}
-export interface AppTokenPosition extends AbstractPosition, AbstractToken {
- type: 'app-token'
- supply: SerializedDecimalNumber // Example: "1000"
- // Price ratio between the token and underlying token(s)
- pricePerShare: SerializedDecimalNumber[]
+export interface RawTokenInfo {
+ address?: string
+ name: string
+ symbol: string
+ decimals: number
+ imageUrl: string
+ tokenId: string
+ networkId: NetworkId
+ isNative?: boolean
+ priceUsd?: string
}
+export interface TokenInfo extends Omit {
+ imageUrl: string
+ balance: DecimalNumber
+ totalSupply: DecimalNumber
+}
+
+export type TokensInfo = Record
+
+export type AppTokenPosition = AbstractPosition &
+ AbstractToken & {
+ type: 'app-token'
+ supply: SerializedDecimalNumber // Example: "1000"
+ // Price ratio between the token and underlying token(s)
+ pricePerShare: SerializedDecimalNumber[]
+ }
+
export interface ContractPosition extends AbstractPosition {
type: 'contract-position'
// This would be derived from the underlying tokens
diff --git a/src/types/shortcuts.ts b/src/types/shortcuts.ts
index 4e033c16..b5b32c75 100644
--- a/src/types/shortcuts.ts
+++ b/src/types/shortcuts.ts
@@ -1,23 +1,96 @@
+import { z, ZodObject, ZodRawShape } from 'zod'
+import { NetworkId } from './networkId'
+import { ZodAddressLowerCased } from './address'
+import { SwapTransaction } from './swaps'
+
+export type ShortcutCategory = 'claim' | 'deposit' | 'withdraw' | 'swap-deposit'
+
export interface ShortcutsHook {
- getShortcutDefinitions(): ShortcutDefinition[]
+ getShortcutDefinitions(
+ networkId: NetworkId,
+ address?: string,
+ ): Promise[]>
}
-export interface ShortcutDefinition {
+export const tokenAmounts = z
+ .array(
+ z.object({
+ tokenId: z.string(),
+ amount: z.string(),
+ useMax: z.boolean().optional(),
+ }),
+ )
+ .nonempty()
+
+export const tokenAmountWithMetadata = z.object({
+ tokenId: z.string(),
+ amount: z.string(),
+ // these can be inferred from the tokenId, but we need to pass them for now
+ decimals: z.number(),
+ address: ZodAddressLowerCased.optional(),
+ isNative: z.boolean(),
+ // this can be different for cross chain swaps, keeping it optional to be backwards compatible
+ networkId: z.nativeEnum(NetworkId).optional(),
+})
+
+export const ZodEnableAppFee = z.boolean().optional()
+
+// enforces the tokens field to be an array of objects with tokenId and amount
+// for all deposit and withdraw shortcuts
+type TriggerInputShape = Category extends 'deposit' | 'withdraw'
+ ? ZodRawShape & { tokens: typeof tokenAmounts }
+ : Category extends 'swap-deposit'
+ ? ZodRawShape & {
+ swapFromToken: typeof tokenAmountWithMetadata
+ enableAppFee: typeof ZodEnableAppFee
+ }
+ : ZodRawShape
+
+type TriggerOutputTransactions = {
+ transactions: Transaction[] // 0, 1 or more transactions to sign by the user
+}
+
+export type TriggerOutputShape =
+ Category extends 'swap-deposit'
+ ? TriggerOutputTransactions & {
+ dataProps: { swapTransaction: SwapTransaction }
+ }
+ : TriggerOutputTransactions
+
+export interface ShortcutDefinition<
+ Category extends ShortcutCategory,
+ InputShape extends TriggerInputShape,
+> {
id: string // Example: claim-reward
name: string // Example: Claim
description: string // Example: Claim your reward
- networks: string[] // Example: ['celo']
- category?: 'claim' // We'll add more categories later
+ networkIds: NetworkId[] // Example: ['celo-mainnet']
+ category: Category
+ triggerInputShape: InputShape
onTrigger: (
- network: string,
- address: string,
- positionAddress: string,
- ) => Promise // 0, 1 or more transactions to sign by the user
+ args: {
+ networkId: NetworkId
+ address: string
+ } & z.infer>,
+ ) => Promise>
}
export type Transaction = {
- network: string
+ networkId: NetworkId
from: string
to: string
data: string
+ value?: BigInt
+ // These are needed when returning more than one transaction
+ gas?: BigInt // in wei
+ estimatedGasUse?: BigInt // in wei
+}
+
+// This is to help TS infer the type of the triggerInputShape
+// so the onTrigger args can be properly typed
+export function createShortcut<
+ Category extends ShortcutCategory,
+ InputShape extends TriggerInputShape,
+>(definition: ShortcutDefinition) {
+ return definition
}
diff --git a/src/types/swaps.ts b/src/types/swaps.ts
new file mode 100644
index 00000000..0d98d84f
--- /dev/null
+++ b/src/types/swaps.ts
@@ -0,0 +1,40 @@
+import { Address } from './address'
+
+// Types based on the response from `getSwapQuote` endpoint
+export type SwapTransaction =
+ | SameChainSwapTransaction
+ | CrossChainSwapTransaction
+
+interface SameChainSwapTransaction extends BaseSwapTransaction {
+ swapType: 'same-chain'
+}
+
+interface CrossChainSwapTransaction extends BaseSwapTransaction {
+ swapType: 'cross-chain'
+ // Swap duration estimation in seconds
+ estimatedDuration: number
+ maxCrossChainFee: string
+ estimatedCrossChainFee: string
+}
+
+interface BaseSwapTransaction {
+ swapType: 'same-chain' | 'cross-chain'
+ chainId: number
+ buyAmount: string
+ sellAmount: string
+ buyTokenAddress: Address
+ sellTokenAddress: Address
+ price: string
+ guaranteedPrice: string
+ appFeePercentageIncludedInPrice?: string
+ estimatedPriceImpact: string | null
+ gas: string
+ gasPrice: string
+ to: Address
+ value: string // Needed for native asset swaps
+ data: string
+ from: Address
+ allowanceTarget: Address
+ estimatedGasUse: string
+ simulationStatus?: 'success' | 'failure'
+}
diff --git a/src/utils/batcher.ts b/src/utils/batcher.ts
new file mode 100644
index 00000000..dfaa6aff
--- /dev/null
+++ b/src/utils/batcher.ts
@@ -0,0 +1,9 @@
+const BATCH_SIZE = 100
+
+export function createBatches(items: Type[]): Type[][] {
+ const batches: Type[][] = []
+ for (let i = 0; i < items.length; i += BATCH_SIZE) {
+ batches.push(items.slice(i, i + BATCH_SIZE))
+ }
+ return batches
+}
diff --git a/src/utils/got.ts b/src/utils/got.ts
new file mode 100644
index 00000000..6b08dc20
--- /dev/null
+++ b/src/utils/got.ts
@@ -0,0 +1,57 @@
+import got, { ExtendOptions, TimeoutError } from 'got'
+import { logger } from '../log'
+
+const gotLogger = logger.child({ module: 'got', level: 'debug' })
+
+// https://github.com/sindresorhus/got/blob/HEAD/documentation/quick-start.md#options
+const options: ExtendOptions = {
+ timeout: {
+ request: 15 * 1000,
+ },
+ hooks: {
+ beforeError: [
+ (err) => {
+ if (err instanceof TimeoutError) {
+ gotLogger.warn(
+ {
+ err,
+ request: {
+ url: err.request.requestUrl,
+ options: err.request.options,
+ timings: err.timings,
+ },
+ },
+ `Request timed out on ${err.request.options.method} ${err.request.requestUrl}`,
+ )
+ }
+ return err
+ },
+ ],
+ afterResponse: [
+ (response) => {
+ if (
+ response.timings.phases.total &&
+ response.timings.phases.total > 5 * 1000
+ ) {
+ gotLogger.debug(
+ {
+ response: {
+ statusCode: response.statusCode,
+ statusMessage: response.statusMessage,
+ url: response.requestUrl,
+ timings: response.timings,
+ method: response.request.options.method,
+ },
+ },
+ `Request to ${response.request.options.method} ${response.requestUrl} took longer than 5s`,
+ )
+ }
+ return response
+ },
+ ],
+ },
+}
+
+const client = got.extend(options)
+
+export default client
diff --git a/src/utils/i18next.ts b/src/utils/i18next.ts
new file mode 100644
index 00000000..24727ce5
--- /dev/null
+++ b/src/utils/i18next.ts
@@ -0,0 +1,29 @@
+import i18next from 'i18next'
+import Backend from 'i18next-fs-backend'
+import i18nextMiddleware from 'i18next-http-middleware'
+import path from 'path'
+
+const DEFAULT_LANGUAGE = 'base'
+
+export function createI18Next() {
+ const i18nextInstance = i18next.createInstance()
+ i18nextInstance
+ .use(Backend)
+ .use(i18nextMiddleware.LanguageDetector)
+ .init({
+ // Sync init, so t can be used immediately
+ initAsync: false,
+ backend: {
+ loadPath: path.join(__dirname, '../../locales/{{lng}}.json'),
+ },
+ fallbackLng: DEFAULT_LANGUAGE,
+ preload: [DEFAULT_LANGUAGE],
+ // Uncomment to troubleshoot i18next issues
+ // debug: true,
+ })
+ .catch((error) => {
+ throw new Error(`Failed to initialize i18next: ${error}`)
+ })
+
+ return i18nextInstance
+}
diff --git a/src/utils/prepareSwapTransactions.test.ts b/src/utils/prepareSwapTransactions.test.ts
new file mode 100644
index 00000000..357974b4
--- /dev/null
+++ b/src/utils/prepareSwapTransactions.test.ts
@@ -0,0 +1,333 @@
+import { ChainType, SquidCallType } from '@0xsquid/squid-types'
+import { NetworkId } from '../types/networkId'
+import { prepareSwapTransactions } from './prepareSwapTransactions'
+import got from './got'
+import { Address } from 'viem'
+
+const mockGotPostJson = jest.fn()
+const mockReadContract = jest.fn()
+
+jest.mock('./got', () => ({
+ HTTPError: jest.requireActual('./got').HTTPError,
+ post: jest.fn(() => ({
+ json: mockGotPostJson,
+ })),
+}))
+jest.mock('../runtime/client', () => ({
+ getClient: jest.fn(() => ({
+ readContract: mockReadContract,
+ })),
+}))
+
+const mockWalletAddress = '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d'
+
+const mockNativeSwapFromToken = {
+ tokenId: 'op-mainnet:native',
+ isNative: true,
+ amount: '1',
+ decimals: 18,
+ networkId: NetworkId['op-mainnet'],
+}
+
+const mockCeloSwapFromToken = {
+ tokenId: 'celo-mainnet:native',
+ isNative: true,
+ amount: '1',
+ decimals: 18,
+ networkId: NetworkId['celo-mainnet'],
+ address: '0x471EcE3750Da237f93B8E339c536989b8978a438' as Address,
+}
+
+const mockErc20SwapFromToken = {
+ tokenId: 'arbitrum-one:0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ isNative: false,
+ amount: '1',
+ decimals: 6,
+ address: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0' as Address,
+}
+
+const mockErc20CrossChainSwapFromToken = {
+ tokenId: 'op-mainnet:0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ isNative: false,
+ amount: '1',
+ decimals: 6,
+ address: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0' as Address,
+ networkId: NetworkId['op-mainnet'],
+}
+
+const mockPostHook = {
+ chainType: ChainType.EVM as const,
+ calls: [
+ {
+ chainType: ChainType.EVM as const,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ callData: '0xapprove',
+ value: '0',
+ estimatedGas: '1000',
+ },
+ {
+ chainType: ChainType.EVM as const,
+ callType: SquidCallType.FULL_TOKEN_BALANCE,
+ target: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ callData: '0xsupply',
+ value: '0',
+ estimatedGas: '2000',
+ },
+ ],
+ description: 'Deposit to pool',
+}
+
+const swapTransaction = {
+ allowanceTarget: '0x4c363649d45d93a39aa2e72cb1beae5e25c63e88',
+ gas: '12345',
+ estimatedGasUse: '12211',
+ to: '0x12345678',
+ from: mockWalletAddress,
+ value: '111',
+ data: '0xswapdata',
+ simulationStatus: 'success',
+}
+
+describe('prepareSwapTransactions', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ mockGotPostJson.mockResolvedValue({
+ unvalidatedSwapTransaction: swapTransaction,
+ })
+ mockReadContract.mockResolvedValue(0)
+ })
+
+ it('prepares swap transaction from native token', async () => {
+ const { transactions, dataProps } = await prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockNativeSwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ })
+
+ expect(transactions).toHaveLength(1)
+ expect(transactions[0]).toEqual({
+ networkId: NetworkId['op-mainnet'],
+ from: mockWalletAddress,
+ to: '0x12345678',
+ data: '0xswapdata',
+ value: 111n,
+ gas: 14196n,
+ estimatedGasUse: 12211n,
+ })
+ expect(dataProps).toEqual({ swapTransaction })
+ expect(got.post).toHaveBeenCalledTimes(1)
+ expect(got.post).toHaveBeenCalledWith(
+ 'https://api.mainnet.valora.xyz/getSwapQuote',
+ {
+ json: {
+ buyToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ buyIsNative: false,
+ buyNetworkId: NetworkId['arbitrum-one'],
+ sellIsNative: true,
+ sellNetworkId: NetworkId['op-mainnet'],
+ sellAmount: (1e18).toString(),
+ slippagePercentage: '1',
+ postHook: mockPostHook,
+ userAddress: mockWalletAddress,
+ },
+ },
+ )
+ })
+
+ it('prepares swap transaction from celo native token', async () => {
+ const { transactions, dataProps } = await prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockCeloSwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ })
+
+ expect(transactions).toHaveLength(2)
+ expect(dataProps).toEqual({ swapTransaction })
+ expect(transactions[0]).toEqual({
+ networkId: NetworkId['celo-mainnet'],
+ from: mockWalletAddress,
+ to: '0x471EcE3750Da237f93B8E339c536989b8978a438',
+ data: expect.any(String),
+ })
+ expect(transactions[1]).toEqual({
+ networkId: NetworkId['celo-mainnet'],
+ from: mockWalletAddress,
+ to: '0x12345678',
+ data: '0xswapdata',
+ value: 111n,
+ gas: 14196n,
+ estimatedGasUse: 12211n,
+ })
+ expect(got.post).toHaveBeenCalledWith(
+ 'https://api.mainnet.valora.xyz/getSwapQuote',
+ {
+ json: {
+ buyToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ buyIsNative: false,
+ buyNetworkId: NetworkId['arbitrum-one'],
+ sellToken: '0x471EcE3750Da237f93B8E339c536989b8978a438',
+ sellIsNative: true,
+ sellNetworkId: NetworkId['celo-mainnet'],
+ sellAmount: (1e18).toString(),
+ slippagePercentage: '1',
+ postHook: mockPostHook,
+ userAddress: mockWalletAddress,
+ },
+ },
+ )
+ })
+
+ it('prepares swap transaction from erc20 token with network id not set and swap has non simulated gas', async () => {
+ mockGotPostJson.mockResolvedValueOnce({
+ unvalidatedSwapTransaction: {
+ ...swapTransaction,
+ simulationStatus: 'failure',
+ },
+ })
+ const { transactions, dataProps } = await prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockErc20SwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ })
+
+ expect(transactions).toHaveLength(2)
+ expect(transactions[0]).toEqual({
+ networkId: NetworkId['arbitrum-one'],
+ from: mockWalletAddress,
+ to: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ data: expect.any(String),
+ })
+ expect(transactions[1]).toEqual({
+ networkId: NetworkId['arbitrum-one'],
+ from: mockWalletAddress,
+ to: '0x12345678',
+ data: '0xswapdata',
+ value: 111n,
+ gas: 12345n,
+ estimatedGasUse: 12211n,
+ })
+ expect(dataProps).toEqual({
+ swapTransaction: { ...swapTransaction, simulationStatus: 'failure' },
+ })
+ expect(got.post).toHaveBeenCalledTimes(1)
+ expect(got.post).toHaveBeenCalledWith(
+ 'https://api.mainnet.valora.xyz/getSwapQuote',
+ {
+ json: {
+ buyToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ buyIsNative: false,
+ buyNetworkId: NetworkId['arbitrum-one'],
+ sellToken: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ sellIsNative: false,
+ sellNetworkId: NetworkId['arbitrum-one'],
+ sellAmount: (1e6).toString(),
+ slippagePercentage: '1',
+ postHook: mockPostHook,
+ userAddress: mockWalletAddress,
+ },
+ },
+ )
+ })
+
+ it('prepares swap transaction from erc20 token with network id set', async () => {
+ const { transactions, dataProps } = await prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockErc20CrossChainSwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ })
+
+ expect(transactions).toHaveLength(2)
+ expect(transactions[0]).toEqual({
+ networkId: NetworkId['op-mainnet'],
+ from: mockWalletAddress,
+ to: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ data: expect.any(String),
+ })
+ expect(transactions[1]).toEqual({
+ networkId: NetworkId['op-mainnet'],
+ from: mockWalletAddress,
+ to: '0x12345678',
+ data: '0xswapdata',
+ value: 111n,
+ gas: 14196n,
+ estimatedGasUse: 12211n,
+ })
+ expect(dataProps).toEqual({ swapTransaction })
+ expect(got.post).toHaveBeenCalledTimes(1)
+ expect(got.post).toHaveBeenCalledWith(
+ 'https://api.mainnet.valora.xyz/getSwapQuote',
+ {
+ json: {
+ buyToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ buyIsNative: false,
+ buyNetworkId: NetworkId['arbitrum-one'],
+ sellToken: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0',
+ sellIsNative: false,
+ sellNetworkId: NetworkId['op-mainnet'],
+ sellAmount: (1e6).toString(),
+ slippagePercentage: '1',
+ postHook: mockPostHook,
+ userAddress: mockWalletAddress,
+ },
+ },
+ )
+ })
+
+ it('skips approve if swap amount is already approved', async () => {
+ mockReadContract.mockResolvedValue(1e6)
+
+ const { transactions } = await prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockErc20SwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ })
+
+ expect(transactions).toHaveLength(1)
+ expect(transactions[0]).toEqual({
+ networkId: NetworkId['arbitrum-one'],
+ from: mockWalletAddress,
+ to: '0x12345678',
+ data: '0xswapdata',
+ value: 111n,
+ gas: 14196n,
+ estimatedGasUse: 12211n,
+ })
+ })
+
+ it('throws if getting swap quote fails', async () => {
+ mockGotPostJson.mockRejectedValueOnce(new Error('swap quote failed'))
+ await expect(
+ prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockNativeSwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ }),
+ ).rejects.toThrow('swap quote failed')
+ })
+
+ it('throws if no swap quote is found in the response', async () => {
+ mockGotPostJson.mockResolvedValueOnce({})
+ await expect(
+ prepareSwapTransactions({
+ networkId: NetworkId['arbitrum-one'],
+ walletAddress: '0x2b8441ef13333ffa955c9ea5ab5b3692da95260d',
+ swapFromToken: mockNativeSwapFromToken,
+ swapToTokenAddress: '0x724dc807b04555b71ed48a6896b6f41593b8c637',
+ postHook: mockPostHook,
+ }),
+ ).rejects.toThrow('Unable to get swap quote')
+ })
+})
diff --git a/src/utils/prepareSwapTransactions.ts b/src/utils/prepareSwapTransactions.ts
new file mode 100644
index 00000000..1ad77506
--- /dev/null
+++ b/src/utils/prepareSwapTransactions.ts
@@ -0,0 +1,162 @@
+import { z } from 'zod'
+import {
+ tokenAmountWithMetadata,
+ Transaction,
+ TriggerOutputShape,
+} from '../types/shortcuts'
+import { EvmContractCall, Hook as SquidHook } from '@0xsquid/squid-types'
+import { NetworkId } from '../types/networkId'
+import {
+ Address,
+ encodeFunctionData,
+ erc20Abi,
+ parseUnits,
+ zeroAddress,
+} from 'viem'
+import { logger } from '../log'
+import { getConfig } from '../config'
+import got from './got'
+import { HTTPError } from 'got'
+import { getClient } from '../runtime/client'
+import { SwapTransaction } from '../types/swaps'
+
+type GetSwapQuoteResponse = {
+ unvalidatedSwapTransaction?: SwapTransaction
+ details: {
+ swapProvider?: string
+ }
+ errors: {
+ provider: string
+ error: {
+ message: string
+ details: unknown
+ }
+ }[]
+}
+
+export async function prepareSwapTransactions({
+ swapFromToken,
+ postHook,
+ swapToTokenAddress,
+ networkId,
+ walletAddress,
+ enableAppFee,
+}: {
+ swapFromToken: z.infer
+ postHook: Omit<
+ SquidHook,
+ 'fundAmount' | 'fundToken' | 'provider' | 'logoURI' | 'calls'
+ > & { calls: EvmContractCall[] } // we don't support CosmosCall
+ swapToTokenAddress: Address
+ networkId: NetworkId
+ walletAddress: Address
+ enableAppFee?: boolean
+}): Promise> {
+ const amountToSwap = parseUnits(swapFromToken.amount, swapFromToken.decimals)
+ // use the token's networkId if present, but fallback to the networkId
+ // as older clients supporting only same chain swap and deposit won't set it.
+ const fromNetworkId = swapFromToken.networkId ?? networkId
+
+ const swapParams = {
+ buyToken: swapToTokenAddress,
+ buyIsNative: false,
+ buyNetworkId: networkId,
+ ...(swapFromToken.address && { sellToken: swapFromToken.address }),
+ sellIsNative: swapFromToken.isNative,
+ sellNetworkId: fromNetworkId,
+ sellAmount: amountToSwap.toString(),
+ slippagePercentage: '1',
+ postHook,
+ userAddress: walletAddress,
+ enableAppFee,
+ }
+
+ const url = getConfig().GET_SWAP_QUOTE_URL
+
+ let swapQuote: GetSwapQuoteResponse
+
+ try {
+ swapQuote = await got
+ .post(url, { json: swapParams })
+ .json()
+ } catch (err) {
+ if (err instanceof HTTPError) {
+ logger.warn(
+ {
+ err,
+ response: err.response.body,
+ swapParams,
+ },
+ 'Got a non-2xx response from getSwapQuote',
+ )
+ } else {
+ logger.warn({ err, swapParams }, 'Error getting swap quote')
+ }
+ throw err
+ }
+
+ if (!swapQuote.unvalidatedSwapTransaction) {
+ logger.warn(
+ {
+ swapParams,
+ swapQuote,
+ },
+ 'No unvalidatedSwapTransaction in swapQuote',
+ )
+ throw new Error('Unable to get swap quote')
+ }
+
+ const client = getClient(fromNetworkId)
+
+ const transactions: Transaction[] = []
+ const { allowanceTarget } = swapQuote.unvalidatedSwapTransaction
+
+ if (allowanceTarget !== zeroAddress && swapFromToken.address) {
+ const approvedAllowanceForSpender = await client.readContract({
+ address: swapFromToken.address,
+ abi: erc20Abi,
+ functionName: 'allowance',
+ args: [walletAddress, allowanceTarget],
+ })
+
+ if (approvedAllowanceForSpender < amountToSwap) {
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: 'approve',
+ args: [allowanceTarget, amountToSwap],
+ })
+
+ const approveTx: Transaction = {
+ networkId: fromNetworkId,
+ from: walletAddress,
+ to: swapFromToken.address,
+ data,
+ }
+ transactions.push(approveTx)
+ }
+ }
+
+ const { from, to, data, value, gas, estimatedGasUse, simulationStatus } =
+ swapQuote.unvalidatedSwapTransaction
+
+ const swapTx: Transaction = {
+ networkId: fromNetworkId,
+ from,
+ to,
+ data,
+ value: BigInt(value),
+ // if gas was simulated, add a 15% buffer
+ gas:
+ simulationStatus === 'success'
+ ? (BigInt(gas) * 115n) / 100n
+ : BigInt(gas),
+ estimatedGasUse: estimatedGasUse ? BigInt(estimatedGasUse) : undefined,
+ }
+
+ transactions.push(swapTx)
+
+ return {
+ transactions,
+ dataProps: { swapTransaction: swapQuote.unvalidatedSwapTransaction },
+ }
+}
diff --git a/test/i18next.ts b/test/i18next.ts
new file mode 100644
index 00000000..c150eac0
--- /dev/null
+++ b/test/i18next.ts
@@ -0,0 +1,6 @@
+import { createI18Next } from '../src/utils/i18next'
+
+// Instance used for testing
+const testI18next = createI18Next()
+
+export const t = testI18next.t.bind(testI18next)
diff --git a/test/server.ts b/test/server.ts
new file mode 100644
index 00000000..cf0de04d
--- /dev/null
+++ b/test/server.ts
@@ -0,0 +1,397 @@
+import { setupServer } from 'msw/node'
+import { rest } from 'msw'
+
+const handlers = [
+ rest.get(
+ 'https://us-central1-celo-mobile-mainnet.cloudfunctions.net/getRtdbTokensInfo',
+ async (_req, res, ctx) => {
+ return res(
+ ctx.json({
+ tokens: {
+ '0x471ece3750da237f93b8e339c536989b8978a438': {
+ address: '0x471ece3750da237f93b8e339c536989b8978a438',
+ name: 'Celo native asset',
+ symbol: 'CELO',
+ decimals: 18,
+ usdPrice: '0.58326592153266402092',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/CELO.png',
+ },
+ '0x765de816845861e75a25fca122bb6898b8b1282a': {
+ address: '0x765de816845861e75a25fca122bb6898b8b1282a',
+ name: 'Celo Dollar',
+ symbol: 'cUSD',
+ decimals: 18,
+ usdPrice: '1',
+ imageUrl:
+ 'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/cUSD.png',
+ },
+ },
+ }),
+ )
+ },
+ ),
+ rest.get(
+ 'https://api.curve.fi/v1/getPools/all/celo',
+ async (_req, res, ctx) => {
+ return res(
+ ctx.json({
+ success: true,
+ data: {
+ poolData: [
+ // truncated list from actual test query to curve api https://api.curve.fi/v1/documentation/#/Pools/get_getPools__blockchainId___registryId_
+ {
+ id: 'factory-v2-0',
+ address: '0x998395fEd908d33CF27115A1D9Ab6555def6cd45',
+ coinsAddresses: [
+ '0x90Ca507a5D4458a4C6C6249d186b6dCb02a5BCCd',
+ '0xef4229c8c3250C675F21BCefa42f58EfbfF6002a',
+ '0x88eeC49252c8cbc039DCdB394c0c2BA2f1637EA0',
+ '0x0000000000000000000000000000000000000000',
+ ],
+ decimals: ['18', '6', '6', '0'],
+ virtualPrice: 0,
+ amplificationCoefficient: '400',
+ totalSupply: '0',
+ name: 'Curve.fi Factory Plain Pool: DAI/USDC/USDT',
+ assetType: '0',
+ implementationAddress:
+ '0xBcdCADB91446366d10b293152c967e64dE789B92',
+ symbol: 'celo-3CRV-f',
+ implementation: 'plain3basic',
+ assetTypeName: 'usd',
+ coins: [
+ {
+ address: '0x90Ca507a5D4458a4C6C6249d186b6dCb02a5BCCd',
+ usdPrice: 0.999668,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'DAI',
+ poolBalance: '0',
+ },
+ {
+ address: '0xef4229c8c3250C675F21BCefa42f58EfbfF6002a',
+ usdPrice: 1,
+ decimals: '6',
+ isBasePoolLpToken: false,
+ symbol: 'USDC',
+ poolBalance: '0',
+ },
+ {
+ address: '0x88eeC49252c8cbc039DCdB394c0c2BA2f1637EA0',
+ usdPrice: 1.001,
+ decimals: '6',
+ isBasePoolLpToken: false,
+ symbol: 'USDT',
+ poolBalance: '0',
+ },
+ ],
+ poolUrls: {
+ swap: [
+ 'https://curve.fi/#/celo/pools/factory-v2-0/swap',
+ 'https://celo.curve.fi/factory/0',
+ ],
+ deposit: [
+ 'https://curve.fi/#/celo/pools/factory-v2-0/deposit',
+ 'https://celo.curve.fi/factory/0/deposit',
+ ],
+ withdraw: [
+ 'https://curve.fi/#/celo/pools/factory-v2-0/withdraw',
+ 'https://celo.curve.fi/factory/0/withdraw',
+ ],
+ },
+ lpTokenAddress: '0x998395fEd908d33CF27115A1D9Ab6555def6cd45',
+ usdTotal: 0,
+ isMetaPool: false,
+ usdTotalExcludingBasePool: 0,
+ usesRateOracle: false,
+ isBroken: false,
+ },
+ {
+ id: 'factory-v2-1',
+ address: '0x32fD7e563c6521Ab4D59CE3277bcfBe3317CFd63',
+ coinsAddresses: [
+ '0x765DE816845861e75A25fCA122bb6898B8B1282a',
+ '0x37f750B7cC259A2f741AF45294f6a16572CF5cAd',
+ '0x617f3112bf5397D0467D315cC709EF968D9ba546',
+ '0x0000000000000000000000000000000000000000',
+ ],
+ decimals: ['18', '6', '6', '0'],
+ virtualPrice: '1004058888587887603',
+ amplificationCoefficient: '200',
+ totalSupply: '676201839080639239053585',
+ name: 'Curve.fi Factory Plain Pool: tripool',
+ assetType: '0',
+ implementationAddress:
+ '0xBcdCADB91446366d10b293152c967e64dE789B92',
+ symbol: 'cUSD3pool-f',
+ implementation: 'plain3basic',
+ assetTypeName: 'usd',
+ coins: [
+ {
+ address: '0x765DE816845861e75A25fCA122bb6898B8B1282a',
+ usdPrice: 0.998744,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'cUSD',
+ poolBalance: '267854857910499123887035',
+ },
+ {
+ address: '0x37f750B7cC259A2f741AF45294f6a16572CF5cAd',
+ usdPrice: 1,
+ decimals: '6',
+ isBasePoolLpToken: false,
+ symbol: 'USDC',
+ poolBalance: '223714127573',
+ },
+ {
+ address: '0x617f3112bf5397D0467D315cC709EF968D9ba546',
+ usdPrice: 1.000605,
+ decimals: '6',
+ isBasePoolLpToken: false,
+ symbol: 'USDT',
+ poolBalance: '187413876091',
+ },
+ ],
+ poolUrls: {
+ swap: [
+ 'https://curve.fi/#/celo/pools/factory-v2-1/swap',
+ 'https://celo.curve.fi/factory/1',
+ ],
+ deposit: [
+ 'https://curve.fi/#/celo/pools/factory-v2-1/deposit',
+ 'https://celo.curve.fi/factory/1/deposit',
+ ],
+ withdraw: [
+ 'https://curve.fi/#/celo/pools/factory-v2-1/withdraw',
+ 'https://celo.curve.fi/factory/1/withdraw',
+ ],
+ },
+ lpTokenAddress: '0x32fD7e563c6521Ab4D59CE3277bcfBe3317CFd63',
+ usdTotal: 678759.8212679987,
+ isMetaPool: false,
+ usdTotalExcludingBasePool: 678759.8212679987,
+ gaugeAddress: '0x18c45c10a0f41bc3ed8d6324c687335179a40b28',
+ usesRateOracle: false,
+ isBroken: false,
+ },
+ {
+ id: 'factory-v2-2',
+ address: '0xAF7Ee5Ba02dC9879D24cb16597cd854e13f3aDa8',
+ coinsAddresses: [
+ '0xC16B81Af351BA9e64C1a069E3Ab18c244A1E3049',
+ '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73',
+ '0x0000000000000000000000000000000000000000',
+ '0x0000000000000000000000000000000000000000',
+ ],
+ decimals: ['18', '18', '0', '0'],
+ virtualPrice: '17383049386256554431',
+ amplificationCoefficient: '200',
+ totalSupply: '35476026966646549',
+ name: 'Curve.fi Factory Plain Pool: agEUR/cEUR',
+ assetType: '3',
+ implementationAddress:
+ '0xfEE7166C32Bdf6356Ef60636f43400AA55551A96',
+ symbol: 'agEURcEUR-f',
+ implementation: 'plain2basic',
+ assetTypeName: 'other',
+ coins: [
+ {
+ address: '0xC16B81Af351BA9e64C1a069E3Ab18c244A1E3049',
+ usdPrice: 1.094,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'agEUR',
+ poolBalance: '460008637212874997',
+ },
+ {
+ address: '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73',
+ usdPrice: 1.092,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'cEUR',
+ poolBalance: '157158676672396128',
+ },
+ ],
+ poolUrls: {
+ swap: [
+ 'https://curve.fi/#/celo/pools/factory-v2-2/swap',
+ 'https://celo.curve.fi/factory/2',
+ ],
+ deposit: [
+ 'https://curve.fi/#/celo/pools/factory-v2-2/deposit',
+ 'https://celo.curve.fi/factory/2/deposit',
+ ],
+ withdraw: [
+ 'https://curve.fi/#/celo/pools/factory-v2-2/withdraw',
+ 'https://celo.curve.fi/factory/2/withdraw',
+ ],
+ },
+ lpTokenAddress: '0xAF7Ee5Ba02dC9879D24cb16597cd854e13f3aDa8',
+ usdTotal: 0.6748667240371419,
+ isMetaPool: false,
+ usdTotalExcludingBasePool: 0.6748667240371419,
+ gaugeAddress: '0x1f207d9235ab7667d38dceef9e75862cac6900a9',
+ gaugeRewards: [],
+ gaugeCrvApy: [0, 0],
+ usesRateOracle: false,
+ isBroken: false,
+ },
+ ],
+ tvlAll: 20709605.184946403,
+ tvl: 20709605.184946403,
+ },
+ generatedTimeMs: 1710357358479,
+ }),
+ )
+ },
+ ),
+ rest.get(
+ 'https://api.curve.fi/v1/getPools/all/ethereum',
+ async (_req, res, ctx) => {
+ return res(
+ ctx.json({
+ success: true,
+ data: {
+ poolData: [
+ // truncated list from actual test query to curve api https://api.curve.fi/v1/documentation/#/Pools/get_getPools__blockchainId___registryId_
+ {
+ id: 'factory-v2-0',
+ address: '0x1F71f05CF491595652378Fe94B7820344A551B8E',
+ coinsAddresses: [
+ '0x96E61422b6A9bA0e068B6c5ADd4fFaBC6a4aae27',
+ '0x57Ab1ec28D129707052df4dF418D58a2D46d5f51',
+ '0x0000000000000000000000000000000000000000',
+ '0x0000000000000000000000000000000000000000',
+ ],
+ decimals: ['18', '18', '0', '0'],
+ virtualPrice: 0,
+ amplificationCoefficient: '100',
+ totalSupply: '20000000000000000',
+ name: 'Curve.fi Factory Plain Pool: ibEUR/sEUR',
+ assetType: '99',
+ implementationAddress:
+ '0x6523Ac15EC152Cb70a334230F6c5d62C5Bd963f1',
+ symbol: 'ibEUR+sEUR-f',
+ implementation: 'plain2basic',
+ assetTypeName: 'unknown',
+ coins: [
+ {
+ address: '0x96E61422b6A9bA0e068B6c5ADd4fFaBC6a4aae27',
+ usdPrice: 1.0293825320572565,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'ibEUR',
+ poolBalance: '2440147371390294759297',
+ },
+ {
+ address: '0x57Ab1ec28D129707052df4dF418D58a2D46d5f51',
+ usdPrice: 1.0017291207272516,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'sUSD',
+ poolBalance: '2182087364350',
+ },
+ ],
+ poolUrls: {
+ swap: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-0/swap',
+ 'https://classic.curve.fi/factory/0',
+ ],
+ deposit: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-0/deposit',
+ 'https://classic.curve.fi/factory/0/deposit',
+ ],
+ withdraw: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-0/withdraw',
+ 'https://classic.curve.fi/factory/0/withdraw',
+ ],
+ },
+ lpTokenAddress: '0x1F71f05CF491595652378Fe94B7820344A551B8E',
+ usdTotal: 2511.8450819404607,
+ isMetaPool: false,
+ usdTotalExcludingBasePool: 2511.8450819404607,
+ usesRateOracle: false,
+ isBroken: false,
+ },
+ {
+ id: 'factory-v2-145',
+ address: '0xe7A3b38c39F97E977723bd1239C3470702568e7B',
+ coinsAddresses: [
+ '0xEE586e7Eaad39207F0549BC65f19e336942C992f',
+ '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8',
+ '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
+ '0x0000000000000000000000000000000000000000',
+ ],
+ decimals: ['18', '18', '6', '0'],
+ virtualPrice: '1003840784416721236',
+ amplificationCoefficient: '10',
+ totalSupply: '207711420092740613091153',
+ name: 'Curve.fi Factory Plain Pool: Euro Pool',
+ assetType: '3',
+ implementationAddress:
+ '0x9B52F13DF69D79Ec5aAB6D1aCe3157d29B409cC3',
+ symbol: 'europool-f',
+ implementation: 'plain3basic',
+ assetTypeName: 'other',
+ coins: [
+ {
+ address: '0xEE586e7Eaad39207F0549BC65f19e336942C992f',
+ usdPrice: 1.0693998825835587,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'cEUR',
+ poolBalance: '77041895193731946061232',
+ },
+ {
+ address: '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8',
+ usdPrice: 1.086,
+ decimals: '18',
+ isBasePoolLpToken: false,
+ symbol: 'EURA',
+ poolBalance: '67538628832312070530528',
+ },
+ {
+ address: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
+ usdPrice: 1.082,
+ decimals: '6',
+ isBasePoolLpToken: false,
+ symbol: 'EURC',
+ poolBalance: '63987165776',
+ },
+ ],
+ poolUrls: {
+ swap: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-145/swap',
+ 'https://classic.curve.fi/factory/145',
+ ],
+ deposit: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-145/deposit',
+ 'https://classic.curve.fi/factory/145/deposit',
+ ],
+ withdraw: [
+ 'https://curve.fi/#/ethereum/pools/factory-v2-145/withdraw',
+ 'https://classic.curve.fi/factory/145/withdraw',
+ ],
+ },
+ lpTokenAddress: '0xe7A3b38c39F97E977723bd1239C3470702568e7B',
+ usdTotal: 224969.65795571468,
+ isMetaPool: false,
+ usdTotalExcludingBasePool: 224969.65795571468,
+ gaugeAddress: '0x9f57569eaa61d427deeebac8d9546a745160391c',
+ gaugeRewards: [],
+ gaugeCrvApy: [0.06816638061949697, 0.17041595154874242],
+ gaugeFutureCrvApy: [0.06798905631851226, 0.16997264079628066],
+ usesRateOracle: false,
+ isBroken: false,
+ },
+ ],
+ },
+ }),
+ )
+ },
+ ),
+]
+
+// This configures a request mocking server with the given request handlers.
+export const server = setupServer(...handlers)
diff --git a/yarn.lock b/yarn.lock
index 34ff096f..b762947d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,15 +2,23 @@
# yarn lockfile v1
+"@0xsquid/squid-types@^0.1.137":
+ version "0.1.137"
+ resolved "https://registry.yarnpkg.com/@0xsquid/squid-types/-/squid-types-0.1.137.tgz#d25a4e127fc5a3810edfc3dd51e174ac8968f1d9"
+ integrity sha512-RDLiTMtVWStq1O2BhrnciUy+2IorsIupTlyC/cgoOgQdahyjaLBmLZk8wj5iFN64z88tEZaH4NUKEAmH1E54hQ==
+ dependencies:
+ long "^5.2.4"
+ typescript "*"
+
"@aashutoshrathi/word-wrap@^1.2.3":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
-"@adraffy/ens-normalize@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d"
- integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==
+"@adraffy/ens-normalize@^1.10.1":
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33"
+ integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==
"@ampproject/remapping@^2.1.0":
version "2.2.0"
@@ -20,12 +28,13 @@
"@jridgewell/gen-mapping" "^0.1.0"
"@jridgewell/trace-mapping" "^0.3.9"
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.21.4":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658"
- integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1":
+ version "7.24.2"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
+ integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==
dependencies:
- "@babel/highlight" "^7.22.5"
+ "@babel/highlight" "^7.24.2"
+ picocolors "^1.0.0"
"@babel/compat-data@^7.17.10":
version "7.18.5"
@@ -53,13 +62,14 @@
json5 "^2.2.1"
semver "^6.3.0"
-"@babel/generator@^7.18.2", "@babel/generator@^7.7.2":
- version "7.18.2"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d"
- integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==
+"@babel/generator@^7.18.2", "@babel/generator@^7.24.1", "@babel/generator@^7.7.2":
+ version "7.24.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498"
+ integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==
dependencies:
- "@babel/types" "^7.18.2"
- "@jridgewell/gen-mapping" "^0.3.0"
+ "@babel/types" "^7.24.0"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
jsesc "^2.5.1"
"@babel/helper-compilation-targets@^7.18.2":
@@ -72,25 +82,25 @@
browserslist "^4.20.2"
semver "^6.3.0"
-"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2":
- version "7.18.2"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd"
- integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==
+"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
-"@babel/helper-function-name@^7.17.9":
- version "7.17.9"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12"
- integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
- "@babel/template" "^7.16.7"
- "@babel/types" "^7.17.0"
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
-"@babel/helper-hoist-variables@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246"
- integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
- "@babel/types" "^7.16.7"
+ "@babel/types" "^7.22.5"
"@babel/helper-module-imports@^7.16.7":
version "7.16.7"
@@ -125,17 +135,22 @@
dependencies:
"@babel/types" "^7.18.2"
-"@babel/helper-split-export-declaration@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b"
- integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==
+"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
dependencies:
- "@babel/types" "^7.16.7"
+ "@babel/types" "^7.22.5"
-"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
- integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
+"@babel/helper-string-parser@^7.23.4":
+ version "7.24.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e"
+ integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==
+
+"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.16.7":
version "7.16.7"
@@ -151,19 +166,20 @@
"@babel/traverse" "^7.18.2"
"@babel/types" "^7.18.2"
-"@babel/highlight@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
- integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==
+"@babel/highlight@^7.24.2":
+ version "7.24.2"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26"
+ integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==
dependencies:
- "@babel/helper-validator-identifier" "^7.22.5"
- chalk "^2.0.0"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
js-tokens "^4.0.0"
+ picocolors "^1.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5":
- version "7.18.5"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c"
- integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.5", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1":
+ version "7.24.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88"
+ integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
@@ -263,37 +279,45 @@
dependencies:
"@babel/helper-plugin-utils" "^7.17.12"
-"@babel/template@^7.16.7", "@babel/template@^7.3.3":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
- integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==
- dependencies:
- "@babel/code-frame" "^7.16.7"
- "@babel/parser" "^7.16.7"
- "@babel/types" "^7.16.7"
-
-"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5", "@babel/traverse@^7.7.4":
- version "7.18.5"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd"
- integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==
- dependencies:
- "@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.18.2"
- "@babel/helper-environment-visitor" "^7.18.2"
- "@babel/helper-function-name" "^7.17.9"
- "@babel/helper-hoist-variables" "^7.16.7"
- "@babel/helper-split-export-declaration" "^7.16.7"
- "@babel/parser" "^7.18.5"
- "@babel/types" "^7.18.4"
- debug "^4.1.0"
+"@babel/runtime@^7.26.10":
+ version "7.26.10"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2"
+ integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.3.3":
+ version "7.24.0"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
+ integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==
+ dependencies:
+ "@babel/code-frame" "^7.23.5"
+ "@babel/parser" "^7.24.0"
+ "@babel/types" "^7.24.0"
+
+"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5":
+ version "7.24.1"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c"
+ integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==
+ dependencies:
+ "@babel/code-frame" "^7.24.1"
+ "@babel/generator" "^7.24.1"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.24.1"
+ "@babel/types" "^7.24.0"
+ debug "^4.3.1"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
- version "7.18.4"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354"
- integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==
+"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+ version "7.24.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf"
+ integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==
dependencies:
- "@babel/helper-validator-identifier" "^7.16.7"
+ "@babel/helper-string-parser" "^7.23.4"
+ "@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3":
@@ -301,10 +325,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@colors/colors@1.5.0":
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
- integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
+"@bgd-labs/aave-address-book@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@bgd-labs/aave-address-book/-/aave-address-book-4.17.2.tgz#976823b4c825aeda33bd9375705260aef857c88c"
+ integrity sha512-UVVCaLlLBA5VHl+qip/9qH8yZnNyIvyeRd4nHgKAluNbjeyRPzqESqToGmWSvtWOYK2kUtOrWCu0z9ncq6t6IA==
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
@@ -313,22 +337,22 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
-"@eslint-community/eslint-utils@^4.2.0":
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a"
- integrity sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.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.4.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403"
- integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==
+"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1":
+ version "4.10.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
+ integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
-"@eslint/eslintrc@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d"
- integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==
+"@eslint/eslintrc@^2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
+ integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@@ -340,23 +364,114 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@8.44.0":
- version "8.44.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af"
- integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==
+"@eslint/js@8.57.1":
+ version "8.57.1"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
+ integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
-"@gar/promisify@^1.1.3":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
- integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
+"@google-cloud/common@^5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/common/-/common-5.0.0.tgz#578246e0af02d68aa94aefb03d737bca37554dd0"
+ integrity sha512-IsbTVr7Ag+04GMT87X738vDs85QU1rMvaesm2wEQrtTbZAR92tGmUQ8/D/kdnYgAi98Q4zmfhF+T8Xs/Lw4zAA==
+ dependencies:
+ "@google-cloud/projectify" "^4.0.0"
+ "@google-cloud/promisify" "^4.0.0"
+ arrify "^2.0.1"
+ duplexify "^4.1.1"
+ ent "^2.2.0"
+ extend "^3.0.2"
+ google-auth-library "^9.0.0"
+ retry-request "^6.0.0"
+ teeny-request "^9.0.0"
+
+"@google-cloud/functions-framework@^3.1.3", "@google-cloud/functions-framework@^3.5.1":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/@google-cloud/functions-framework/-/functions-framework-3.5.1.tgz#5066c8841f4393ea97b8745c8c2d9ecda3a08695"
+ integrity sha512-J01F8mCAb9SEsEGOJjKR/1UHmZTzBWIBNjAETtiPx7Xie3WgeWTvMnfrbsZbaBG0oePkepRxo28R8Fi9B2J++A==
+ dependencies:
+ "@types/express" "^4.17.21"
+ body-parser "^1.18.3"
+ cloudevents "^8.0.2"
+ express "^4.21.2"
+ minimist "^1.2.8"
+ on-finished "^2.3.0"
+ read-pkg-up "^7.0.1"
+ semver "^7.6.3"
-"@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==
+"@google-cloud/logging-bunyan@^5.1.0":
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/logging-bunyan/-/logging-bunyan-5.1.0.tgz#443eb338988554e459d21247c67386922e1e9a1c"
+ integrity sha512-D2Rg5nb+onjWre4eEowWyNmVF1RN7WThWdu1cCOcTMVOoVEGJphMxrBo9VQKQmkqdlAUG4NaM6i2sqieISQDsg==
+ dependencies:
+ "@google-cloud/logging" "^11.0.0"
+ google-auth-library "^9.0.0"
+
+"@google-cloud/logging@^11.0.0", "@google-cloud/logging@^11.2.0":
+ version "11.2.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/logging/-/logging-11.2.0.tgz#d282f136467cc4500932f1fa6d4fe58325eb2db2"
+ integrity sha512-Ma94jvuoMpbgNniwtelOt8w82hxK62FuOXZonEv0Hyk3B+/YVuLG/SWNyY9yMso/RXnPEc1fP2qo9kDrjf/b2w==
+ dependencies:
+ "@google-cloud/common" "^5.0.0"
+ "@google-cloud/paginator" "^5.0.0"
+ "@google-cloud/projectify" "^4.0.0"
+ "@google-cloud/promisify" "^4.0.0"
+ "@opentelemetry/api" "^1.7.0"
+ arrify "^2.0.1"
+ dot-prop "^6.0.0"
+ eventid "^2.0.0"
+ extend "^3.0.2"
+ gcp-metadata "^6.0.0"
+ google-auth-library "^9.0.0"
+ google-gax "^4.0.3"
+ on-finished "^2.3.0"
+ pumpify "^2.0.1"
+ stream-events "^1.0.5"
+ uuid "^9.0.0"
+
+"@google-cloud/paginator@^5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-5.0.0.tgz#b8cc62f151685095d11467402cbf417c41bf14e6"
+ integrity sha512-87aeg6QQcEPxGCOthnpUjvw4xAZ57G7pL8FS0C4e/81fr3FjkpUpibf1s2v5XGyGhUVGF4Jfg7yEcxqn2iUw1w==
dependencies:
- "@humanwhocodes/object-schema" "^1.2.1"
- debug "^4.1.1"
+ arrify "^2.0.0"
+ extend "^3.0.2"
+
+"@google-cloud/projectify@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-4.0.0.tgz#d600e0433daf51b88c1fa95ac7f02e38e80a07be"
+ integrity sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==
+
+"@google-cloud/promisify@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-4.0.0.tgz#a906e533ebdd0f754dca2509933334ce58b8c8b1"
+ integrity sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==
+
+"@grpc/grpc-js@~1.8.0":
+ version "1.8.22"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.22.tgz#847930c9af46e14df05b57fc12325db140ceff1d"
+ integrity sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA==
+ 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.13.0":
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748"
+ integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
+ dependencies:
+ "@humanwhocodes/object-schema" "^2.0.3"
+ debug "^4.3.1"
minimatch "^3.0.5"
"@humanwhocodes/module-importer@^1.0.1":
@@ -364,15 +479,10 @@
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==
-
-"@isaacs/string-locale-compare@^1.1.0":
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b"
- integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==
+"@humanwhocodes/object-schema@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
+ integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
@@ -390,109 +500,109 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
-"@jest/console@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.1.tgz#b48ba7b9c34b51483e6d590f46e5837f1ab5f639"
- integrity sha512-Aj772AYgwTSr5w8qnyoJ0eDYvN6bMsH3ORH1ivMotrInHLKdUz6BDlaEXHdM6kODaBIkNIyQGzsMvRdOv7VG7Q==
+"@jest/console@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc"
+ integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
chalk "^4.0.0"
- jest-message-util "^29.6.1"
- jest-util "^29.6.1"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
slash "^3.0.0"
-"@jest/core@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.1.tgz#fac0d9ddf320490c93356ba201451825231e95f6"
- integrity sha512-CcowHypRSm5oYQ1obz1wfvkjZZ2qoQlrKKvlfPwh5jUXVU12TWr2qMeH8chLMuTFzHh5a1g2yaqlqDICbr+ukQ==
+"@jest/core@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f"
+ integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==
dependencies:
- "@jest/console" "^29.6.1"
- "@jest/reporters" "^29.6.1"
- "@jest/test-result" "^29.6.1"
- "@jest/transform" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/console" "^29.7.0"
+ "@jest/reporters" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
ansi-escapes "^4.2.1"
chalk "^4.0.0"
ci-info "^3.2.0"
exit "^0.1.2"
graceful-fs "^4.2.9"
- jest-changed-files "^29.5.0"
- jest-config "^29.6.1"
- jest-haste-map "^29.6.1"
- jest-message-util "^29.6.1"
- jest-regex-util "^29.4.3"
- jest-resolve "^29.6.1"
- jest-resolve-dependencies "^29.6.1"
- jest-runner "^29.6.1"
- jest-runtime "^29.6.1"
- jest-snapshot "^29.6.1"
- jest-util "^29.6.1"
- jest-validate "^29.6.1"
- jest-watcher "^29.6.1"
+ jest-changed-files "^29.7.0"
+ jest-config "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-resolve-dependencies "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ jest-watcher "^29.7.0"
micromatch "^4.0.4"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
slash "^3.0.0"
strip-ansi "^6.0.0"
-"@jest/environment@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.1.tgz#ee358fff2f68168394b4a50f18c68278a21fe82f"
- integrity sha512-RMMXx4ws+Gbvw3DfLSuo2cfQlK7IwGbpuEWXCqyYDcqYTI+9Ju3a5hDnXaxjNsa6uKh9PQF2v+qg+RLe63tz5A==
+"@jest/environment@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7"
+ integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==
dependencies:
- "@jest/fake-timers" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
- jest-mock "^29.6.1"
+ jest-mock "^29.7.0"
-"@jest/expect-utils@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.1.tgz#ab83b27a15cdd203fe5f68230ea22767d5c3acc5"
- integrity sha512-o319vIf5pEMx0LmzSxxkYYxo4wrRLKHq9dP1yJU7FoPTB0LfAKSz8SWD6D/6U3v/O52t9cF5t+MeJiRsfk7zMw==
+"@jest/expect-utils@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6"
+ integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==
dependencies:
- jest-get-type "^29.4.3"
+ jest-get-type "^29.6.3"
-"@jest/expect@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.1.tgz#fef18265188f6a97601f1ea0a2912d81a85b4657"
- integrity sha512-N5xlPrAYaRNyFgVf2s9Uyyvr795jnB6rObuPx4QFvNJz8aAjpZUDfO4bh5G/xuplMID8PrnuF1+SfSyDxhsgYg==
+"@jest/expect@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2"
+ integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==
dependencies:
- expect "^29.6.1"
- jest-snapshot "^29.6.1"
+ expect "^29.7.0"
+ jest-snapshot "^29.7.0"
-"@jest/fake-timers@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.1.tgz#c773efddbc61e1d2efcccac008139f621de57c69"
- integrity sha512-RdgHgbXyosCDMVYmj7lLpUwXA4c69vcNzhrt69dJJdf8azUrpRh3ckFCaTPNjsEeRi27Cig0oKDGxy5j7hOgHg==
+"@jest/fake-timers@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565"
+ integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@sinonjs/fake-timers" "^10.0.2"
"@types/node" "*"
- jest-message-util "^29.6.1"
- jest-mock "^29.6.1"
- jest-util "^29.6.1"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
-"@jest/globals@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.1.tgz#c8a8923e05efd757308082cc22893d82b8aa138f"
- integrity sha512-2VjpaGy78JY9n9370H8zGRCFbYVWwjY6RdDMhoJHa1sYfwe6XM/azGN0SjY8kk7BOZApIejQ1BFPyH7FPG0w3A==
+"@jest/globals@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d"
+ integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==
dependencies:
- "@jest/environment" "^29.6.1"
- "@jest/expect" "^29.6.1"
- "@jest/types" "^29.6.1"
- jest-mock "^29.6.1"
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ jest-mock "^29.7.0"
-"@jest/reporters@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.1.tgz#3325a89c9ead3cf97ad93df3a427549d16179863"
- integrity sha512-9zuaI9QKr9JnoZtFQlw4GREQbxgmNYXU6QuWtmuODvk5nvPUeBYapVR/VYMyi2WSx3jXTLJTJji8rN6+Cm4+FA==
+"@jest/reporters@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7"
+ integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==
dependencies:
"@bcoe/v8-coverage" "^0.2.3"
- "@jest/console" "^29.6.1"
- "@jest/test-result" "^29.6.1"
- "@jest/transform" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/console" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@jridgewell/trace-mapping" "^0.3.18"
"@types/node" "*"
chalk "^4.0.0"
@@ -501,81 +611,81 @@
glob "^7.1.3"
graceful-fs "^4.2.9"
istanbul-lib-coverage "^3.0.0"
- istanbul-lib-instrument "^5.1.0"
+ istanbul-lib-instrument "^6.0.0"
istanbul-lib-report "^3.0.0"
istanbul-lib-source-maps "^4.0.0"
istanbul-reports "^3.1.3"
- jest-message-util "^29.6.1"
- jest-util "^29.6.1"
- jest-worker "^29.6.1"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
slash "^3.0.0"
string-length "^4.0.1"
strip-ansi "^6.0.0"
v8-to-istanbul "^9.0.1"
-"@jest/schemas@^29.6.0":
- version "29.6.0"
- resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040"
- integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
dependencies:
"@sinclair/typebox" "^0.27.8"
-"@jest/source-map@^29.6.0":
- version "29.6.0"
- resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1"
- integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA==
+"@jest/source-map@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4"
+ integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==
dependencies:
"@jridgewell/trace-mapping" "^0.3.18"
callsites "^3.0.0"
graceful-fs "^4.2.9"
-"@jest/test-result@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.1.tgz#850e565a3f58ee8ca6ec424db00cb0f2d83c36ba"
- integrity sha512-Ynr13ZRcpX6INak0TPUukU8GWRfm/vAytE3JbJNGAvINySWYdfE7dGZMbk36oVuK4CigpbhMn8eg1dixZ7ZJOw==
+"@jest/test-result@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c"
+ integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==
dependencies:
- "@jest/console" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/console" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/istanbul-lib-coverage" "^2.0.0"
collect-v8-coverage "^1.0.0"
-"@jest/test-sequencer@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.1.tgz#e3e582ee074dd24ea9687d7d1aaf05ee3a9b068e"
- integrity sha512-oBkC36PCDf/wb6dWeQIhaviU0l5u6VCsXa119yqdUosYAt7/FbQU2M2UoziO3igj/HBDEgp57ONQ3fm0v9uyyg==
+"@jest/test-sequencer@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce"
+ integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==
dependencies:
- "@jest/test-result" "^29.6.1"
+ "@jest/test-result" "^29.7.0"
graceful-fs "^4.2.9"
- jest-haste-map "^29.6.1"
+ jest-haste-map "^29.7.0"
slash "^3.0.0"
-"@jest/transform@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.1.tgz#acb5606019a197cb99beda3c05404b851f441c92"
- integrity sha512-URnTneIU3ZjRSaf906cvf6Hpox3hIeJXRnz3VDSw5/X93gR8ycdfSIEy19FlVx8NFmpN7fe3Gb1xF+NjXaQLWg==
+"@jest/transform@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c"
+ integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==
dependencies:
"@babel/core" "^7.11.6"
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@jridgewell/trace-mapping" "^0.3.18"
babel-plugin-istanbul "^6.1.1"
chalk "^4.0.0"
convert-source-map "^2.0.0"
fast-json-stable-stringify "^2.1.0"
graceful-fs "^4.2.9"
- jest-haste-map "^29.6.1"
- jest-regex-util "^29.4.3"
- jest-util "^29.6.1"
+ jest-haste-map "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
micromatch "^4.0.4"
pirates "^4.0.4"
slash "^3.0.0"
write-file-atomic "^4.0.2"
-"@jest/types@^29.6.1":
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2"
- integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==
+"@jest/types@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59"
+ integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
dependencies:
- "@jest/schemas" "^29.6.0"
+ "@jest/schemas" "^29.6.3"
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
@@ -590,26 +700,26 @@
"@jridgewell/set-array" "^1.0.0"
"@jridgewell/sourcemap-codec" "^1.4.10"
-"@jridgewell/gen-mapping@^0.3.0":
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9"
- integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==
+"@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
+ integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
dependencies:
- "@jridgewell/set-array" "^1.0.0"
+ "@jridgewell/set-array" "^1.2.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
- "@jridgewell/trace-mapping" "^0.3.9"
+ "@jridgewell/trace-mapping" "^0.3.24"
-"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
+"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
-"@jridgewell/set-array@^1.0.0":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
- integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
+"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
-"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
@@ -622,25 +732,47 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
-"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9":
- version "0.3.18"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
- integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.25"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+ integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
dependencies:
- "@jridgewell/resolve-uri" "3.1.0"
- "@jridgewell/sourcemap-codec" "1.4.14"
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
-"@noble/curves@1.0.0", "@noble/curves@~1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932"
- integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==
+"@mswjs/cookies@^0.2.2":
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-0.2.2.tgz#b4e207bf6989e5d5427539c2443380a33ebb922b"
+ integrity sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==
dependencies:
- "@noble/hashes" "1.3.0"
+ "@types/set-cookie-parser" "^2.4.0"
+ set-cookie-parser "^2.4.6"
-"@noble/hashes@1.3.0", "@noble/hashes@~1.3.0":
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
- integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
+"@mswjs/interceptors@^0.17.10":
+ version "0.17.10"
+ resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.10.tgz#857b41f30e2b92345ed9a4e2b1d0a08b8b6fcad4"
+ integrity sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==
+ dependencies:
+ "@open-draft/until" "^1.0.3"
+ "@types/debug" "^4.1.7"
+ "@xmldom/xmldom" "^0.8.3"
+ debug "^4.3.3"
+ headers-polyfill "3.2.5"
+ outvariant "^1.2.1"
+ strict-event-emitter "^0.2.4"
+ web-encoding "^1.1.5"
+
+"@noble/curves@1.8.1", "@noble/curves@^1.6.0", "@noble/curves@~1.8.1":
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.1.tgz#19bc3970e205c99e4bdb1c64a4785706bce497ff"
+ integrity sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==
+ dependencies:
+ "@noble/hashes" "1.7.1"
+
+"@noble/hashes@1.7.1", "@noble/hashes@^1.5.0", "@noble/hashes@~1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f"
+ integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -663,399 +795,95 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@npmcli/arborist@^6.2.5":
- version "6.2.5"
- resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-6.2.5.tgz#b35c6ec42feeb7b44d6a6fcd2ea323e35b256d80"
- integrity sha512-+GPm+9WrDnl9q+LvuMB2W+roVinHTGDdYWOtYzRfpAnuiqaATFbH14skpXjlJ7LvyUcyd1oJhuGq6XXJLGFNng==
- dependencies:
- "@isaacs/string-locale-compare" "^1.1.0"
- "@npmcli/fs" "^3.1.0"
- "@npmcli/installed-package-contents" "^2.0.2"
- "@npmcli/map-workspaces" "^3.0.2"
- "@npmcli/metavuln-calculator" "^5.0.0"
- "@npmcli/name-from-folder" "^2.0.0"
- "@npmcli/node-gyp" "^3.0.0"
- "@npmcli/package-json" "^3.0.0"
- "@npmcli/query" "^3.0.0"
- "@npmcli/run-script" "^6.0.0"
- bin-links "^4.0.1"
- cacache "^17.0.4"
- common-ancestor-path "^1.0.1"
- hosted-git-info "^6.1.1"
- json-parse-even-better-errors "^3.0.0"
- json-stringify-nice "^1.1.4"
- minimatch "^6.1.6"
- nopt "^7.0.0"
- npm-install-checks "^6.0.0"
- npm-package-arg "^10.1.0"
- npm-pick-manifest "^8.0.1"
- npm-registry-fetch "^14.0.3"
- npmlog "^7.0.1"
- pacote "^15.0.8"
- parse-conflict-json "^3.0.0"
- proc-log "^3.0.0"
- promise-all-reject-late "^1.0.0"
- promise-call-limit "^1.0.1"
- read-package-json-fast "^3.0.2"
- semver "^7.3.7"
- ssri "^10.0.1"
- treeverse "^3.0.0"
- walk-up-path "^1.0.0"
-
-"@npmcli/config@^6.1.4":
- version "6.1.4"
- resolved "https://registry.yarnpkg.com/@npmcli/config/-/config-6.1.4.tgz#b7751d6629892b0e1bd33b2f377e66a5ea1f7765"
- integrity sha512-3bIf/86iQ9ac86hy5uzE1kQnwgd9W/kmZ+K/OmYWuBMX97PQi4yLZHqn2xtfukwF/3/6NjUPxYC1H/aP3nImCA==
- dependencies:
- "@npmcli/map-workspaces" "^3.0.2"
- ini "^3.0.0"
- nopt "^7.0.0"
- proc-log "^3.0.0"
- read-package-json-fast "^3.0.2"
- semver "^7.3.5"
- walk-up-path "^1.0.0"
-
-"@npmcli/disparity-colors@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/disparity-colors/-/disparity-colors-3.0.0.tgz#60ea8c6eb5ba9de2d1950e15b06205b2c3ab7833"
- integrity sha512-5R/z157/f20Fi0Ou4ZttL51V0xz0EdPEOauFtPCEYOLInDBRCj1/TxOJ5aGTrtShxEshN2d+hXb9ZKSi5RLBcg==
- dependencies:
- ansi-styles "^4.3.0"
-
-"@npmcli/fs@^2.1.0":
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865"
- integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==
- dependencies:
- "@gar/promisify" "^1.1.3"
- semver "^7.3.5"
-
-"@npmcli/fs@^3.1.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.0.tgz#233d43a25a91d68c3a863ba0da6a3f00924a173e"
- integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==
- dependencies:
- semver "^7.3.5"
-
-"@npmcli/git@^4.0.0", "@npmcli/git@^4.0.1":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-4.0.4.tgz#cdf74f21b1d440c0756fb28159d935129d9daa33"
- integrity sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==
- dependencies:
- "@npmcli/promise-spawn" "^6.0.0"
- lru-cache "^7.4.4"
- npm-pick-manifest "^8.0.0"
- proc-log "^3.0.0"
- promise-inflight "^1.0.1"
- promise-retry "^2.0.1"
- semver "^7.3.5"
- which "^3.0.0"
-
-"@npmcli/installed-package-contents@^2.0.1", "@npmcli/installed-package-contents@^2.0.2":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33"
- integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==
- dependencies:
- npm-bundled "^3.0.0"
- npm-normalize-package-bin "^3.0.0"
-
-"@npmcli/map-workspaces@^3.0.2":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.3.tgz#476944b63cd1f65bf83c6fdc7f4ca7be56906b1f"
- integrity sha512-HlCvFuTzw4UNoKyZdqiNrln+qMF71QJkxy2dsusV8QQdoa89e2TF4dATCzBxbl4zzRzdDoWWyP5ADVrNAH9cRQ==
- dependencies:
- "@npmcli/name-from-folder" "^2.0.0"
- glob "^9.3.1"
- minimatch "^7.4.2"
- read-package-json-fast "^3.0.0"
-
-"@npmcli/metavuln-calculator@^5.0.0":
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-5.0.0.tgz#917c3be49ebed0b424b07f38060b929127e4c499"
- integrity sha512-BBFQx4M12wiEuVwCgtX/Depx0B/+NHMwDWOlXT41/Pdy5W/1Fenk+hibUlMSrFWwASbX+fY90UbILAEIYH02/A==
- dependencies:
- cacache "^17.0.0"
- json-parse-even-better-errors "^3.0.0"
- pacote "^15.0.0"
- semver "^7.3.5"
-
-"@npmcli/move-file@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4"
- integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==
- dependencies:
- mkdirp "^1.0.4"
- rimraf "^3.0.2"
-
-"@npmcli/name-from-folder@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815"
- integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==
-
-"@npmcli/node-gyp@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a"
- integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==
+"@open-draft/until@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca"
+ integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==
-"@npmcli/package-json@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-3.0.0.tgz#c9219a197e1be8dbf43c4ef8767a72277c0533b6"
- integrity sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg==
- dependencies:
- json-parse-even-better-errors "^3.0.0"
+"@opentelemetry/api@^1.7.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe"
+ integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==
-"@npmcli/promise-spawn@^6.0.0", "@npmcli/promise-spawn@^6.0.1":
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2"
- integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==
- dependencies:
- which "^3.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==
-"@npmcli/query@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/query/-/query-3.0.0.tgz#51a0dfb85811e04f244171f164b6bc83b36113a7"
- integrity sha512-MFNDSJNgsLZIEBVZ0Q9w9K7o07j5N4o4yjtdz2uEpuCZlXGMuPENiRaFYk0vRqAA64qVuUQwC05g27fRtfUgnA==
- dependencies:
- postcss-selector-parser "^6.0.10"
+"@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==
-"@npmcli/run-script@^6.0.0":
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.0.tgz#f89e322c729e26ae29db6cc8cc76559074aac208"
- integrity sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==
- dependencies:
- "@npmcli/node-gyp" "^3.0.0"
- "@npmcli/promise-spawn" "^6.0.0"
- node-gyp "^9.0.0"
- read-package-json-fast "^3.0.0"
- which "^3.0.0"
+"@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==
-"@octokit/auth-token@^3.0.0":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.3.tgz#ce7e48a3166731f26068d7a7a7996b5da58cbe0c"
- integrity sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==
- dependencies:
- "@octokit/types" "^9.0.0"
-
-"@octokit/core@^4.2.1":
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.1.tgz#fee6341ad0ce60c29cc455e056cd5b500410a588"
- integrity sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==
- 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.5"
- resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.5.tgz#2bb2a911c12c50f10014183f5d596ce30ac67dd1"
- integrity sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==
- 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.5"
- resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.5.tgz#a4cb3ea73f83b861893a6370ee82abb36e81afd2"
- integrity sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==
- 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@^7.0.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-7.1.0.tgz#71a042c06b2fad793148426a526492f86b126132"
- integrity sha512-vbKrs/VZ8Sx4T9IxxxnksL969L705GkcgrzdlJoF0rVxjTfetYUmaGzD9oUvNhbx9MrxOZreYJlpm1BySe2Z9w==
- dependencies:
- "@octokit/tsconfig" "^1.0.2"
- "@octokit/types" "^9.3.1"
+"@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==
-"@octokit/plugin-retry@^5.0.0":
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-retry/-/plugin-retry-5.0.2.tgz#c324506d08fa01080cc22f10b9f12dfeb096ba79"
- integrity sha512-/Z7rWLCfjwmaVdyFuMkZoAnhfrvYgtvDrbO2d6lv7XrvJa8gFGB5tLUMngfuyMBfDCc5B9+EVu7IkQx5ebVlMg==
+"@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:
- "@octokit/types" "^9.0.0"
- bottleneck "^2.15.3"
+ "@protobufjs/aspromise" "^1.1.1"
+ "@protobufjs/inquire" "^1.1.0"
-"@octokit/plugin-throttling@^6.0.0":
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-6.1.0.tgz#093275e6b542be371acb0631252a428f2f1b0615"
- integrity sha512-JqMbTiPC0sUSTsLQsdq3JVx1mx8UtTo5mwR80YqPXE93+XhevvSyOR1rO2Z+NbO/r0TK4hqFJSSi/9oIZBxZTg==
- dependencies:
- "@octokit/types" "^9.0.0"
- bottleneck "^2.15.3"
+"@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==
-"@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"
+"@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==
-"@octokit/request@^6.0.0":
- version "6.2.3"
- resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.3.tgz#76d5d6d44da5c8d406620a4c285d280ae310bdb4"
- integrity sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==
- 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"
+"@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==
-"@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==
+"@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==
-"@octokit/types@^9.0.0", "@octokit/types@^9.3.1":
- version "9.3.1"
- resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.1.tgz#9eb20390f8cfcc975635d813f9a2094efd4aa2dd"
- integrity sha512-zfJzyXLHC42sWcn2kS+oZ/DRvFZBYCCbfInZtwp1Uopl1qh6pRg4NSP/wFX1xCOpXvEkctiG1sxlSlkZmzvxdw==
- dependencies:
- "@octokit/openapi-types" "^18.0.0"
+"@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==
-"@pnpm/config.env-replace@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.0.0.tgz#c76fa65847c9554e88d910f264c2ba9a1575e833"
- integrity sha512-ZVPVDi1E8oeXlYqkGRtX0CkzLTwE2zt62bjWaWKaAvI8NZqHzlMvGeSNDpW+JB3+aKanYb4UETJOF1/CxGPemA==
+"@rtsao/scc@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
+ integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
-"@pnpm/network.ca-file@^1.0.1":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983"
- integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==
- dependencies:
- graceful-fs "4.2.10"
+"@scure/base@~1.2.2", "@scure/base@~1.2.4":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.4.tgz#002eb571a35d69bdb4c214d0995dff76a8dcd2a9"
+ integrity sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==
-"@pnpm/npm-conf@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.1.0.tgz#1bbecd961a1ea447f209556728e2dcadddb0bca6"
- integrity sha512-Oe6ntvgsMTE3hDIqy6sajqHF+MnzJrOF06qC2QSiUEybLL7cp6tjoKUa32gpd9+KPVl4QyMs3E3nsXrx/Vdnlw==
+"@scure/bip32@1.6.2", "@scure/bip32@^1.5.0":
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.2.tgz#093caa94961619927659ed0e711a6e4bf35bffd0"
+ integrity sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==
dependencies:
- "@pnpm/config.env-replace" "^1.0.0"
- "@pnpm/network.ca-file" "^1.0.1"
- config-chain "^1.1.11"
-
-"@scure/base@~1.1.0":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
- integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
+ "@noble/curves" "~1.8.1"
+ "@noble/hashes" "~1.7.1"
+ "@scure/base" "~1.2.2"
-"@scure/bip32@1.3.0":
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87"
- integrity sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==
+"@scure/bip39@1.5.4", "@scure/bip39@^1.4.0":
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.4.tgz#07fd920423aa671be4540d59bdd344cc1461db51"
+ integrity sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==
dependencies:
- "@noble/curves" "~1.0.0"
- "@noble/hashes" "~1.3.0"
- "@scure/base" "~1.1.0"
-
-"@scure/bip39@1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b"
- integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==
- dependencies:
- "@noble/hashes" "~1.3.0"
- "@scure/base" "~1.1.0"
-
-"@semantic-release/commit-analyzer@^10.0.0":
- version "10.0.1"
- resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-10.0.1.tgz#be6fcc1703459294c394ede41b37fd9a21d39807"
- integrity sha512-9ejHzTAijYs9z246sY/dKBatmOPcd0GQ7lH4MgLCkv1q4GCiDZRkjHJkaQZXZVaK7mJybS+sH3Ng6G8i3pYMGQ==
- dependencies:
- conventional-changelog-angular "^6.0.0"
- conventional-commits-filter "^3.0.0"
- conventional-commits-parser "^4.0.0"
- debug "^4.0.0"
- import-from "^4.0.0"
- lodash-es "^4.17.21"
- micromatch "^4.0.2"
-
-"@semantic-release/error@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-3.0.0.tgz#30a3b97bbb5844d695eb22f9d3aa40f6a92770c2"
- integrity sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==
-
-"@semantic-release/error@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-4.0.0.tgz#692810288239637f74396976a9340fbc0aa9f6f9"
- integrity sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==
-
-"@semantic-release/github@^9.0.0":
- version "9.0.3"
- resolved "https://registry.yarnpkg.com/@semantic-release/github/-/github-9.0.3.tgz#2559da9bcedeacb572f240469270a281c2a83615"
- integrity sha512-X6gq4USKVlCxPwIIyXb99jU7gwVWlnsKOevs+OyABRdoqc+OIRITbFmrrYU3eE1vGMGk+Qu/GAoLUQQQwC3YOA==
- dependencies:
- "@octokit/core" "^4.2.1"
- "@octokit/plugin-paginate-rest" "^7.0.0"
- "@octokit/plugin-retry" "^5.0.0"
- "@octokit/plugin-throttling" "^6.0.0"
- "@semantic-release/error" "^4.0.0"
- aggregate-error "^4.0.1"
- debug "^4.3.4"
- dir-glob "^3.0.1"
- globby "^13.1.4"
- http-proxy-agent "^7.0.0"
- https-proxy-agent "^7.0.0"
- issue-parser "^6.0.0"
- lodash-es "^4.17.21"
- mime "^3.0.0"
- p-filter "^3.0.0"
- url-join "^5.0.0"
-
-"@semantic-release/npm@^10.0.2":
- version "10.0.2"
- resolved "https://registry.yarnpkg.com/@semantic-release/npm/-/npm-10.0.2.tgz#2e3e79a3dae5a12c67e7c314904e536834a87304"
- integrity sha512-Mo0XoBza4pUapxiBhLLYXeSZ9tkuHDUd/WvMbpilwuPRfJDnQXMqx5tBVon8d2mBk8JXmXpqB+ExhlWJmVT40A==
- dependencies:
- "@semantic-release/error" "^3.0.0"
- aggregate-error "^4.0.1"
- execa "^7.0.0"
- fs-extra "^11.0.0"
- lodash-es "^4.17.21"
- nerf-dart "^1.0.0"
- normalize-url "^8.0.0"
- npm "^9.5.0"
- rc "^1.2.8"
- read-pkg "^7.0.0"
- registry-auth-token "^5.0.0"
- semver "^7.1.2"
- tempy "^3.0.0"
-
-"@semantic-release/release-notes-generator@^11.0.0":
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-11.0.1.tgz#38a7d66e9a762915bea36a006dbb2d41fbcb4a66"
- integrity sha512-4deWsiY4Rg80oc9Ms11N20BIDgYkPMys4scNYQpi2Njdrtw5Z55nXKNsUN3kn6Sy/nI9dqqbp5L63TL4luI5Bw==
- dependencies:
- conventional-changelog-angular "^5.0.0"
- conventional-changelog-writer "^5.0.0"
- conventional-commits-filter "^2.0.0"
- conventional-commits-parser "^3.2.3"
- debug "^4.0.0"
- get-stream "^6.0.0"
- import-from "^4.0.0"
- into-stream "^7.0.0"
- lodash-es "^4.17.21"
- read-pkg-up "^9.0.0"
-
-"@sigstore/protobuf-specs@^0.1.0":
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz#957cb64ea2f5ce527cc9cf02a096baeb0d2b99b4"
- integrity sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==
+ "@noble/hashes" "~1.7.1"
+ "@scure/base" "~1.2.4"
"@sinclair/typebox@^0.27.8":
version "0.27.8"
@@ -1113,13 +941,6 @@
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
-"@tufjs/models@1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-1.0.1.tgz#cc8bb0478188b4b6e58d5528668212724aac87ac"
- integrity sha512-AY0VoG/AXdlSOocuREfPoEW4SNhOPp/7fw6mpAxfVIny1uZ+0fEtMoCi7NhELSlqQIRLMu7RgfKhkxT+AJ+EXg==
- dependencies:
- minimatch "^7.4.2"
-
"@types/babel__core@^7.1.14":
version "7.1.19"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
@@ -1153,6 +974,21 @@
dependencies:
"@babel/types" "^7.3.0"
+"@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/bunyan@^1.8.11":
+ version "1.8.11"
+ resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.11.tgz#0b9e7578a5aa2390faf12a460827154902299638"
+ integrity sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==
+ dependencies:
+ "@types/node" "*"
+
"@types/cacheable-request@^6.0.1":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
@@ -1163,6 +999,62 @@
"@types/node" "*"
"@types/responselike" "^1.0.0"
+"@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/cookie@^0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
+ integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
+
+"@types/cookiejar@^2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78"
+ integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==
+
+"@types/cors@^2.8.17":
+ version "2.8.17"
+ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b"
+ integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/debug@^4.1.7":
+ version "4.1.8"
+ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317"
+ integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==
+ dependencies:
+ "@types/ms" "*"
+
+"@types/express-serve-static-core@^4.17.33":
+ version "4.19.6"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267"
+ integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express@^4.17.21":
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
+ integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.33"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/fast-redact@^3.0.4":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/fast-redact/-/fast-redact-3.0.4.tgz#7f7cdf30efd02ae6f9360f3361ee9a7a8b9a748d"
+ integrity sha512-tgGJaXucrCH4Yx2l/AI6e/JQksZhKGIQsVwBMTh+nxUhQDv5tXScTs5DHTw+qSKDXnHL2dTAh1e2rd5pcFQyNQ==
+
"@types/glob@~7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
@@ -1183,6 +1075,11 @@
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
+"@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/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
@@ -1202,18 +1099,28 @@
dependencies:
"@types/istanbul-lib-report" "*"
-"@types/jest@^29.5.2":
- version "29.5.2"
- resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.2.tgz#86b4afc86e3a8f3005b297ed8a72494f89e6395b"
- integrity sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==
+"@types/jest@^29.5.14":
+ version "29.5.14"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5"
+ integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==
dependencies:
expect "^29.0.0"
pretty-format "^29.0.0"
+"@types/js-levenshtein@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz#ba05426a43f9e4e30b631941e0aa17bf0c890ed5"
+ integrity sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==
+
+"@types/js-yaml@^4.0.9":
+ version "4.0.9"
+ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
+ integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==
+
"@types/json-schema@^7.0.9":
- version "7.0.11"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
- integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/json5@^0.0.29":
version "0.0.29"
@@ -1227,30 +1134,55 @@
dependencies:
"@types/node" "*"
+"@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/methods@^1.1.4":
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547"
+ integrity sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==
+
+"@types/mime@*", "@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@*":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
- integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
-"@types/minimist@^1.2.0":
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
- integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
+"@types/ms@*":
+ version "0.7.31"
+ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
+ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
-"@types/node@*":
- version "12.20.55"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
- integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
+"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
+ version "20.3.3"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.3.tgz#329842940042d2b280897150e023e604d11657d6"
+ integrity sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==
-"@types/normalize-package-data@^2.4.0", "@types/normalize-package-data@^2.4.1":
+"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
-"@types/prettier@^2.1.5":
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a"
- integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==
+"@types/qrcode-terminal@^0.12.2":
+ version "0.12.2"
+ resolved "https://registry.yarnpkg.com/@types/qrcode-terminal/-/qrcode-terminal-0.12.2.tgz#8d7de3aa41f2d3c724bbc74a157ef3209abf8c75"
+ integrity sha512-v+RcIEJ+Uhd6ygSQ0u5YYY7ZM+la7GgPbs0V/7l/kFs2uO4S8BcIUEMoP7za4DNIqNnUD5npf0A/7kBhrCKG5Q==
+
+"@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/responselike@^1.0.0":
version "1.0.0"
@@ -1260,14 +1192,38 @@
"@types/node" "*"
"@types/semver@^7.3.12":
- version "7.3.12"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c"
- integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==
+ version "7.5.8"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
+ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+
+"@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/shelljs@^0.8.12":
- version "0.8.12"
- resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.12.tgz#79dc9632af7d5ca1b5afb65a6bfc1422d79b5fa0"
- integrity sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==
+"@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/set-cookie-parser@^2.4.0":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@types/set-cookie-parser/-/set-cookie-parser-2.4.3.tgz#963a7437ed026c6adec2a71478ed6e3df2837160"
+ integrity sha512-7QhnH7bi+6KAhBB+Auejz1uV9DHiopZqu7LfR/5gZZTkejJV5nYeZZpgfFoE0N8aDsXuiYpfKyfyMatCwQhyTQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/shelljs@^0.8.15":
+ version "0.8.15"
+ resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.15.tgz#22c6ab9dfe05cec57d8e6cb1a95ea173aee9fcac"
+ integrity sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==
dependencies:
"@types/glob" "~7.2.0"
"@types/node" "*"
@@ -1277,6 +1233,23 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
+"@types/superagent@^8.1.0":
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.1.tgz#dbc620c5df3770b0c3092f947d6d5e808adae2bc"
+ integrity sha512-YQyEXA4PgCl7EVOoSAS3o0fyPFU6erv5mMixztQYe1bqbWmmn8c+IrqoxjQeZe4MgwXikgcaZPiI/DsbmOVlzA==
+ dependencies:
+ "@types/cookiejar" "^2.1.5"
+ "@types/methods" "^1.1.4"
+ "@types/node" "*"
+
+"@types/supertest@^6.0.3":
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-6.0.3.tgz#d736f0e994b195b63e1c93e80271a2faf927388c"
+ integrity sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==
+ dependencies:
+ "@types/methods" "^1.1.4"
+ "@types/superagent" "^8.1.0"
+
"@types/yargs-parser@*":
version "21.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
@@ -1289,163 +1262,221 @@
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@^5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz#a1a5290cf33863b4db3fb79350b3c5275a7b1223"
- integrity sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==
+"@typescript-eslint/eslint-plugin@^7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3"
+ integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==
+ dependencies:
+ "@eslint-community/regexpp" "^4.10.0"
+ "@typescript-eslint/scope-manager" "7.18.0"
+ "@typescript-eslint/type-utils" "7.18.0"
+ "@typescript-eslint/utils" "7.18.0"
+ "@typescript-eslint/visitor-keys" "7.18.0"
+ graphemer "^1.4.0"
+ ignore "^5.3.1"
+ natural-compare "^1.4.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/parser@^8.24.0":
+ version "8.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.24.0.tgz#bba837f9ee125b78f459ad947ff9b61be8139085"
+ integrity sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==
dependencies:
- "@eslint-community/regexpp" "^4.4.0"
- "@typescript-eslint/scope-manager" "5.61.0"
- "@typescript-eslint/type-utils" "5.61.0"
- "@typescript-eslint/utils" "5.61.0"
+ "@typescript-eslint/scope-manager" "8.24.0"
+ "@typescript-eslint/types" "8.24.0"
+ "@typescript-eslint/typescript-estree" "8.24.0"
+ "@typescript-eslint/visitor-keys" "8.24.0"
debug "^4.3.4"
- graphemer "^1.4.0"
- ignore "^5.2.0"
- natural-compare-lite "^1.4.0"
- semver "^7.3.7"
- tsutils "^3.21.0"
-"@typescript-eslint/parser@^4.25.0":
- version "4.33.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899"
- integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==
+"@typescript-eslint/scope-manager@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
+ integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
dependencies:
- "@typescript-eslint/scope-manager" "4.33.0"
- "@typescript-eslint/types" "4.33.0"
- "@typescript-eslint/typescript-estree" "4.33.0"
- debug "^4.3.1"
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/visitor-keys" "5.62.0"
-"@typescript-eslint/scope-manager@4.33.0":
- version "4.33.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3"
- integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==
+"@typescript-eslint/scope-manager@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83"
+ integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==
dependencies:
- "@typescript-eslint/types" "4.33.0"
- "@typescript-eslint/visitor-keys" "4.33.0"
+ "@typescript-eslint/types" "7.18.0"
+ "@typescript-eslint/visitor-keys" "7.18.0"
-"@typescript-eslint/scope-manager@5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz#b670006d069c9abe6415c41f754b1b5d949ef2b2"
- integrity sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==
+"@typescript-eslint/scope-manager@8.24.0":
+ version "8.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz#2e34b3eb2ce768f2ffb109474174ced5417002b1"
+ integrity sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==
dependencies:
- "@typescript-eslint/types" "5.61.0"
- "@typescript-eslint/visitor-keys" "5.61.0"
+ "@typescript-eslint/types" "8.24.0"
+ "@typescript-eslint/visitor-keys" "8.24.0"
-"@typescript-eslint/type-utils@5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.61.0.tgz#e90799eb2045c4435ea8378cb31cd8a9fddca47a"
- integrity sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==
+"@typescript-eslint/type-utils@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b"
+ integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==
dependencies:
- "@typescript-eslint/typescript-estree" "5.61.0"
- "@typescript-eslint/utils" "5.61.0"
+ "@typescript-eslint/typescript-estree" "7.18.0"
+ "@typescript-eslint/utils" "7.18.0"
debug "^4.3.4"
- tsutils "^3.21.0"
+ ts-api-utils "^1.3.0"
-"@typescript-eslint/types@4.33.0":
- version "4.33.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72"
- integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==
+"@typescript-eslint/types@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
+ integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
-"@typescript-eslint/types@5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.61.0.tgz#e99ff11b5792d791554abab0f0370936d8ca50c0"
- integrity sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==
+"@typescript-eslint/types@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9"
+ integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==
-"@typescript-eslint/typescript-estree@4.33.0":
- version "4.33.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609"
- integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==
- dependencies:
- "@typescript-eslint/types" "4.33.0"
- "@typescript-eslint/visitor-keys" "4.33.0"
- debug "^4.3.1"
- globby "^11.0.3"
- is-glob "^4.0.1"
- semver "^7.3.5"
- tsutils "^3.21.0"
+"@typescript-eslint/types@8.24.0":
+ version "8.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.24.0.tgz#694e7fb18d70506c317b816de9521300b0f72c8e"
+ integrity sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==
-"@typescript-eslint/typescript-estree@5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz#4c7caca84ce95bb41aa585d46a764bcc050b92f3"
- integrity sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==
+"@typescript-eslint/typescript-estree@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
+ integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
dependencies:
- "@typescript-eslint/types" "5.61.0"
- "@typescript-eslint/visitor-keys" "5.61.0"
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/visitor-keys" "5.62.0"
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.61.0", "@typescript-eslint/utils@^5.10.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.61.0.tgz#5064838a53e91c754fffbddd306adcca3fe0af36"
- integrity sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==
+"@typescript-eslint/typescript-estree@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931"
+ integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==
+ dependencies:
+ "@typescript-eslint/types" "7.18.0"
+ "@typescript-eslint/visitor-keys" "7.18.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ minimatch "^9.0.4"
+ semver "^7.6.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/typescript-estree@8.24.0":
+ version "8.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz#0487349be174097bb329a58273100a9629e03c6c"
+ integrity sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==
+ dependencies:
+ "@typescript-eslint/types" "8.24.0"
+ "@typescript-eslint/visitor-keys" "8.24.0"
+ debug "^4.3.4"
+ fast-glob "^3.3.2"
+ is-glob "^4.0.3"
+ minimatch "^9.0.4"
+ semver "^7.6.0"
+ ts-api-utils "^2.0.1"
+
+"@typescript-eslint/utils@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f"
+ integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@typescript-eslint/scope-manager" "7.18.0"
+ "@typescript-eslint/types" "7.18.0"
+ "@typescript-eslint/typescript-estree" "7.18.0"
+
+"@typescript-eslint/utils@^5.10.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
+ integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
- "@typescript-eslint/scope-manager" "5.61.0"
- "@typescript-eslint/types" "5.61.0"
- "@typescript-eslint/typescript-estree" "5.61.0"
+ "@typescript-eslint/scope-manager" "5.62.0"
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/typescript-estree" "5.62.0"
eslint-scope "^5.1.1"
semver "^7.3.7"
-"@typescript-eslint/visitor-keys@4.33.0":
- version "4.33.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd"
- integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==
+"@typescript-eslint/visitor-keys@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
+ integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
dependencies:
- "@typescript-eslint/types" "4.33.0"
- eslint-visitor-keys "^2.0.0"
+ "@typescript-eslint/types" "5.62.0"
+ eslint-visitor-keys "^3.3.0"
-"@typescript-eslint/visitor-keys@5.61.0":
- version "5.61.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz#c79414fa42158fd23bd2bb70952dc5cdbb298140"
- integrity sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==
+"@typescript-eslint/visitor-keys@7.18.0":
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7"
+ integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==
dependencies:
- "@typescript-eslint/types" "5.61.0"
- eslint-visitor-keys "^3.3.0"
+ "@typescript-eslint/types" "7.18.0"
+ eslint-visitor-keys "^3.4.3"
-"@valora/eslint-config-typescript@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@valora/eslint-config-typescript/-/eslint-config-typescript-1.0.1.tgz#99524730423f1cd125a94ee50539e3aa3d4b9e7c"
- integrity sha512-8sF+XoEB/tQXpy5M94Je+R+aL1DGFyGHD/Fn1hz4ZbGvG4gaQnrWa9fsAeQbSqF/Rn93RZKJeEgLQysuIU1wxg==
+"@typescript-eslint/visitor-keys@8.24.0":
+ version "8.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz#36ecf0b9b1d819ad88a3bd4157ab7d594cb797c9"
+ integrity sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==
+ dependencies:
+ "@typescript-eslint/types" "8.24.0"
+ eslint-visitor-keys "^4.2.0"
+
+"@ungap/structured-clone@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
+ integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
+
+"@valora/eslint-config-typescript@^1.1.9":
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/@valora/eslint-config-typescript/-/eslint-config-typescript-1.1.9.tgz#1d0911017041a14cb7dacceb721e5d930176bb89"
+ integrity sha512-dA7Dio/B/QexbhqSYionoDtTvLrzopHTWvJeQvEvRv3DhR/v1M99a5tA8AxNuIuivfI0l4VVfgWsJw6qZwvW/g==
+ dependencies:
+ "@typescript-eslint/parser" "^8.24.0"
+
+"@valora/http-handler@^0.0.1":
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/@valora/http-handler/-/http-handler-0.0.1.tgz#9221dbc51ac783fc31c5f535f9a00346742fff86"
+ integrity sha512-p2DhGqLoGRH7pvmgu2AJMfTUFqsShjOw+vIpxGsawzC061Jm5smvelahVkX3jYpUbYKRr1zWWg50S46i/c1Ssg==
+ dependencies:
+ "@google-cloud/functions-framework" "^3.1.3"
+
+"@valora/logging@^1.3.18":
+ version "1.3.18"
+ resolved "https://registry.yarnpkg.com/@valora/logging/-/logging-1.3.18.tgz#075fbfc7bbf33e63d9c1b92bc1fa96c01daf8f29"
+ integrity sha512-+NUo6ZEeEeeolP+QdPp5OS4evOp6s4b7uMBfwkFRvvAysd++315wfnG5N2Ib+C8zr9r17gc7ryOHcCJFMI13Dg==
dependencies:
- "@typescript-eslint/parser" "^4.25.0"
+ "@google-cloud/logging" "^11.2.0"
+ "@google-cloud/logging-bunyan" "^5.1.0"
+ "@types/bunyan" "^1.8.11"
+ "@types/fast-redact" "^3.0.4"
+ bunyan "^1.8.15"
+ bunyan-prettystream "^0.1.3"
+ fast-redact "^3.5.0"
"@valora/prettier-config@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@valora/prettier-config/-/prettier-config-0.0.1.tgz#5c739ce07c4d2d8b320c7b49366efa80ac98a655"
integrity sha512-wg05yCU8Ext1jr8LEEs7dm2KakYbyg3rPxoD7ASSfGycP7HlkIfMJW6NzLTFko3CmkaFxeeydpFbgVOe36cnig==
-"@wagmi/chains@1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.2.0.tgz#d59eaa70ec51a5fdcd113975926992acfb17ab12"
- integrity sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ==
-
-JSONStream@^1.0.4, JSONStream@^1.3.5:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
- integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
- dependencies:
- jsonparse "^1.2.0"
- through ">=2.2.7 <3"
+"@xmldom/xmldom@^0.8.3":
+ version "0.8.9"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.9.tgz#b6ef7457e826be8049667ae673eda7876eb049be"
+ integrity sha512-4VSbbcMoxc4KLjb1gs96SRmi7w4h1SF+fCoiK0XaQX62buCc1G5d0DC5bJ9xJBNPDSVCmIrcl8BiYxzjrqaaJA==
-abbrev@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
- integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
-
-abbrev@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
- integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
+"@zxing/text-encoding@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
+ integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
-abitype@0.8.11:
- version "0.8.11"
- resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.11.tgz#66e1cf2cbf46f48d0e57132d7c1c392447536cc1"
- integrity sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A==
+abitype@1.0.8, abitype@^1.0.6:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba"
+ integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==
abort-controller@^3.0.0:
version "3.0.0"
@@ -1454,6 +1485,22 @@ abort-controller@^3.0.0:
dependencies:
event-target-shim "^5.0.0"
+accepts@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895"
+ integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==
+ dependencies:
+ mime-types "^3.0.0"
+ negotiator "^1.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"
@@ -1469,46 +1516,28 @@ acorn@^8.4.1, acorn@^8.9.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
-agent-base@6, agent-base@^6.0.2:
+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"
-agent-base@^7.0.2, agent-base@^7.1.0:
+agent-base@^7.0.2:
version "7.1.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434"
integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==
dependencies:
debug "^4.3.4"
-agentkeepalive@^4.2.1:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255"
- integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==
- dependencies:
- debug "^4.1.0"
- depd "^2.0.0"
- humanize-ms "^1.2.1"
-
-aggregate-error@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
- integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
- dependencies:
- clean-stack "^2.0.0"
- indent-string "^4.0.0"
-
-aggregate-error@^4.0.0, aggregate-error@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-4.0.1.tgz#25091fe1573b9e0be892aeda15c7c66a545f758e"
- integrity sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==
+ajv-formats@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
dependencies:
- clean-stack "^4.0.0"
- indent-string "^5.0.0"
+ ajv "^8.0.0"
-ajv@^6.10.0, ajv@^6.12.4:
+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==
@@ -1518,6 +1547,16 @@ ajv@^6.10.0, ajv@^6.12.4:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ajv@^8.0.0, ajv@^8.11.0:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
+ integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
ansi-escapes@^4.2.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@@ -1525,13 +1564,6 @@ ansi-escapes@^4.2.1:
dependencies:
type-fest "^0.21.3"
-ansi-escapes@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6"
- integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==
- dependencies:
- type-fest "^1.0.2"
-
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
@@ -1544,7 +1576,7 @@ ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
-ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.3.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==
@@ -1556,45 +1588,14 @@ ansi-styles@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
-ansicolors@~0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
- integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==
-
-anymatch@^3.0.3:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
- integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+anymatch@^3.0.3, 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"
-"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
- integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
-
-archy@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
- integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==
-
-are-we-there-yet@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd"
- integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^3.6.0"
-
-are-we-there-yet@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-4.0.0.tgz#3ff397dc14f08b52dd8b2a64d3cee154ab8760d2"
- integrity sha512-nSXlV+u3vtVjRgihdTzbfWYzxPWGo424zPgQbHD0ZqIla3jqYAewDcvee0Ua2hjS5IfTAmjGlx1Jf0PKwjZDEw==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^4.1.0"
-
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
@@ -1612,25 +1613,34 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-argv-formatter@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9"
- integrity sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==
+array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b"
+ integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==
+ dependencies:
+ call-bound "^1.0.3"
+ is-array-buffer "^3.0.5"
+
+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-ify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece"
integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==
-array-includes@^3.1.4, array-includes@^3.1.6:
- version "3.1.6"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f"
- integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==
+array-includes@^3.1.4, array-includes@^3.1.8:
+ version "3.1.8"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d"
+ integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
- get-intrinsic "^1.1.3"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.4"
is-string "^1.0.7"
array-union@^2.1.0:
@@ -1638,51 +1648,110 @@ array-union@^2.1.0:
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-array.prototype.flat@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2"
- integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==
+array.prototype.findlast@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904"
+ integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.findlastindex@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
+ integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.flat@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18"
+ integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ define-properties "^1.2.0"
+ es-abstract "^1.22.1"
es-shim-unscopables "^1.0.0"
-array.prototype.flatmap@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183"
- integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==
+array.prototype.flatmap@^1.3.2, array.prototype.flatmap@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b"
+ integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
- es-shim-unscopables "^1.0.0"
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-shim-unscopables "^1.0.2"
-array.prototype.tosorted@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532"
- integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==
+array.prototype.tosorted@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc"
+ integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
- es-shim-unscopables "^1.0.0"
- get-intrinsic "^1.1.3"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.3"
+ es-errors "^1.3.0"
+ es-shim-unscopables "^1.0.2"
-arrify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
- integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
+arraybuffer.prototype.slice@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c"
+ integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==
+ dependencies:
+ array-buffer-byte-length "^1.0.1"
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ is-array-buffer "^3.0.4"
+
+arrify@^2.0.0, arrify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
+asap@^2.0.0:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
+
+async@^3.2.3:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
+ integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
+
+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==
+
+available-typed-arrays@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
+ integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
+ dependencies:
+ possible-typed-array-names "^1.0.0"
-babel-jest@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.1.tgz#a7141ad1ed5ec50238f3cd36127636823111233a"
- integrity sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A==
+babel-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
+ integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==
dependencies:
- "@jest/transform" "^29.6.1"
+ "@jest/transform" "^29.7.0"
"@types/babel__core" "^7.1.14"
babel-plugin-istanbul "^6.1.1"
- babel-preset-jest "^29.5.0"
+ babel-preset-jest "^29.6.3"
chalk "^4.0.0"
graceful-fs "^4.2.9"
slash "^3.0.0"
@@ -1698,10 +1767,10 @@ babel-plugin-istanbul@^6.1.1:
istanbul-lib-instrument "^5.0.4"
test-exclude "^6.0.0"
-babel-plugin-jest-hoist@^29.5.0:
- version "29.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a"
- integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==
+babel-plugin-jest-hoist@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626"
+ integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==
dependencies:
"@babel/template" "^7.3.3"
"@babel/types" "^7.3.3"
@@ -1726,12 +1795,12 @@ babel-preset-current-node-syntax@^1.0.0:
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
"@babel/plugin-syntax-top-level-await" "^7.8.3"
-babel-preset-jest@^29.5.0:
- version "29.5.0"
- resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2"
- integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==
+babel-preset-jest@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c"
+ integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==
dependencies:
- babel-plugin-jest-hoist "^29.5.0"
+ babel-plugin-jest-hoist "^29.6.3"
babel-preset-current-node-syntax "^1.0.0"
balanced-match@^1.0.0:
@@ -1739,40 +1808,62 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-js@^1.3.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==
-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.1.1:
- version "9.1.1"
- resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6"
- integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==
-
-bin-links@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.1.tgz#afeb0549e642f61ff889b58ea2f8dca78fb9d8d3"
- integrity sha512-bmFEM39CyX336ZGGRsGPlc6jZHriIoHacOQcTt72MktIjpPhZoP4te2jOyUXF3BLILmJ8aNLncoPVeIIFlrDeA==
- dependencies:
- cmd-shim "^6.0.0"
- npm-normalize-package-bin "^3.0.0"
- read-cmd-shim "^4.0.0"
- write-file-atomic "^5.0.0"
+bignumber.js@^9.0.0, bignumber.js@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.2.0.tgz#273a03ba2dd44bb29ffff91a1097d9e952d2680d"
+ integrity sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==
-binary-extensions@^2.2.0:
+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==
-bottleneck@^2.15.3:
- version "2.19.5"
- resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91"
- integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==
+bl@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+ dependencies:
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
+
+body-parser@1.20.3, body-parser@^1.18.3:
+ version "1.20.3"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
+ integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.5"
+ 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.13.0"
+ raw-body "2.5.2"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+body-parser@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa"
+ integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==
+ dependencies:
+ bytes "^3.1.2"
+ content-type "^1.0.5"
+ debug "^4.4.0"
+ http-errors "^2.0.0"
+ iconv-lite "^0.6.3"
+ on-finished "^2.4.1"
+ qs "^6.14.0"
+ raw-body "^3.0.0"
+ type-is "^2.0.0"
brace-expansion@^1.1.7:
version "1.1.11"
@@ -1789,12 +1880,12 @@ brace-expansion@^2.0.1:
dependencies:
balanced-match "^1.0.0"
-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==
+braces@^3.0.3, braces@~3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
- fill-range "^7.0.1"
+ fill-range "^7.1.1"
browserslist@^4.20.2:
version "4.20.4"
@@ -1807,7 +1898,7 @@ browserslist@^4.20.2:
node-releases "^2.0.5"
picocolors "^1.0.0"
-bs-logger@0.x:
+bs-logger@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==
@@ -1821,68 +1912,43 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
+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-from@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-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==
+buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
base64-js "^1.3.1"
- ieee754 "^1.2.1"
+ ieee754 "^1.1.13"
-builtins@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9"
- integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==
- dependencies:
- semver "^7.0.0"
-
-cacache@^16.1.0:
- version "16.1.3"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e"
- integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==
- dependencies:
- "@npmcli/fs" "^2.1.0"
- "@npmcli/move-file" "^2.0.0"
- chownr "^2.0.0"
- fs-minipass "^2.1.0"
- glob "^8.0.1"
- infer-owner "^1.0.4"
- lru-cache "^7.7.1"
- minipass "^3.1.6"
- minipass-collect "^1.0.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.4"
- mkdirp "^1.0.4"
- p-map "^4.0.0"
- promise-inflight "^1.0.1"
- rimraf "^3.0.2"
- ssri "^9.0.0"
- tar "^6.1.11"
- unique-filename "^2.0.0"
-
-cacache@^17.0.0, cacache@^17.0.4:
- version "17.0.5"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.5.tgz#6dbec26c11f1f6a2b558bc11ed3316577c339ebc"
- integrity sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==
- dependencies:
- "@npmcli/fs" "^3.1.0"
- fs-minipass "^3.0.0"
- glob "^9.3.1"
- lru-cache "^7.7.1"
- minipass "^4.0.0"
- minipass-collect "^1.0.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.4"
- p-map "^4.0.0"
- promise-inflight "^1.0.1"
- ssri "^10.0.0"
- tar "^6.1.11"
- unique-filename "^3.0.0"
+bunyan-prettystream@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/bunyan-prettystream/-/bunyan-prettystream-0.1.3.tgz#6c3b713266f6ad32007c7b6ab1e998a245349d98"
+ integrity sha512-ovZoJY65kWByTUEDu1gMB89t+NGV9Ixm7azEhp2zXiGfSTvPGlu8+HFiVp6XuEQw0P6OS0oyi/Za6gknsl8Bwg==
+
+bunyan@^1.8.15:
+ version "1.8.15"
+ resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46"
+ integrity sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==
+ optionalDependencies:
+ dtrace-provider "~0.8"
+ moment "^2.19.3"
+ mv "~2"
+ safe-json-stringify "~1"
+
+bytes@3.1.2, bytes@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
cacheable-lookup@^5.0.3:
version "5.0.4"
@@ -1902,28 +1968,37 @@ cacheable-request@^7.0.2:
normalize-url "^6.0.1"
responselike "^2.0.0"
-call-bind@^1.0.0, call-bind@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840"
+ integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+
+call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
+ integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
+ dependencies:
+ call-bind-apply-helpers "^1.0.0"
+ es-define-property "^1.0.0"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.2"
+
+call-bound@^1.0.2, call-bound@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681"
+ integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==
dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
+ call-bind-apply-helpers "^1.0.1"
+ get-intrinsic "^1.2.6"
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-keys@^6.2.2:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
- integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
- dependencies:
- camelcase "^5.3.1"
- map-obj "^4.0.0"
- quick-lru "^4.0.1"
-
camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
@@ -1939,15 +2014,7 @@ caniuse-lite@^1.0.30001349:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001355.tgz#e240b7177443ed0198c737a7f609536976701c77"
integrity sha512-Sd6pjJHF27LzCB7pT7qs+kuX2ndurzCzkpJl6Qct7LPSZ9jn0bkOA8mdgMgmqnQAWLVOOGjLpc+66V57eLtb1g==
-cardinal@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505"
- integrity sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==
- dependencies:
- ansicolors "~0.3.2"
- redeyed "~2.1.0"
-
-chalk@^2.0.0, chalk@^2.3.2:
+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==
@@ -1956,7 +2023,7 @@ chalk@^2.0.0, chalk@^2.3.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
+chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -1964,66 +2031,57 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-chalk@^5.0.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3"
- integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==
-
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
-chownr@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
- integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+chokidar@^3.4.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"
-ci-info@^3.2.0, ci-info@^3.6.1, ci-info@^3.7.1, ci-info@^3.8.0:
+ci-info@^3.2.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
-cidr-regex@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-3.1.1.tgz#ba1972c57c66f61875f18fd7dd487469770b571d"
- integrity sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw==
- dependencies:
- ip-regex "^4.1.0"
-
cjs-module-lexer@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
-clean-stack@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-4.2.0.tgz#c464e4cde4ac789f4e0735c5d75beb49d7b30b31"
- integrity sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
dependencies:
- escape-string-regexp "5.0.0"
+ restore-cursor "^3.1.0"
-cli-columns@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-4.0.0.tgz#9fe4d65975238d55218c41bd2ed296a7fa555646"
- integrity sha512-XW2Vg+w+L9on9wtwKpyzluIPCWXjaBahI7mTcYjx+BVIYD9c3yqcv/yKC7CmdCZat4rq2yiE1UMSJC5ivKfMtQ==
- dependencies:
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
+cli-spinners@^2.5.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db"
+ integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==
-cli-table3@^0.6.1, cli-table3@^0.6.3:
- version "0.6.3"
- resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2"
- integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==
- dependencies:
- string-width "^4.2.0"
- optionalDependencies:
- "@colors/colors" "1.5.0"
+cli-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
cliui@^8.0.1:
version "8.0.1"
@@ -2046,10 +2104,17 @@ clone@^1.0.2:
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
-cmd-shim@^6.0.0:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d"
- integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==
+cloudevents@^8.0.2:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/cloudevents/-/cloudevents-8.0.2.tgz#034bde4e1a0ee21a8a34b8fe837e7d98c8bbdf8d"
+ integrity sha512-93KKRR61D2NNE+2lg2HmLbl17beVTKpf1UYd/8BcXpuiDxbU2fb8gAfriSmVGmj1xX/Oh2t5Fh/xGOWFdu6F4A==
+ dependencies:
+ ajv "^8.11.0"
+ ajv-formats "^2.1.1"
+ json-bigint "^1.0.0"
+ process "^0.11.10"
+ util "^0.12.4"
+ uuid "^8.3.2"
co@^4.6.0:
version "4.6.0"
@@ -2085,23 +2150,12 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-color-support@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
- integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
-
-columnify@^1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3"
- integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==
+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:
- strip-ansi "^6.0.1"
- wcwidth "^1.0.0"
-
-common-ancestor-path@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7"
- integrity sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==
+ delayed-stream "~1.0.0"
compare-func@^2.0.0:
version "2.0.0"
@@ -2111,38 +2165,34 @@ compare-func@^2.0.0:
array-ify "^1.0.0"
dot-prop "^5.1.0"
+component-emitter@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
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==
-config-chain@^1.1.11:
- version "1.1.13"
- resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
- integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
+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:
- ini "^1.3.4"
- proto-list "~1.2.1"
+ safe-buffer "5.2.1"
-console-control-strings@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
- integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
-
-conventional-changelog-angular@^5.0.0:
- version "5.0.13"
- resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c"
- integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==
+content-disposition@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2"
+ integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==
dependencies:
- compare-func "^2.0.0"
- q "^1.5.1"
+ safe-buffer "5.2.1"
-conventional-changelog-angular@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz#a9a9494c28b7165889144fd5b91573c4aa9ca541"
- integrity sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==
- dependencies:
- compare-func "^2.0.0"
+content-type@^1.0.5, content-type@~1.0.4, content-type@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
conventional-changelog-conventionalcommits@^6.1.0:
version "6.1.0"
@@ -2151,59 +2201,6 @@ conventional-changelog-conventionalcommits@^6.1.0:
dependencies:
compare-func "^2.0.0"
-conventional-changelog-writer@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz#e0757072f045fe03d91da6343c843029e702f359"
- integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==
- dependencies:
- conventional-commits-filter "^2.0.7"
- dateformat "^3.0.0"
- handlebars "^4.7.7"
- json-stringify-safe "^5.0.1"
- lodash "^4.17.15"
- meow "^8.0.0"
- semver "^6.0.0"
- split "^1.0.0"
- through2 "^4.0.0"
-
-conventional-commits-filter@^2.0.0, conventional-commits-filter@^2.0.7:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3"
- integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==
- dependencies:
- lodash.ismatch "^4.4.0"
- modify-values "^1.0.0"
-
-conventional-commits-filter@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz#bf1113266151dd64c49cd269e3eb7d71d7015ee2"
- integrity sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==
- dependencies:
- lodash.ismatch "^4.4.0"
- modify-values "^1.0.1"
-
-conventional-commits-parser@^3.2.3:
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz#a7d3b77758a202a9b2293d2112a8d8052c740972"
- integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==
- dependencies:
- JSONStream "^1.0.4"
- is-text-path "^1.0.1"
- lodash "^4.17.15"
- meow "^8.0.0"
- split2 "^3.0.0"
- through2 "^4.0.0"
-
-conventional-commits-parser@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz#02ae1178a381304839bce7cea9da5f1b549ae505"
- integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==
- dependencies:
- JSONStream "^1.3.5"
- is-text-path "^1.0.1"
- meow "^8.1.2"
- split2 "^3.2.2"
-
convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
@@ -2216,20 +2213,51 @@ convert-source-map@^2.0.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
-core-util-is@~1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
- integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+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==
-cosmiconfig@^8.0.0:
- version "8.1.3"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689"
- integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==
- dependencies:
- import-fresh "^3.2.1"
- js-yaml "^4.1.0"
- parse-json "^5.0.0"
- path-type "^4.0.0"
+cookie-signature@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
+ integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
+
+cookie@0.7.1, cookie@^0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
+ integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
+
+cookie@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
+
+cookiejar@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
+ integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
+
+cors@^2.8.5:
+ version "2.8.5"
+ resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+ integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+ dependencies:
+ object-assign "^4"
+ vary "^1"
+
+create-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320"
+ integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ prompts "^2.0.1"
create-require@^1.1.0:
version "1.1.1"
@@ -2245,29 +2273,46 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
-crypto-random-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2"
- integrity sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==
+data-view-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570"
+ integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==
dependencies:
- type-fest "^1.0.1"
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.2"
-cssesc@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
- integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+data-view-byte-length@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735"
+ integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==
+ dependencies:
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.2"
-dateformat@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
- integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
+data-view-byte-offset@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191"
+ integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.1"
+
+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.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, 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==
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
+ integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
dependencies:
- ms "2.1.2"
+ ms "^2.1.3"
debug@^3.2.7:
version "3.2.7"
@@ -2276,19 +2321,6 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
-decamelize-keys@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8"
- integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==
- dependencies:
- decamelize "^1.1.0"
- map-obj "^1.0.0"
-
-decamelize@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
-
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
@@ -2296,15 +2328,10 @@ decompress-response@^6.0.0:
dependencies:
mimic-response "^3.1.0"
-dedent@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
- integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==
-
-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==
+dedent@^1.0.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.0.tgz#6e0fb8016002deba2d56927ebd7e3caf7e84e22a"
+ integrity sha512-3sSQTYoWKGcRHmHl6Y6opLpRJH55bxeGQ0Y1LCI5pZzUXvokVkj0FC4bi7uEwazxA9FQZ0Nv067Zt5kSUvXxEA==
deep-is@^0.1.3:
version "0.1.4"
@@ -2316,6 +2343,13 @@ deepmerge@^4.2.2:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
+default-gateway@^6.0.0:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
+ integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
+ dependencies:
+ execa "^5.0.0"
+
defaults@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a"
@@ -2328,49 +2362,62 @@ defer-to-connect@^2.0.0:
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
-define-properties@^1.1.3, define-properties@^1.1.4:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
- integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==
+define-data-property@^1.0.1, define-data-property@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
+define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
+ integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
dependencies:
+ define-data-property "^1.0.1"
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
-delegates@^1.0.0:
+delayed-stream@~1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
- integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
-depd@^2.0.0:
+depd@2.0.0, 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==
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
-diff-sequences@^29.4.3:
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
- integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
+dezalgo@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
+ integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
+ dependencies:
+ asap "^2.0.0"
+ wrappy "1"
+
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
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==
-diff@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
- integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
-
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -2399,12 +2446,67 @@ dot-prop@^5.1.0:
dependencies:
is-obj "^2.0.0"
-duplexer2@~0.1.0:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
- integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==
+dot-prop@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083"
+ integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==
+ dependencies:
+ is-obj "^2.0.0"
+
+dotenv@^16.4.7:
+ version "16.4.7"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
+ integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
+
+dtrace-provider@~0.8:
+ version "0.8.8"
+ resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.8.tgz#2996d5490c37e1347be263b423ed7b297fb0d97e"
+ integrity sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==
+ dependencies:
+ nan "^2.14.0"
+
+dunder-proto@^1.0.0, dunder-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
+ integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ es-errors "^1.3.0"
+ gopd "^1.2.0"
+
+duplexer@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
+ integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
+
+duplexify@^4.0.0, duplexify@^4.1.1:
+ 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==
+
+ejs@^3.1.10:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"
+ integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==
dependencies:
- readable-stream "^2.0.2"
+ jake "^10.8.5"
electron-to-chromium@^1.4.147:
version "1.4.158"
@@ -2421,100 +2523,163 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-encoding@^0.1.13:
- version "0.1.13"
- resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
- integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
- dependencies:
- iconv-lite "^0.6.2"
+encodeurl@^2.0.0, encodeurl@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
+ integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
-end-of-stream@^1.1.0:
+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.1.0, 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"
-env-ci@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/env-ci/-/env-ci-9.0.0.tgz#53df706b4b841f5f05413402ef82049eba8e4af3"
- integrity sha512-Q3cjr1tX9xwigprw4G8M3o7PIOO/1LYji6TyGsbD1WfMmD23etZvhgmPXJqkP788yH4dgSSK7oaIMuaayUJIfg==
- dependencies:
- execa "^7.0.0"
- java-properties "^1.0.2"
-
-env-paths@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
- integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
-
-err-code@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
- integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
+ent@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
+ integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==
-error-ex@^1.3.1, error-ex@^1.3.2:
+error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.19.0, es-abstract@^1.19.5, es-abstract@^1.20.4:
- version "1.20.4"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861"
- integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==
- dependencies:
- call-bind "^1.0.2"
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- function.prototype.name "^1.1.5"
- get-intrinsic "^1.1.3"
- get-symbol-description "^1.0.0"
- has "^1.0.3"
- has-property-descriptors "^1.0.0"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
+es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6:
+ version "1.23.8"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.8.tgz#99754723118355d82fcef9ce4c90ccbcd5d2a285"
+ integrity sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==
+ dependencies:
+ array-buffer-byte-length "^1.0.2"
+ arraybuffer.prototype.slice "^1.0.4"
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ data-view-buffer "^1.0.2"
+ data-view-byte-length "^1.0.2"
+ data-view-byte-offset "^1.0.1"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-set-tostringtag "^2.0.3"
+ es-to-primitive "^1.3.0"
+ function.prototype.name "^1.1.8"
+ get-intrinsic "^1.2.6"
+ get-symbol-description "^1.1.0"
+ globalthis "^1.0.4"
+ gopd "^1.2.0"
+ has-property-descriptors "^1.0.2"
+ has-proto "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ internal-slot "^1.1.0"
+ is-array-buffer "^3.0.5"
is-callable "^1.2.7"
- is-negative-zero "^2.0.2"
- is-regex "^1.1.4"
- is-shared-array-buffer "^1.0.2"
- is-string "^1.0.7"
- is-weakref "^1.0.2"
- object-inspect "^1.12.2"
+ is-data-view "^1.0.2"
+ is-regex "^1.2.1"
+ is-shared-array-buffer "^1.0.4"
+ is-string "^1.1.1"
+ is-typed-array "^1.1.15"
+ is-weakref "^1.1.0"
+ math-intrinsics "^1.1.0"
+ object-inspect "^1.13.3"
object-keys "^1.1.1"
- object.assign "^4.1.4"
- regexp.prototype.flags "^1.4.3"
- safe-regex-test "^1.0.0"
- string.prototype.trimend "^1.0.5"
- string.prototype.trimstart "^1.0.5"
- unbox-primitive "^1.0.2"
-
-es-shim-unscopables@^1.0.0:
+ object.assign "^4.1.7"
+ own-keys "^1.0.0"
+ regexp.prototype.flags "^1.5.3"
+ safe-array-concat "^1.1.3"
+ safe-push-apply "^1.0.0"
+ safe-regex-test "^1.1.0"
+ string.prototype.trim "^1.2.10"
+ string.prototype.trimend "^1.0.9"
+ string.prototype.trimstart "^1.0.8"
+ typed-array-buffer "^1.0.3"
+ typed-array-byte-length "^1.0.3"
+ typed-array-byte-offset "^1.0.4"
+ typed-array-length "^1.0.7"
+ unbox-primitive "^1.1.0"
+ which-typed-array "^1.1.18"
+
+es-define-property@^1.0.0, es-define-property@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
+ integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es-iterator-helpers@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75"
+ integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.6"
+ es-errors "^1.3.0"
+ es-set-tostringtag "^2.0.3"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.6"
+ globalthis "^1.0.4"
+ gopd "^1.2.0"
+ has-property-descriptors "^1.0.2"
+ has-proto "^1.2.0"
+ has-symbols "^1.1.0"
+ internal-slot "^1.1.0"
+ iterator.prototype "^1.1.4"
+ safe-array-concat "^1.1.3"
+
+es-object-atoms@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
- integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
+ resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941"
+ integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==
dependencies:
- has "^1.0.3"
+ es-errors "^1.3.0"
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+es-set-tostringtag@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
+ integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.1"
+
+es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763"
+ integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==
dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
+ hasown "^2.0.0"
+
+es-to-primitive@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18"
+ integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==
+ dependencies:
+ is-callable "^1.2.7"
+ is-date-object "^1.0.5"
+ is-symbol "^1.0.4"
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-escape-string-regexp@5.0.0, escape-string-regexp@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
- integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
+escape-html@^1.0.3, 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@^1.0.5:
version "1.0.5"
@@ -2531,88 +2696,94 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-eslint-import-resolver-node@^0.3.7:
- version "0.3.7"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
- integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==
+eslint-import-resolver-node@^0.3.9:
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
+ integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==
dependencies:
debug "^3.2.7"
- is-core-module "^2.11.0"
- resolve "^1.22.1"
+ is-core-module "^2.13.0"
+ resolve "^1.22.4"
-eslint-module-utils@^2.7.4:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
- integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==
+eslint-module-utils@^2.12.0:
+ version "2.12.0"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b"
+ integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==
dependencies:
debug "^3.2.7"
-eslint-plugin-import@^2.27.5:
- version "2.27.5"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65"
- integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==
+eslint-plugin-import@^2.31.0:
+ version "2.31.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7"
+ integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==
dependencies:
- array-includes "^3.1.6"
- array.prototype.flat "^1.3.1"
- array.prototype.flatmap "^1.3.1"
+ "@rtsao/scc" "^1.1.0"
+ array-includes "^3.1.8"
+ array.prototype.findlastindex "^1.2.5"
+ array.prototype.flat "^1.3.2"
+ array.prototype.flatmap "^1.3.2"
debug "^3.2.7"
doctrine "^2.1.0"
- eslint-import-resolver-node "^0.3.7"
- eslint-module-utils "^2.7.4"
- has "^1.0.3"
- is-core-module "^2.11.0"
+ eslint-import-resolver-node "^0.3.9"
+ eslint-module-utils "^2.12.0"
+ hasown "^2.0.2"
+ is-core-module "^2.15.1"
is-glob "^4.0.3"
minimatch "^3.1.2"
- object.values "^1.1.6"
- resolve "^1.22.1"
- semver "^6.3.0"
- tsconfig-paths "^3.14.1"
-
-eslint-plugin-jest@^27.2.2:
- version "27.2.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.2.tgz#be4ded5f91905d9ec89aa8968d39c71f3b072c0c"
- integrity sha512-euzbp06F934Z7UDl5ZUaRPLAc9MKjh0rMPERrHT7UhlCEwgb25kBj37TvMgWeHZVkR5I9CayswrpoaqZU1RImw==
+ object.fromentries "^2.0.8"
+ object.groupby "^1.0.3"
+ object.values "^1.2.0"
+ semver "^6.3.1"
+ string.prototype.trimend "^1.0.8"
+ tsconfig-paths "^3.15.0"
+
+eslint-plugin-jest@^27.9.0:
+ version "27.9.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz#7c98a33605e1d8b8442ace092b60e9919730000b"
+ integrity sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==
dependencies:
"@typescript-eslint/utils" "^5.10.0"
-eslint-plugin-react-hooks@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
- integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
+eslint-plugin-react-hooks@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596"
+ integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
eslint-plugin-react-native-globals@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==
-eslint-plugin-react-native@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.0.0.tgz#eec41984abe4970bdd7c6082dff7a98a5e34d0bb"
- integrity sha512-kMmdxrSY7A1WgdqaGC+rY/28rh7kBGNBRsk48ovqkQmdg5j4K+DaFmegENDzMrdLkoufKGRNkKX6bgSwQTCAxQ==
+eslint-plugin-react-native@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz#5343acd3b2246bc1b857ac38be708f070d18809f"
+ integrity sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==
dependencies:
- "@babel/traverse" "^7.7.4"
eslint-plugin-react-native-globals "^0.1.1"
-eslint-plugin-react@^7.32.2:
- version "7.32.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10"
- integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==
+eslint-plugin-react@^7.37.4:
+ version "7.37.4"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz#1b6c80b6175b6ae4b26055ae4d55d04c414c7181"
+ integrity sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==
dependencies:
- array-includes "^3.1.6"
- array.prototype.flatmap "^1.3.1"
- array.prototype.tosorted "^1.1.1"
+ array-includes "^3.1.8"
+ array.prototype.findlast "^1.2.5"
+ array.prototype.flatmap "^1.3.3"
+ array.prototype.tosorted "^1.1.4"
doctrine "^2.1.0"
+ es-iterator-helpers "^1.2.1"
estraverse "^5.3.0"
+ hasown "^2.0.2"
jsx-ast-utils "^2.4.1 || ^3.0.0"
minimatch "^3.1.2"
- object.entries "^1.1.6"
- object.fromentries "^2.0.6"
- object.hasown "^1.1.2"
- object.values "^1.1.6"
+ object.entries "^1.1.8"
+ object.fromentries "^2.0.8"
+ object.values "^1.2.1"
prop-types "^15.8.1"
- resolve "^2.0.0-next.4"
- semver "^6.3.0"
- string.prototype.matchall "^4.0.8"
+ resolve "^2.0.0-next.5"
+ semver "^6.3.1"
+ string.prototype.matchall "^4.0.12"
+ string.prototype.repeat "^1.0.0"
eslint-scope@^5.1.1:
version "5.1.1"
@@ -2622,45 +2793,46 @@ eslint-scope@^5.1.1:
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==
+eslint-scope@^7.2.2:
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
-eslint-visitor-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
- integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
-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-visitor-keys@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
+ integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
-eslint@^8.44.0:
- version "8.44.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.44.0.tgz#51246e3889b259bbcd1d7d736a0c10add4f0e500"
- integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==
+eslint@^8.57.1:
+ version "8.57.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9"
+ integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
- "@eslint-community/regexpp" "^4.4.0"
- "@eslint/eslintrc" "^2.1.0"
- "@eslint/js" "8.44.0"
- "@humanwhocodes/config-array" "^0.11.10"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/eslintrc" "^2.1.4"
+ "@eslint/js" "8.57.1"
+ "@humanwhocodes/config-array" "^0.13.0"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
- ajv "^6.10.0"
+ "@ungap/structured-clone" "^1.2.0"
+ ajv "^6.12.4"
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.6.0"
+ eslint-scope "^7.2.2"
+ eslint-visitor-keys "^3.4.3"
+ espree "^9.6.1"
esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@@ -2670,7 +2842,6 @@ eslint@^8.44.0:
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"
@@ -2682,19 +2853,18 @@ eslint@^8.44.0:
natural-compare "^1.4.0"
optionator "^0.9.3"
strip-ansi "^6.0.1"
- strip-json-comments "^3.1.0"
text-table "^0.2.0"
-espree@^9.6.0:
- version "9.6.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.0.tgz#80869754b1c6560f32e3b6929194a3fe07c5b82f"
- integrity sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==
+espree@^9.6.0, espree@^9.6.1:
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
dependencies:
acorn "^8.9.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.4.1"
-esprima@^4.0.0, esprima@~4.0.0:
+esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
@@ -2728,11 +2898,41 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+etag@^1.8.1, 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==
+
+event-stream@=3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
+ integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==
+ dependencies:
+ duplexer "~0.1.1"
+ from "~0"
+ map-stream "~0.1.0"
+ pause-stream "0.0.11"
+ split "0.3"
+ stream-combiner "~0.0.4"
+ through "~2.3.1"
+
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==
+eventemitter3@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
+ integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
+
+eventid@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/eventid/-/eventid-2.0.1.tgz#574e860149457a79a2efe788c459f0c3062d02ec"
+ integrity sha512-sPNTqiMokAvV048P2c9+foqVJzk49o6d4e0D/sq5jog3pw+4kBgyR0gaM1FM7Mx6Kzd9dztesh9oYz1LWWOpzw==
+ dependencies:
+ uuid "^8.0.0"
+
events@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
@@ -2753,47 +2953,115 @@ execa@^5.0.0:
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
-execa@^7.0.0:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43"
- integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==
- dependencies:
- cross-spawn "^7.0.3"
- get-stream "^6.0.1"
- human-signals "^4.3.0"
- is-stream "^3.0.0"
- merge-stream "^2.0.0"
- npm-run-path "^5.1.0"
- onetime "^6.0.0"
- signal-exit "^3.0.7"
- strip-final-newline "^3.0.0"
-
exit@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
-expect@^29.0.0, expect@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.1.tgz#64dd1c8f75e2c0b209418f2b8d36a07921adfdf1"
- integrity sha512-XEdDLonERCU1n9uR56/Stx9OqojaLAQtZf9PrCHH9Hl8YXiEIka3H4NXJ3NOIBmQJTg7+j7buh34PMHfJujc8g==
+expect@^29.0.0, expect@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc"
+ integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==
+ dependencies:
+ "@jest/expect-utils" "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+
+express@^4.21.2:
+ version "4.21.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32"
+ integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.3"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.7.1"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.3.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.3"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.12"
+ proxy-addr "~2.0.7"
+ qs "6.13.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.19.0"
+ serve-static "1.16.2"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+express@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9"
+ integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==
+ dependencies:
+ accepts "^2.0.0"
+ body-parser "^2.2.0"
+ content-disposition "^1.0.0"
+ content-type "^1.0.5"
+ cookie "^0.7.1"
+ cookie-signature "^1.2.1"
+ debug "^4.4.0"
+ encodeurl "^2.0.0"
+ escape-html "^1.0.3"
+ etag "^1.8.1"
+ finalhandler "^2.1.0"
+ fresh "^2.0.0"
+ http-errors "^2.0.0"
+ merge-descriptors "^2.0.0"
+ mime-types "^3.0.0"
+ on-finished "^2.4.1"
+ once "^1.4.0"
+ parseurl "^1.3.3"
+ proxy-addr "^2.0.7"
+ qs "^6.14.0"
+ range-parser "^1.2.1"
+ router "^2.2.0"
+ send "^1.1.0"
+ serve-static "^2.2.0"
+ statuses "^2.0.1"
+ type-is "^2.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==
+
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
dependencies:
- "@jest/expect-utils" "^29.6.1"
- "@types/node" "*"
- jest-get-type "^29.4.3"
- jest-matcher-utils "^29.6.1"
- jest-message-util "^29.6.1"
- jest-util "^29.6.1"
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.2.11, 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==
+fast-glob@^3.2.9, fast-glob@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
@@ -2811,10 +3079,15 @@ fast-levenshtein@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
-fastest-levenshtein@^1.0.16:
- version "1.0.16"
- resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
- integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
+fast-redact@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4"
+ integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==
+
+fast-safe-stringify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
+ integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
fastq@^1.6.0:
version "1.13.0"
@@ -2830,21 +3103,13 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
-figures@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
- integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==
+figures@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
dependencies:
escape-string-regexp "^1.0.5"
-figures@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-5.0.0.tgz#126cd055052dea699f8a54e8c9450e6ecfc44d5f"
- integrity sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==
- dependencies:
- escape-string-regexp "^5.0.0"
- is-unicode-supported "^1.2.0"
-
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"
@@ -2852,19 +3117,44 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+filelist@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
+ integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
+ dependencies:
+ minimatch "^5.0.1"
+
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
-find-up@^2.0.0:
+finalhandler@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
+ integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+finalhandler@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f"
+ integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==
dependencies:
- locate-path "^2.0.0"
+ debug "^4.4.0"
+ encodeurl "^2.0.0"
+ escape-html "^1.0.3"
+ on-finished "^2.4.1"
+ parseurl "^1.3.3"
+ statuses "^2.0.1"
find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
@@ -2882,21 +3172,6 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
-find-up@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790"
- integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==
- dependencies:
- locate-path "^7.1.0"
- path-exists "^5.0.0"
-
-find-versions@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-5.1.0.tgz#973f6739ce20f5e439a27eba8542a4b236c8e685"
- integrity sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==
- dependencies:
- semver-regex "^4.0.5"
-
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -2910,94 +3185,100 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
-from2@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
- integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.0"
+ is-callable "^1.1.3"
-fs-extra@^11.0.0:
- version "11.1.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
- integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
+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:
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^2.0.0"
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
-fs-minipass@^2.0.0, fs-minipass@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
- integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+formidable@^3.5.1:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.1.tgz#9360a23a656f261207868b1484624c4c8d06ee1a"
+ integrity sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==
dependencies:
- minipass "^3.0.0"
+ dezalgo "^1.0.4"
+ hexoid "^1.0.0"
+ once "^1.4.0"
-fs-minipass@^3.0.0, fs-minipass@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.1.tgz#853809af15b6d03e27638d1ab6432e6b378b085d"
- integrity sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==
- dependencies:
- minipass "^4.0.0"
+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==
+
+fresh@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4"
+ integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==
+
+from@~0:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
+ integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==
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:
+fsevents@^2.3.2, 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==
-
-function.prototype.name@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
- integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
- functions-have-names "^1.2.2"
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+function.prototype.name@^1.1.6, function.prototype.name@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78"
+ integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ functions-have-names "^1.2.3"
+ hasown "^2.0.2"
+ is-callable "^1.2.7"
-functions-have-names@^1.2.2:
+functions-have-names@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
-gauge@^4.0.3:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce"
- integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==
+gaxios@^6.0.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.1.0.tgz#8ab08adbf9cc600368a57545f58e004ccf831ccb"
+ integrity sha512-EIHuesZxNyIkUGcTQKQPMICyOpDD/bi+LJIJx+NLsSGmnS7N+xCLRX5bi4e9yAu9AlSZdVq+qlyWWVuTh/483w==
dependencies:
- aproba "^1.0.3 || ^2.0.0"
- color-support "^1.1.3"
- console-control-strings "^1.1.0"
- has-unicode "^2.0.1"
- signal-exit "^3.0.7"
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
- wide-align "^1.1.5"
+ extend "^3.0.2"
+ https-proxy-agent "^7.0.1"
+ is-stream "^2.0.0"
+ node-fetch "^2.6.9"
-gauge@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-5.0.0.tgz#e270ca9d97dae84abf64e5277ef1ebddc7dd1e2f"
- integrity sha512-0s5T5eciEG7Q3ugkxAkFtaDhrrhXsCRivA5y8C9WMHWuI8UlMOJg7+Iwf7Mccii+Dfs3H5jHepU0joPVyQU0Lw==
+gcp-metadata@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.0.0.tgz#2ae12008bef8caa8726cba31fd0a641ebad5fb56"
+ integrity sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==
dependencies:
- aproba "^1.0.3 || ^2.0.0"
- color-support "^1.1.3"
- console-control-strings "^1.1.0"
- has-unicode "^2.0.1"
- signal-exit "^3.0.7"
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
- wide-align "^1.1.5"
+ gaxios "^6.0.0"
+ json-bigint "^1.0.0"
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
@@ -3009,14 +3290,21 @@ get-caller-file@^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-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
- integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.3"
+get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5"
+ integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ dunder-proto "^1.0.0"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ function-bind "^1.1.2"
+ gopd "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ math-intrinsics "^1.0.0"
get-package-type@^0.1.0:
version "0.1.0"
@@ -3030,32 +3318,21 @@ get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
-get-stream@^6.0.0, get-stream@^6.0.1:
+get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
-get-symbol-description@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
- integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
- dependencies:
- call-bind "^1.0.2"
- get-intrinsic "^1.1.1"
-
-git-log-parser@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/git-log-parser/-/git-log-parser-1.2.0.tgz#2e6a4c1b13fc00028207ba795a7ac31667b9fd4a"
- integrity sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==
+get-symbol-description@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee"
+ integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==
dependencies:
- argv-formatter "~1.0.0"
- spawn-error-forwarder "~1.0.0"
- split2 "~1.0.0"
- stream-combiner2 "~1.1.1"
- through2 "~2.0.0"
- traverse "~0.6.6"
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
-glob-parent@^5.1.2:
+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==
@@ -3069,38 +3346,28 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
-glob@^7.0.0, glob@^7.1.3, glob@^7.1.4:
- version "7.2.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
- integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+glob@^6.0.1:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
+ integrity sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==
dependencies:
- fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
- minimatch "^3.1.1"
+ minimatch "2 || 3"
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^8.0.1, glob@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
- integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
+glob@^7.0.0, glob@^7.1.3, glob@^7.1.4:
+ 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 "^5.0.1"
+ minimatch "^3.1.1"
once "^1.3.0"
-
-glob@^9.3.0, glob@^9.3.1:
- version "9.3.2"
- resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.2.tgz#8528522e003819e63d11c979b30896e0eaf52eda"
- integrity sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==
- dependencies:
- fs.realpath "^1.0.0"
- minimatch "^7.4.1"
- minipass "^4.2.4"
- path-scurry "^1.6.1"
+ path-is-absolute "^1.0.0"
globals@^11.1.0:
version "11.12.0"
@@ -3114,7 +3381,15 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
-globby@^11.0.3, globby@^11.1.0:
+globalthis@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236"
+ integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
+ dependencies:
+ define-properties "^1.2.1"
+ gopd "^1.0.1"
+
+globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
@@ -3126,16 +3401,40 @@ globby@^11.0.3, globby@^11.1.0:
merge2 "^1.4.1"
slash "^3.0.0"
-globby@^13.1.4:
- version "13.1.4"
- resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317"
- integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==
+google-auth-library@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.0.0.tgz#b159d22464c679a6a25cb46d48a4ac97f9f426a2"
+ integrity sha512-IQGjgQoVUAfOk6khqTVMLvWx26R+yPw9uLyb1MNyMQpdKiKt0Fd9sp4NWoINjyGHR8S3iw12hMTYK7O8J07c6Q==
+ dependencies:
+ base64-js "^1.3.0"
+ ecdsa-sig-formatter "^1.0.11"
+ gaxios "^6.0.0"
+ gcp-metadata "^6.0.0"
+ gtoken "^7.0.0"
+ jws "^4.0.0"
+ lru-cache "^6.0.0"
+
+google-gax@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-4.0.3.tgz#4a0a69a0edbde2c1dbc9b160549db6e60492786e"
+ integrity sha512-gllHYRhZvpz0LcVN+xtyzBeUa/ZYiLGF4JNBECrvL/LxDkaJc09hHoQ+KzRBI2Ewqgrjj7V3QrOC2pGno5ropw==
dependencies:
- dir-glob "^3.0.1"
- fast-glob "^3.2.11"
- ignore "^5.2.0"
- merge2 "^1.4.1"
- slash "^4.0.0"
+ "@grpc/grpc-js" "~1.8.0"
+ "@grpc/proto-loader" "^0.7.0"
+ "@types/long" "^4.0.0"
+ abort-controller "^3.0.0"
+ duplexify "^4.0.0"
+ google-auth-library "^9.0.0"
+ node-fetch "^2.6.1"
+ object-hash "^3.0.0"
+ proto3-json-serializer "^1.1.1"
+ protobufjs "7.2.4"
+ retry-request "^6.0.0"
+
+gopd@^1.0.1, gopd@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
+ integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
got@^11.8.6:
version "11.8.6"
@@ -3154,34 +3453,30 @@ got@^11.8.6:
p-cancelable "^2.0.0"
responselike "^2.0.0"
-graceful-fs@4.2.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
- version "4.2.10"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
- integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+graceful-fs@^4.2.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==
graphemer@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
-handlebars@^4.7.7:
- version "4.7.7"
- resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
- integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
- dependencies:
- minimist "^1.2.5"
- neo-async "^2.6.0"
- source-map "^0.6.1"
- wordwrap "^1.0.0"
- optionalDependencies:
- uglify-js "^3.1.4"
+graphql@^16.8.1:
+ version "16.8.1"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07"
+ integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==
-hard-rejection@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
- integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
+gtoken@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-7.0.1.tgz#b64bd01d88268ea3a3572c9076a85d1c48f1a455"
+ integrity sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==
+ dependencies:
+ gaxios "^6.0.0"
+ jws "^4.0.0"
-has-bigints@^1.0.1, has-bigints@^1.0.2:
+has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
@@ -3196,71 +3491,75 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-property-descriptors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
- integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
- get-intrinsic "^1.1.1"
-
-has-symbols@^1.0.2, 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==
+ es-define-property "^1.0.0"
-has-tostringtag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
- integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+has-proto@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5"
+ integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==
dependencies:
- has-symbols "^1.0.2"
+ dunder-proto "^1.0.0"
-has-unicode@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
- integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
+has-symbols@^1.0.3, has-symbols@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
+ integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
-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==
+has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+ dependencies:
+ has-symbols "^1.0.3"
+
+hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
- function-bind "^1.1.1"
+ function-bind "^1.1.2"
-hook-std@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/hook-std/-/hook-std-3.0.0.tgz#47038a01981e07ce9d83a6a3b2eb98cad0f7bd58"
- integrity sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==
+headers-polyfill@3.2.5:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.2.5.tgz#6e67d392c9d113d37448fe45014e0afdd168faed"
+ integrity sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==
+
+hexoid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
+ integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
hosted-git-info@^2.1.4:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
-hosted-git-info@^4.0.1:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224"
- integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==
- dependencies:
- lru-cache "^6.0.0"
-
-hosted-git-info@^6.0.0, hosted-git-info@^6.1.1:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-6.1.1.tgz#629442c7889a69c05de604d52996b74fe6f26d58"
- integrity sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==
- dependencies:
- lru-cache "^7.5.1"
-
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
-http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1:
+http-cache-semantics@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
+http-errors@2.0.0, 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"
+
http-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43"
@@ -3270,14 +3569,6 @@ http-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
-http-proxy-agent@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673"
- integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==
- dependencies:
- agent-base "^7.1.0"
- debug "^4.3.4"
-
http2-wrapper@^1.0.0-beta.5.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
@@ -3294,10 +3585,10 @@ https-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
-https-proxy-agent@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz#75cb70d04811685667183b31ab158d006750418a"
- integrity sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==
+https-proxy-agent@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab"
+ integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==
dependencies:
agent-base "^7.0.2"
debug "4"
@@ -3307,43 +3598,48 @@ human-signals@^2.1.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
-human-signals@^4.3.0:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
- integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
+i18next-fs-backend@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-2.6.0.tgz#7b6b54c5ffc2a5073e47eda0673c002376fa1a3c"
+ integrity sha512-3ZlhNoF9yxnM8pa8bWp5120/Ob6t4lVl1l/tbLmkml/ei3ud8IWySCHt2lrY5xWRlSU5D9IV2sm5bEbGuTqwTw==
-humanize-ms@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
- integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
+i18next-http-middleware@^3.7.1:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/i18next-http-middleware/-/i18next-http-middleware-3.7.1.tgz#2c748be8f16d04c1cfe4a0003db31d7684d7625f"
+ integrity sha512-nVTSGB1P4Gad5PFQYf3xVUOzJ4tVSQYD8Rs0luyWkjEMwqdqAcZ9CqIzqYwVLgB5/BKr1COI0oAei5dlYzmGbg==
+
+i18next@^24.2.3:
+ version "24.2.3"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-24.2.3.tgz#3a05f72615cbd7c00d7e348667e2aabef1df753b"
+ integrity sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==
+ dependencies:
+ "@babel/runtime" "^7.26.10"
+
+iconv-lite@0.4.24, 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:
- ms "^2.0.0"
+ safer-buffer ">= 2.1.2 < 3"
-iconv-lite@^0.6.2:
+iconv-lite@0.6.3, iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
-ieee754@^1.2.1:
+ieee754@^1.1.13:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-ignore-walk@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.2.tgz#c48f48397cf8ef6174fcc28aa5f8c1de6203d389"
- integrity sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==
- dependencies:
- minimatch "^7.4.2"
-
-ignore@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
- integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+ignore@^5.2.0, ignore@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
+ integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
-import-fresh@^3.0.0, import-fresh@^3.2.1:
+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==
@@ -3351,11 +3647,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
parent-module "^1.0.0"
resolve-from "^4.0.0"
-import-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2"
- integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==
-
import-local@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
@@ -3369,21 +3660,6 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
-indent-string@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5"
- integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
-
-infer-owner@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
- integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
-
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -3392,117 +3668,158 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, 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==
-ini@^1.3.4, ini@~1.3.0:
- version "1.3.8"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
- integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+inquirer@^8.2.0:
+ version "8.2.5"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8"
+ integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^7.0.0"
-ini@^3.0.0, ini@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d"
- integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==
+internal-ip@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-6.2.0.tgz#d5541e79716e406b74ac6b07b856ef18dc1621c1"
+ integrity sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==
+ dependencies:
+ default-gateway "^6.0.0"
+ ipaddr.js "^1.9.1"
+ is-ip "^3.1.0"
+ p-event "^4.2.0"
-init-package-json@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-5.0.0.tgz#030cf0ea9c84cfc1b0dc2e898b45d171393e4b40"
- integrity sha512-kBhlSheBfYmq3e0L1ii+VKe3zBTLL5lDCDWR+f9dLmEGSB3MqLlMlsolubSsyI88Bg6EA+BIMlomAnQ1SwgQBw==
- dependencies:
- npm-package-arg "^10.0.0"
- promzard "^1.0.0"
- read "^2.0.0"
- read-package-json "^6.0.0"
- semver "^7.3.5"
- validate-npm-package-license "^3.0.4"
- validate-npm-package-name "^5.0.0"
-
-internal-slot@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
- integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
+internal-slot@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961"
+ integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==
dependencies:
- get-intrinsic "^1.1.0"
- has "^1.0.3"
- side-channel "^1.0.4"
+ es-errors "^1.3.0"
+ hasown "^2.0.2"
+ side-channel "^1.1.0"
interpret@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
-into-stream@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-7.0.0.tgz#d1a211e146be8acfdb84dabcbf00fe8205e72936"
- integrity sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==
- dependencies:
- from2 "^2.3.0"
- p-is-promise "^3.0.0"
-
-ip-regex@^4.1.0:
+ip-regex@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
-ip@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
- integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
+ipaddr.js@1.9.1, 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-arguments@^1.0.4:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+ integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-array-buffer@^3.0.4, is-array-buffer@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280"
+ integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ get-intrinsic "^1.2.6"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
-is-bigint@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
- integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+is-async-function@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
+ integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-bigint@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672"
+ integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==
dependencies:
- has-bigints "^1.0.1"
+ has-bigints "^1.0.2"
-is-boolean-object@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
- integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+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:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
+ binary-extensions "^2.0.0"
-is-callable@^1.1.4, is-callable@^1.2.7:
+is-boolean-object@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89"
+ integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==
+ dependencies:
+ call-bound "^1.0.2"
+ has-tostringtag "^1.0.2"
+
+is-callable@^1.1.3, is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
-is-cidr@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814"
- integrity sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA==
+is-core-module@^2.13.0, is-core-module@^2.15.1:
+ version "2.15.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37"
+ integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==
dependencies:
- cidr-regex "^3.1.1"
+ hasown "^2.0.2"
-is-core-module@^2.11.0, is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
- integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
+is-data-view@^1.0.1, is-data-view@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e"
+ integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==
dependencies:
- has "^1.0.3"
+ call-bound "^1.0.2"
+ get-intrinsic "^1.2.6"
+ is-typed-array "^1.1.13"
-is-date-object@^1.0.1:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
- integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+is-date-object@^1.0.5, is-date-object@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7"
+ integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==
dependencies:
- has-tostringtag "^1.0.0"
+ call-bound "^1.0.2"
+ has-tostringtag "^1.0.2"
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-finalizationregistry@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90"
+ integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==
+ dependencies:
+ call-bound "^1.0.3"
+
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"
@@ -3513,29 +3830,49 @@ is-generator-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
+is-generator-function@^1.0.10, is-generator-function@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+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-lambda@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5"
- integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==
+is-interactive@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
+ integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
-is-negative-zero@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
- integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
+is-ip@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8"
+ integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==
+ dependencies:
+ ip-regex "^4.0.0"
-is-number-object@^1.0.4:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
- integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+is-map@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
+ integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
+
+is-node-process@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134"
+ integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==
+
+is-number-object@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541"
+ integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==
dependencies:
- has-tostringtag "^1.0.0"
+ call-bound "^1.0.3"
+ has-tostringtag "^1.0.2"
is-number@^7.0.0:
version "7.0.0"
@@ -3552,106 +3889,108 @@ is-path-inside@^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@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
- integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==
-
-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-promise@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
+ integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
-is-regex@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
- integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+is-regex@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22"
+ integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==
dependencies:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
+ call-bound "^1.0.2"
+ gopd "^1.2.0"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.2"
-is-shared-array-buffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
- integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
+is-set@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d"
+ integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==
+
+is-shared-array-buffer@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f"
+ integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==
dependencies:
- call-bind "^1.0.2"
+ call-bound "^1.0.3"
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-stream@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
- integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
-
-is-string@^1.0.5, is-string@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
- integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+is-string@^1.0.7, is-string@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9"
+ integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==
dependencies:
- has-tostringtag "^1.0.0"
+ call-bound "^1.0.3"
+ has-tostringtag "^1.0.2"
-is-symbol@^1.0.2, is-symbol@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
- integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+is-symbol@^1.0.4, is-symbol@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634"
+ integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==
dependencies:
- has-symbols "^1.0.2"
+ call-bound "^1.0.2"
+ has-symbols "^1.1.0"
+ safe-regex-test "^1.1.0"
-is-text-path@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e"
- integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==
+is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15, is-typed-array@^1.1.3:
+ version "1.1.15"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b"
+ integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==
dependencies:
- text-extensions "^1.0.0"
+ which-typed-array "^1.1.16"
-is-unicode-supported@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714"
- integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==
+is-unicode-supported@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+ integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
-is-weakref@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
- integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+is-weakmap@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd"
+ integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==
+
+is-weakref@^1.0.2, is-weakref@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef"
+ integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==
dependencies:
- call-bind "^1.0.2"
+ call-bound "^1.0.2"
-isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+is-weakset@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca"
+ integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==
+ dependencies:
+ call-bound "^1.0.3"
+ get-intrinsic "^1.2.6"
+
+isarray@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
+ integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
-isomorphic-ws@5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf"
- integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==
-
-issue-parser@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/issue-parser/-/issue-parser-6.0.0.tgz#b1edd06315d4f2044a9755daf85fdafde9b4014a"
- integrity sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==
- dependencies:
- lodash.capitalize "^4.2.1"
- lodash.escaperegexp "^4.1.2"
- lodash.isplainobject "^4.0.6"
- lodash.isstring "^4.0.1"
- lodash.uniqby "^4.7.0"
+isows@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7"
+ integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==
istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3"
integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==
-istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
+istanbul-lib-instrument@^5.0.4:
version "5.2.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f"
integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==
@@ -3662,6 +4001,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
istanbul-lib-coverage "^3.2.0"
semver "^6.3.0"
+istanbul-lib-instrument@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz#7a8af094cbfff1d5bb280f62ce043695ae8dd5b8"
+ integrity sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^7.5.4"
+
istanbul-lib-report@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
@@ -3688,369 +4038,390 @@ istanbul-reports@^3.1.3:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
-java-properties@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211"
- integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==
+iterator.prototype@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.4.tgz#4ae6cf98b97fdc717b7e159d79dc25f8fc9482f1"
+ integrity sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.6"
+ has-symbols "^1.1.0"
+ reflect.getprototypeof "^1.0.8"
+ set-function-name "^2.0.2"
+
+jake@^10.8.5:
+ version "10.9.2"
+ resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f"
+ integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==
+ dependencies:
+ async "^3.2.3"
+ chalk "^4.0.2"
+ filelist "^1.0.4"
+ minimatch "^3.1.2"
-jest-changed-files@^29.5.0:
- version "29.5.0"
- resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e"
- integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==
+jest-changed-files@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
+ integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==
dependencies:
execa "^5.0.0"
+ jest-util "^29.7.0"
p-limit "^3.1.0"
-jest-circus@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.1.tgz#861dab37e71a89907d1c0fabc54a0019738ed824"
- integrity sha512-tPbYLEiBU4MYAL2XoZme/bgfUeotpDBd81lgHLCbDZZFaGmECk0b+/xejPFtmiBP87GgP/y4jplcRpbH+fgCzQ==
+jest-circus@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a"
+ integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==
dependencies:
- "@jest/environment" "^29.6.1"
- "@jest/expect" "^29.6.1"
- "@jest/test-result" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
chalk "^4.0.0"
co "^4.6.0"
- dedent "^0.7.0"
+ dedent "^1.0.0"
is-generator-fn "^2.0.0"
- jest-each "^29.6.1"
- jest-matcher-utils "^29.6.1"
- jest-message-util "^29.6.1"
- jest-runtime "^29.6.1"
- jest-snapshot "^29.6.1"
- jest-util "^29.6.1"
+ jest-each "^29.7.0"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
p-limit "^3.1.0"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
pure-rand "^6.0.0"
slash "^3.0.0"
stack-utils "^2.0.3"
-jest-cli@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.1.tgz#99d9afa7449538221c71f358f0fdd3e9c6e89f72"
- integrity sha512-607dSgTA4ODIN6go9w6xY3EYkyPFGicx51a69H7yfvt7lN53xNswEVLovq+E77VsTRi5fWprLH0yl4DJgE8Ing==
+jest-cli@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995"
+ integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==
dependencies:
- "@jest/core" "^29.6.1"
- "@jest/test-result" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/core" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
chalk "^4.0.0"
+ create-jest "^29.7.0"
exit "^0.1.2"
- graceful-fs "^4.2.9"
import-local "^3.0.2"
- jest-config "^29.6.1"
- jest-util "^29.6.1"
- jest-validate "^29.6.1"
- prompts "^2.0.1"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
yargs "^17.3.1"
-jest-config@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.1.tgz#d785344509065d53a238224c6cdc0ed8e2f2f0dd"
- integrity sha512-XdjYV2fy2xYixUiV2Wc54t3Z4oxYPAELUzWnV6+mcbq0rh742X2p52pii5A3oeRzYjLnQxCsZmp0qpI6klE2cQ==
+jest-config@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f"
+ integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==
dependencies:
"@babel/core" "^7.11.6"
- "@jest/test-sequencer" "^29.6.1"
- "@jest/types" "^29.6.1"
- babel-jest "^29.6.1"
+ "@jest/test-sequencer" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ babel-jest "^29.7.0"
chalk "^4.0.0"
ci-info "^3.2.0"
deepmerge "^4.2.2"
glob "^7.1.3"
graceful-fs "^4.2.9"
- jest-circus "^29.6.1"
- jest-environment-node "^29.6.1"
- jest-get-type "^29.4.3"
- jest-regex-util "^29.4.3"
- jest-resolve "^29.6.1"
- jest-runner "^29.6.1"
- jest-util "^29.6.1"
- jest-validate "^29.6.1"
+ jest-circus "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
micromatch "^4.0.4"
parse-json "^5.2.0"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
slash "^3.0.0"
strip-json-comments "^3.1.1"
-jest-diff@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.1.tgz#13df6db0a89ee6ad93c747c75c85c70ba941e545"
- integrity sha512-FsNCvinvl8oVxpNLttNQX7FAq7vR+gMDGj90tiP7siWw1UdakWUGqrylpsYrpvj908IYckm5Y0Q7azNAozU1Kg==
+jest-diff@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
dependencies:
chalk "^4.0.0"
- diff-sequences "^29.4.3"
- jest-get-type "^29.4.3"
- pretty-format "^29.6.1"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
-jest-docblock@^29.4.3:
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8"
- integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==
+jest-docblock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a"
+ integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==
dependencies:
detect-newline "^3.0.0"
-jest-each@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.1.tgz#975058e5b8f55c6780beab8b6ab214921815c89c"
- integrity sha512-n5eoj5eiTHpKQCAVcNTT7DRqeUmJ01hsAL0Q1SMiBHcBcvTKDELixQOGMCpqhbIuTcfC4kMfSnpmDqRgRJcLNQ==
+jest-each@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1"
+ integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
chalk "^4.0.0"
- jest-get-type "^29.4.3"
- jest-util "^29.6.1"
- pretty-format "^29.6.1"
-
-jest-environment-node@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.1.tgz#08a122dece39e58bc388da815a2166c58b4abec6"
- integrity sha512-ZNIfAiE+foBog24W+2caIldl4Irh8Lx1PUhg/GZ0odM1d/h2qORAsejiFc7zb+SEmYPn1yDZzEDSU5PmDkmVLQ==
- dependencies:
- "@jest/environment" "^29.6.1"
- "@jest/fake-timers" "^29.6.1"
- "@jest/types" "^29.6.1"
+ jest-get-type "^29.6.3"
+ jest-util "^29.7.0"
+ pretty-format "^29.7.0"
+
+jest-environment-node@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376"
+ integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
- jest-mock "^29.6.1"
- jest-util "^29.6.1"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
-jest-get-type@^29.4.3:
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5"
- integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==
+jest-get-type@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
+ integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
-jest-haste-map@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.1.tgz#62655c7a1c1b349a3206441330fb2dbdb4b63803"
- integrity sha512-0m7f9PZXxOCk1gRACiVgX85knUKPKLPg4oRCjLoqIm9brTHXaorMA0JpmtmVkQiT8nmXyIVoZd/nnH1cfC33ig==
+jest-haste-map@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104"
+ integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@types/graceful-fs" "^4.1.3"
"@types/node" "*"
anymatch "^3.0.3"
fb-watchman "^2.0.0"
graceful-fs "^4.2.9"
- jest-regex-util "^29.4.3"
- jest-util "^29.6.1"
- jest-worker "^29.6.1"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
micromatch "^4.0.4"
walker "^1.0.8"
optionalDependencies:
fsevents "^2.3.2"
-jest-leak-detector@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.1.tgz#66a902c81318e66e694df7d096a95466cb962f8e"
- integrity sha512-OrxMNyZirpOEwkF3UHnIkAiZbtkBWiye+hhBweCHkVbCgyEy71Mwbb5zgeTNYWJBi1qgDVfPC1IwO9dVEeTLwQ==
+jest-leak-detector@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728"
+ integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==
dependencies:
- jest-get-type "^29.4.3"
- pretty-format "^29.6.1"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
-jest-matcher-utils@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.1.tgz#6c60075d84655d6300c5d5128f46531848160b53"
- integrity sha512-SLaztw9d2mfQQKHmJXKM0HCbl2PPVld/t9Xa6P9sgiExijviSp7TnZZpw2Fpt+OI3nwUO/slJbOfzfUMKKC5QA==
+jest-matcher-utils@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
+ integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
dependencies:
chalk "^4.0.0"
- jest-diff "^29.6.1"
- jest-get-type "^29.4.3"
- pretty-format "^29.6.1"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
-jest-message-util@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.1.tgz#d0b21d87f117e1b9e165e24f245befd2ff34ff8d"
- integrity sha512-KoAW2zAmNSd3Gk88uJ56qXUWbFk787QKmjjJVOjtGFmmGSZgDBrlIL4AfQw1xyMYPNVD7dNInfIbur9B2rd/wQ==
+jest-message-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3"
+ integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
dependencies:
"@babel/code-frame" "^7.12.13"
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.9"
micromatch "^4.0.4"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
slash "^3.0.0"
stack-utils "^2.0.3"
-jest-mock@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.1.tgz#049ee26aea8cbf54c764af649070910607316517"
- integrity sha512-brovyV9HBkjXAEdRooaTQK42n8usKoSRR3gihzUpYeV/vwqgSoNfrksO7UfSACnPmxasO/8TmHM3w9Hp3G1dgw==
+jest-mock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347"
+ integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
- jest-util "^29.6.1"
+ jest-util "^29.7.0"
jest-pnp-resolver@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
-jest-regex-util@^29.4.3:
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8"
- integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==
+jest-regex-util@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52"
+ integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==
-jest-resolve-dependencies@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.1.tgz#b85b06670f987a62515bbf625d54a499e3d708f5"
- integrity sha512-BbFvxLXtcldaFOhNMXmHRWx1nXQO5LoXiKSGQcA1LxxirYceZT6ch8KTE1bK3X31TNG/JbkI7OkS/ABexVahiw==
+jest-resolve-dependencies@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428"
+ integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==
dependencies:
- jest-regex-util "^29.4.3"
- jest-snapshot "^29.6.1"
+ jest-regex-util "^29.6.3"
+ jest-snapshot "^29.7.0"
-jest-resolve@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.1.tgz#4c3324b993a85e300add2f8609f51b80ddea39ee"
- integrity sha512-AeRkyS8g37UyJiP9w3mmI/VXU/q8l/IH52vj/cDAyScDcemRbSBhfX/NMYIGilQgSVwsjxrCHf3XJu4f+lxCMg==
+jest-resolve@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30"
+ integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==
dependencies:
chalk "^4.0.0"
graceful-fs "^4.2.9"
- jest-haste-map "^29.6.1"
+ jest-haste-map "^29.7.0"
jest-pnp-resolver "^1.2.2"
- jest-util "^29.6.1"
- jest-validate "^29.6.1"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
resolve "^1.20.0"
resolve.exports "^2.0.0"
slash "^3.0.0"
-jest-runner@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.1.tgz#54557087e7972d345540d622ab5bfc3d8f34688c"
- integrity sha512-tw0wb2Q9yhjAQ2w8rHRDxteryyIck7gIzQE4Reu3JuOBpGp96xWgF0nY8MDdejzrLCZKDcp8JlZrBN/EtkQvPQ==
+jest-runner@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e"
+ integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==
dependencies:
- "@jest/console" "^29.6.1"
- "@jest/environment" "^29.6.1"
- "@jest/test-result" "^29.6.1"
- "@jest/transform" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/console" "^29.7.0"
+ "@jest/environment" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
chalk "^4.0.0"
emittery "^0.13.1"
graceful-fs "^4.2.9"
- jest-docblock "^29.4.3"
- jest-environment-node "^29.6.1"
- jest-haste-map "^29.6.1"
- jest-leak-detector "^29.6.1"
- jest-message-util "^29.6.1"
- jest-resolve "^29.6.1"
- jest-runtime "^29.6.1"
- jest-util "^29.6.1"
- jest-watcher "^29.6.1"
- jest-worker "^29.6.1"
+ jest-docblock "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-leak-detector "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-resolve "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-util "^29.7.0"
+ jest-watcher "^29.7.0"
+ jest-worker "^29.7.0"
p-limit "^3.1.0"
source-map-support "0.5.13"
-jest-runtime@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.1.tgz#8a0fc9274ef277f3d70ba19d238e64334958a0dc"
- integrity sha512-D6/AYOA+Lhs5e5il8+5pSLemjtJezUr+8zx+Sn8xlmOux3XOqx4d8l/2udBea8CRPqqrzhsKUsN/gBDE/IcaPQ==
- dependencies:
- "@jest/environment" "^29.6.1"
- "@jest/fake-timers" "^29.6.1"
- "@jest/globals" "^29.6.1"
- "@jest/source-map" "^29.6.0"
- "@jest/test-result" "^29.6.1"
- "@jest/transform" "^29.6.1"
- "@jest/types" "^29.6.1"
+jest-runtime@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817"
+ integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/globals" "^29.7.0"
+ "@jest/source-map" "^29.6.3"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
chalk "^4.0.0"
cjs-module-lexer "^1.0.0"
collect-v8-coverage "^1.0.0"
glob "^7.1.3"
graceful-fs "^4.2.9"
- jest-haste-map "^29.6.1"
- jest-message-util "^29.6.1"
- jest-mock "^29.6.1"
- jest-regex-util "^29.4.3"
- jest-resolve "^29.6.1"
- jest-snapshot "^29.6.1"
- jest-util "^29.6.1"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
slash "^3.0.0"
strip-bom "^4.0.0"
-jest-snapshot@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.1.tgz#0d083cb7de716d5d5cdbe80d598ed2fbafac0239"
- integrity sha512-G4UQE1QQ6OaCgfY+A0uR1W2AY0tGXUPQpoUClhWHq1Xdnx1H6JOrC2nH5lqnOEqaDgbHFgIwZ7bNq24HpB180A==
+jest-snapshot@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5"
+ integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==
dependencies:
"@babel/core" "^7.11.6"
"@babel/generator" "^7.7.2"
"@babel/plugin-syntax-jsx" "^7.7.2"
"@babel/plugin-syntax-typescript" "^7.7.2"
"@babel/types" "^7.3.3"
- "@jest/expect-utils" "^29.6.1"
- "@jest/transform" "^29.6.1"
- "@jest/types" "^29.6.1"
- "@types/prettier" "^2.1.5"
+ "@jest/expect-utils" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
babel-preset-current-node-syntax "^1.0.0"
chalk "^4.0.0"
- expect "^29.6.1"
+ expect "^29.7.0"
graceful-fs "^4.2.9"
- jest-diff "^29.6.1"
- jest-get-type "^29.4.3"
- jest-matcher-utils "^29.6.1"
- jest-message-util "^29.6.1"
- jest-util "^29.6.1"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
natural-compare "^1.4.0"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
semver "^7.5.3"
-jest-util@^29.0.0, jest-util@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.1.tgz#c9e29a87a6edbf1e39e6dee2b4689b8a146679cb"
- integrity sha512-NRFCcjc+/uO3ijUVyNOQJluf8PtGCe/W6cix36+M3cTFgiYqFOOW5MgN4JOOcvbUhcKTYVd1CvHz/LWi8d16Mg==
+jest-util@^29.0.0, jest-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"
+ integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
chalk "^4.0.0"
ci-info "^3.2.0"
graceful-fs "^4.2.9"
picomatch "^2.2.3"
-jest-validate@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.1.tgz#765e684af6e2c86dce950aebefbbcd4546d69f7b"
- integrity sha512-r3Ds69/0KCN4vx4sYAbGL1EVpZ7MSS0vLmd3gV78O+NAx3PDQQukRU5hNHPXlyqCgFY8XUk7EuTMLugh0KzahA==
+jest-validate@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c"
+ integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==
dependencies:
- "@jest/types" "^29.6.1"
+ "@jest/types" "^29.6.3"
camelcase "^6.2.0"
chalk "^4.0.0"
- jest-get-type "^29.4.3"
+ jest-get-type "^29.6.3"
leven "^3.1.0"
- pretty-format "^29.6.1"
+ pretty-format "^29.7.0"
-jest-watcher@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.1.tgz#7c0c43ddd52418af134c551c92c9ea31e5ec942e"
- integrity sha512-d4wpjWTS7HEZPaaj8m36QiaP856JthRZkrgcIY/7ISoUWPIillrXM23WPboZVLbiwZBt4/qn2Jke84Sla6JhFA==
+jest-watcher@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2"
+ integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==
dependencies:
- "@jest/test-result" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
"@types/node" "*"
ansi-escapes "^4.2.1"
chalk "^4.0.0"
emittery "^0.13.1"
- jest-util "^29.6.1"
+ jest-util "^29.7.0"
string-length "^4.0.1"
-jest-worker@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.1.tgz#64b015f0e985ef3a8ad049b61fe92b3db74a5319"
- integrity sha512-U+Wrbca7S8ZAxAe9L6nb6g8kPdia5hj32Puu5iOqBCMTMWFHXuK6dOV2IFrpedbTV8fjMFLdWNttQTBL6u2MRA==
+jest-worker@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a"
+ integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==
dependencies:
"@types/node" "*"
- jest-util "^29.6.1"
+ jest-util "^29.7.0"
merge-stream "^2.0.0"
supports-color "^8.0.0"
-jest@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.1.tgz#74be1cb719c3abe439f2d94aeb18e6540a5b02ad"
- integrity sha512-Nirw5B4nn69rVUZtemCQhwxOBhm0nsp3hmtF4rzCeWD7BkjAXRIji7xWQfnTNbz9g0aVsBX6aZK3n+23LM6uDw==
+jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613"
+ integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==
dependencies:
- "@jest/core" "^29.6.1"
- "@jest/types" "^29.6.1"
+ "@jest/core" "^29.7.0"
+ "@jest/types" "^29.6.3"
import-local "^3.0.2"
- jest-cli "^29.6.1"
+ jest-cli "^29.7.0"
+
+js-levenshtein@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
+ integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
@@ -4077,47 +4448,39 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+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-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
-json-parse-better-errors@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
- integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
-
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-json-parse-even-better-errors@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz#2cb2ee33069a78870a0c7e3da560026b89669cf7"
- integrity sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==
-
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-json-stringify-nice@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz#2c937962b80181d3f317dd39aa323e14f5a60a67"
- integrity sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==
-
-json-stringify-safe@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
- integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
-
-json5@^1.0.1:
+json5@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
@@ -4129,20 +4492,6 @@ json5@^2.2.1, json5@^2.2.3:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
-jsonfile@^6.0.1:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
- integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
- dependencies:
- universalify "^2.0.0"
- optionalDependencies:
- graceful-fs "^4.1.6"
-
-jsonparse@^1.2.0, jsonparse@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
- integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
-
"jsx-ast-utils@^2.4.1 || ^3.0.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz#e624f259143b9062c92b6413ff92a164c80d3ccb"
@@ -4151,15 +4500,22 @@ jsonparse@^1.2.0, jsonparse@^1.3.1:
array-includes "^3.1.4"
object.assign "^4.1.2"
-just-diff-apply@^5.2.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f"
- integrity sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==
+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"
-just-diff@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-6.0.2.tgz#03b65908543ac0521caf6d8eb85035f7d27ea285"
- integrity sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==
+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"
keyv@^4.0.0:
version "4.5.2"
@@ -4168,11 +4524,6 @@ keyv@^4.0.0:
dependencies:
json-buffer "3.0.1"
-kind-of@^6.0.3:
- version "6.0.3"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
- integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
@@ -4191,148 +4542,11 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
-libnpmaccess@^7.0.2:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52"
- integrity sha512-vHBVMw1JFMTgEk15zRsJuSAg7QtGGHpUSEfnbcRL1/gTBag9iEfJbyjpDmdJmwMhvpoLoNBtdAUCdGnaP32hhw==
- dependencies:
- npm-package-arg "^10.1.0"
- npm-registry-fetch "^14.0.3"
-
-libnpmdiff@^5.0.13:
- version "5.0.13"
- resolved "https://registry.yarnpkg.com/libnpmdiff/-/libnpmdiff-5.0.13.tgz#833712814f9e7f8fb0463660b46ab52e0d040a02"
- integrity sha512-PFuFUZZvKwboVAZePql97O4J63Rtps1HA9XAdzSHJoaRogFbmBlxymFXASjNjKCNlqz7G9oVizM1V6+rxx+Vow==
- dependencies:
- "@npmcli/arborist" "^6.2.5"
- "@npmcli/disparity-colors" "^3.0.0"
- "@npmcli/installed-package-contents" "^2.0.2"
- binary-extensions "^2.2.0"
- diff "^5.1.0"
- minimatch "^6.1.6"
- npm-package-arg "^10.1.0"
- pacote "^15.0.8"
- tar "^6.1.13"
-
-libnpmexec@^5.0.13:
- version "5.0.13"
- resolved "https://registry.yarnpkg.com/libnpmexec/-/libnpmexec-5.0.13.tgz#3e2e1cdf48d441d6dbbd8ff46a41dde9939fe8e2"
- integrity sha512-++Ek3+CNnFpPayUbizpacdY6QicgHzTdwwzYTO6AkPns5LWLoCilom+52+acV+TRbcLz/DPiuIIUgSRSBFFqqw==
- dependencies:
- "@npmcli/arborist" "^6.2.5"
- "@npmcli/run-script" "^6.0.0"
- chalk "^4.1.0"
- ci-info "^3.7.1"
- npm-package-arg "^10.1.0"
- npmlog "^7.0.1"
- pacote "^15.0.8"
- proc-log "^3.0.0"
- read "^2.0.0"
- read-package-json-fast "^3.0.2"
- semver "^7.3.7"
- walk-up-path "^1.0.0"
-
-libnpmfund@^4.0.13:
- version "4.0.13"
- resolved "https://registry.yarnpkg.com/libnpmfund/-/libnpmfund-4.0.13.tgz#6f1b2e24e8b3b53e463c007aa1e2280d79f02a99"
- integrity sha512-HKU4JiAkdEGA4mnqkjo+mtZ0n1YYwdoNvfuK+2qTOyYKmgTm48EOd/GxhW11kfyDWoTUTPp3hzBSQylhXLSm6g==
- dependencies:
- "@npmcli/arborist" "^6.2.5"
-
-libnpmhook@^9.0.3:
- version "9.0.3"
- resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-9.0.3.tgz#5dbd6a146feb7e11993d36a26f750ae2347bb1d9"
- integrity sha512-wMZe58sI7KLhg0+nUWZW5KdMfjNNcOIIbkoP19BDHYoUF9El7eeUWkGNxUGzpHkPKiGoQ1z/v6CYin4deebeuw==
- dependencies:
- aproba "^2.0.0"
- npm-registry-fetch "^14.0.3"
-
-libnpmorg@^5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-5.0.3.tgz#bd0a11d7a84b5f5c14689fb1e244fbb540700d63"
- integrity sha512-QCLLB2oKCCwdiedQRcsj5eHAyYXM7vICM5f0gB9aRQzyVzx57S3anBIzhEUOhJxq6cWKtXRfkR5GsCxHEJ0CxA==
- dependencies:
- aproba "^2.0.0"
- npm-registry-fetch "^14.0.3"
-
-libnpmpack@^5.0.13:
- version "5.0.13"
- resolved "https://registry.yarnpkg.com/libnpmpack/-/libnpmpack-5.0.13.tgz#3a28d106272018f772819329b074b6aa51a4c00f"
- integrity sha512-cqK1ZlgYEZPGzNFNqlq7trJqK/ZVcTJSc9xzG7d/HnENEYern/Mhyoh1dhtQBM2CR6fTCdgT++Sk8uV0ZhCsQQ==
- dependencies:
- "@npmcli/arborist" "^6.2.5"
- "@npmcli/run-script" "^6.0.0"
- npm-package-arg "^10.1.0"
- pacote "^15.0.8"
-
-libnpmpublish@^7.1.2:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-7.1.2.tgz#9a82a3a3df641378fcf5370f2f2d456a15d9fb4b"
- integrity sha512-IUjE5R3jCmTVWGEcJtzoRz3kAWoDqZUZzwhcpBN+rMIDiRRjS9ZGkyeT0KxXocg2DJEggyZyxSIdpaV//aLz/w==
- dependencies:
- ci-info "^3.6.1"
- normalize-package-data "^5.0.0"
- npm-package-arg "^10.1.0"
- npm-registry-fetch "^14.0.3"
- proc-log "^3.0.0"
- semver "^7.3.7"
- sigstore "^1.0.0"
- ssri "^10.0.1"
-
-libnpmsearch@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-6.0.2.tgz#b6a531a312855dd3bf84dd273b1033dd09b4cbec"
- integrity sha512-p+5BF19AvnVg8mcIQhy6yWhI6jHQRVMYaIaKeITEfYAffWsqbottA/WZdMtHL76hViC6SFM1WdclM1w5eAIa1g==
- dependencies:
- npm-registry-fetch "^14.0.3"
-
-libnpmteam@^5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-5.0.3.tgz#196657e9d87c0cc914c44fee588ad2b838074a3c"
- integrity sha512-7XOGhi45s+ml6TyrhJUTyrErcoDMKGKfEtiTEco4ofU7BGGAUOalVztKMVLLJgJOOXdIAIlzCHqkTXEuSiyCiA==
- dependencies:
- aproba "^2.0.0"
- npm-registry-fetch "^14.0.3"
-
-libnpmversion@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/libnpmversion/-/libnpmversion-4.0.2.tgz#cad9cd1b287fcf9576a64edfe71491b49a65d06f"
- integrity sha512-n1X70mFHv8Piy4yos+MFWUARSkTbyV5cdsHScaIkuwYvRAF/s2VtYScDzWB4Oe8uNEuGNdjiRR1E/Dh1tMvv6g==
- dependencies:
- "@npmcli/git" "^4.0.1"
- "@npmcli/run-script" "^6.0.0"
- json-parse-even-better-errors "^3.0.0"
- proc-log "^3.0.0"
- semver "^7.3.7"
-
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-lines-and-columns@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b"
- integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==
-
-load-json-file@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
- integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^4.0.0"
- pify "^3.0.0"
- strip-bom "^3.0.0"
-
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@@ -4347,44 +4561,12 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
-locate-path@^7.1.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a"
- integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==
- dependencies:
- p-locate "^6.0.0"
-
-lodash-es@^4.17.21:
- version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
- integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
-
-lodash.capitalize@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
- integrity sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==
-
-lodash.escaperegexp@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
- integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==
-
-lodash.ismatch@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
- integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
-
-lodash.isstring@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
- integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==
+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.memoize@4.x:
+lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
@@ -4394,16 +4576,29 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash.uniqby@^4.7.0:
- version "4.7.0"
- resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302"
- integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==
-
-lodash@^4.17.15, lodash@^4.17.21:
+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, long@^5.2.4:
+ version "5.2.4"
+ resolved "https://registry.yarnpkg.com/long/-/long-5.2.4.tgz#ee651d5c7c25901cfca5e67220ae9911695e99b2"
+ integrity sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==
+
loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@@ -4416,6 +4611,11 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+lru-cache@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117"
+ integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==
+
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@@ -4423,11 +4623,6 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
-lru-cache@^7.14.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1:
- version "7.18.3"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
- integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
-
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -4435,54 +4630,11 @@ make-dir@^3.0.0:
dependencies:
semver "^6.0.0"
-make-error@1.x, make-error@^1.1.1:
+make-error@^1.1.1, make-error@^1.3.6:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
-make-fetch-happen@^10.0.3:
- version "10.2.1"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164"
- integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==
- dependencies:
- agentkeepalive "^4.2.1"
- cacache "^16.1.0"
- http-cache-semantics "^4.1.0"
- http-proxy-agent "^5.0.0"
- https-proxy-agent "^5.0.0"
- is-lambda "^1.0.1"
- lru-cache "^7.7.1"
- minipass "^3.1.6"
- minipass-collect "^1.0.2"
- minipass-fetch "^2.0.3"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.4"
- negotiator "^0.6.3"
- promise-retry "^2.0.1"
- socks-proxy-agent "^7.0.0"
- ssri "^9.0.0"
-
-make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.0.3:
- version "11.0.3"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz#ed83dd3685b97f75607156d2721848f6eca561b9"
- integrity sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==
- dependencies:
- agentkeepalive "^4.2.1"
- cacache "^17.0.0"
- http-cache-semantics "^4.1.1"
- http-proxy-agent "^5.0.0"
- https-proxy-agent "^5.0.0"
- is-lambda "^1.0.1"
- lru-cache "^7.7.1"
- minipass "^4.0.0"
- minipass-fetch "^3.0.0"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.4"
- negotiator "^0.6.3"
- promise-retry "^2.0.1"
- socks-proxy-agent "^7.0.0"
- ssri "^10.0.0"
-
makeerror@1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
@@ -4490,49 +4642,35 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
-map-obj@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
- integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==
+map-stream@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
+ integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==
-map-obj@^4.0.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
- integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==
+math-intrinsics@^1.0.0, math-intrinsics@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
+ integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
-marked-terminal@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-5.1.1.tgz#d2edc2991841d893ee943b44b40b2ee9518b4d9f"
- integrity sha512-+cKTOx9P4l7HwINYhzbrBSyzgxO2HaHKGZGuB1orZsMIgXYaJyfidT81VXRdpelW/PcHEWxywscePVgI/oUF6g==
- dependencies:
- ansi-escapes "^5.0.0"
- cardinal "^2.1.1"
- chalk "^5.0.0"
- cli-table3 "^0.6.1"
- node-emoji "^1.11.0"
- supports-hyperlinks "^2.2.0"
+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==
-marked@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/marked/-/marked-5.1.0.tgz#cf51f03ba04dfb3469774029fd0106d258658767"
- integrity sha512-z3/nBe7aTI8JDszlYLk7dDVNpngjw0o1ZJtrA9kIfkkHcIF+xH7mO23aISl4WxP83elU+MFROgahqdpd05lMEQ==
-
-meow@^8.0.0, meow@^8.1.2:
- version "8.1.2"
- resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897"
- integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==
- dependencies:
- "@types/minimist" "^1.2.0"
- camelcase-keys "^6.2.2"
- decamelize-keys "^1.1.0"
- hard-rejection "^2.1.0"
- minimist-options "4.1.0"
- normalize-package-data "^3.0.0"
- read-pkg-up "^7.0.1"
- redent "^3.0.0"
- trim-newlines "^3.0.0"
- type-fest "^0.18.0"
- yargs-parser "^20.2.3"
+media-typer@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561"
+ integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==
+
+merge-descriptors@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
+ integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
+
+merge-descriptors@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808"
+ integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
merge-stream@^2.0.0:
version "2.0.0"
@@ -4544,29 +4682,58 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-micromatch@^4.0.2, 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==
+methods@^1.1.2, 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.8"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+ integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies:
- braces "^3.0.2"
+ braces "^3.0.3"
picomatch "^2.3.1"
-mime@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7"
- integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
+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-db@^1.54.0:
+ version "1.54.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
+ integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+
+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-types@^3.0.0, mime-types@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
+ integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
+ dependencies:
+ mime-db "^1.54.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==
+
+mime@2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
+ integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-mimic-fn@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
- integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
-
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@@ -4577,12 +4744,7 @@ mimic-response@^3.1.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-min-indent@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
- integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
-
-minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+"minimatch@2 || 3", 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==
@@ -4596,187 +4758,116 @@ minimatch@^5.0.1:
dependencies:
brace-expansion "^2.0.1"
-minimatch@^6.1.6, minimatch@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-6.2.0.tgz#2b70fd13294178c69c04dfc05aebdb97a4e79e42"
- integrity sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==
- dependencies:
- brace-expansion "^2.0.1"
-
-minimatch@^7.4.1, minimatch@^7.4.2:
- version "7.4.3"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.3.tgz#012cbf110a65134bb354ae9773b55256cdb045a2"
- integrity sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==
+minimatch@^9.0.4:
+ version "9.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51"
+ integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
dependencies:
brace-expansion "^2.0.1"
-minimist-options@4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
- integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
- dependencies:
- arrify "^1.0.1"
- is-plain-obj "^1.1.0"
- kind-of "^6.0.3"
-
-minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
+minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-minipass-collect@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
- integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
- dependencies:
- minipass "^3.0.0"
-
-minipass-fetch@^2.0.3:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add"
- integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==
- dependencies:
- minipass "^3.1.6"
- minipass-sized "^1.0.3"
- minizlib "^2.1.2"
- optionalDependencies:
- encoding "^0.1.13"
-
-minipass-fetch@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.1.tgz#bae3789f668d82ffae3ea47edc6b78b8283b3656"
- integrity sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==
- dependencies:
- minipass "^4.0.0"
- minipass-sized "^1.0.3"
- minizlib "^2.1.2"
- optionalDependencies:
- encoding "^0.1.13"
-
-minipass-flush@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
- integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
+mkdirp@~0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
dependencies:
- minipass "^3.0.0"
+ minimist "^1.2.6"
-minipass-json-stream@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7"
- integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==
- dependencies:
- jsonparse "^1.3.1"
- minipass "^3.0.0"
+moment@^2.19.3:
+ version "2.29.4"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+ integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
-minipass-pipeline@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
- integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
- dependencies:
- minipass "^3.0.0"
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-minipass-sized@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70"
- integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==
- dependencies:
- minipass "^3.0.0"
+ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6:
- version "3.3.6"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
- integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
- dependencies:
- yallist "^4.0.0"
+msw@^1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/msw/-/msw-1.3.5.tgz#708396f33a751d690eb8ee1d08713f5e9a77f27c"
+ integrity sha512-nG3fpmBXxFbKSIdk6miPuL3KjU6WMxgoW4tG1YgnP1M+TRG3Qn7b7R0euKAHq4vpwARHb18ZyfZljSxsTnMX2w==
+ dependencies:
+ "@mswjs/cookies" "^0.2.2"
+ "@mswjs/interceptors" "^0.17.10"
+ "@open-draft/until" "^1.0.3"
+ "@types/cookie" "^0.4.1"
+ "@types/js-levenshtein" "^1.1.1"
+ chalk "^4.1.1"
+ chokidar "^3.4.2"
+ cookie "^0.4.2"
+ graphql "^16.8.1"
+ headers-polyfill "3.2.5"
+ inquirer "^8.2.0"
+ is-node-process "^1.2.0"
+ js-levenshtein "^1.1.6"
+ node-fetch "^2.6.7"
+ outvariant "^1.4.0"
+ path-to-regexp "^6.3.0"
+ strict-event-emitter "^0.4.3"
+ type-fest "^2.19.0"
+ yargs "^17.3.1"
-minipass@^4.0.0, minipass@^4.0.2, minipass@^4.2.4:
- version "4.2.5"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.5.tgz#9e0e5256f1e3513f8c34691dd68549e85b2c8ceb"
- integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==
+mute-stream@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-minizlib@^2.1.1, minizlib@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
- integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+mv@~2:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
+ integrity sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==
dependencies:
- minipass "^3.0.0"
- yallist "^4.0.0"
+ mkdirp "~0.5.1"
+ ncp "~2.0.0"
+ rimraf "~2.4.0"
-mkdirp@^1.0.3, mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-modify-values@^1.0.0, modify-values@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
- integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
-
-ms@2.1.2, ms@^2.0.0, ms@^2.1.1, 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==
-
-mute-stream@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
- integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
-
-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==
+nan@^2.14.0:
+ version "2.17.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
+ integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
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:
+ncp@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
+ integrity sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==
+
+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==
-neo-async@^2.6.0:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
- integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
-
-nerf-dart@^1.0.0:
+negotiator@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a"
- integrity sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
+ integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
-node-emoji@^1.11.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c"
- integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==
- dependencies:
- lodash "^4.17.21"
+node-cleanup@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c"
+ integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==
-node-fetch@^2.6.7:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
- integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
+node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9:
+ 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-gyp@^9.0.0, node-gyp@^9.3.1:
- version "9.3.1"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.3.1.tgz#1e19f5f290afcc9c46973d68700cbd21a96192e4"
- integrity sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==
- dependencies:
- env-paths "^2.2.0"
- glob "^7.1.4"
- graceful-fs "^4.2.6"
- make-fetch-happen "^10.0.3"
- nopt "^6.0.0"
- npmlog "^6.0.0"
- rimraf "^3.0.2"
- semver "^7.3.5"
- tar "^6.1.2"
- which "^2.0.2"
-
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -4787,20 +4878,6 @@ node-releases@^2.0.5:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
-nopt@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d"
- integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==
- dependencies:
- abbrev "^1.0.0"
-
-nopt@^7.0.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.1.0.tgz#91f6a3366182176e72ecab93a09c19b63b485f28"
- integrity sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q==
- dependencies:
- abbrev "^2.0.0"
-
normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -4811,27 +4888,7 @@ normalize-package-data@^2.5.0:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
-normalize-package-data@^3.0.0, normalize-package-data@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e"
- integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==
- dependencies:
- hosted-git-info "^4.0.1"
- is-core-module "^2.5.0"
- semver "^7.3.4"
- validate-npm-package-license "^3.0.1"
-
-normalize-package-data@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588"
- integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==
- dependencies:
- hosted-git-info "^6.0.0"
- is-core-module "^2.8.1"
- semver "^7.3.5"
- validate-npm-package-license "^3.0.4"
-
-normalize-path@^3.0.0:
+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==
@@ -4841,85 +4898,6 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
-normalize-url@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.0.tgz#593dbd284f743e8dcf6a5ddf8fadff149c82701a"
- integrity sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==
-
-npm-audit-report@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-4.0.0.tgz#dfffdb6464a7799d3d30e067ae1943982cf45f69"
- integrity sha512-k2o5476sLrp94b6Gl819YzlS7LAdb8lgE6yQCysBEji5E3WoUdRve6tiVMLKAPPdLfItU4kOSUycWS5HFTrbug==
- dependencies:
- chalk "^4.0.0"
-
-npm-bundled@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7"
- integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==
- dependencies:
- npm-normalize-package-bin "^3.0.0"
-
-npm-install-checks@^6.0.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.1.0.tgz#7221210d9d746a40c37bf6c9b6c7a39f85e92998"
- integrity sha512-udSGENih/5xKh3Ex+L0PtZcOt0Pa+6ppDLnpG5D49/EhMja3LupaY9E/DtJTxyFBwE09ot7Fc+H4DywnZNWTVA==
- dependencies:
- semver "^7.1.1"
-
-npm-normalize-package-bin@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz#6097436adb4ef09e2628b59a7882576fe53ce485"
- integrity sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==
-
-npm-package-arg@^10.0.0, npm-package-arg@^10.1.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1"
- integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==
- dependencies:
- hosted-git-info "^6.0.0"
- proc-log "^3.0.0"
- semver "^7.3.5"
- validate-npm-package-name "^5.0.0"
-
-npm-packlist@^7.0.0:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-7.0.4.tgz#033bf74110eb74daf2910dc75144411999c5ff32"
- integrity sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==
- dependencies:
- ignore-walk "^6.0.0"
-
-npm-pick-manifest@^8.0.0, npm-pick-manifest@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz#c6acd97d1ad4c5dbb80eac7b386b03ffeb289e5f"
- integrity sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==
- dependencies:
- npm-install-checks "^6.0.0"
- npm-normalize-package-bin "^3.0.0"
- npm-package-arg "^10.0.0"
- semver "^7.3.5"
-
-npm-profile@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-7.0.1.tgz#a37dae08b22e662ece2c6e08946f9fcd9fdef663"
- integrity sha512-VReArOY/fCx5dWL66cbJ2OMogTQAVVQA//8jjmjkarboki3V7UJ0XbGFW+khRwiAJFQjuH0Bqr/yF7Y5RZdkMQ==
- dependencies:
- npm-registry-fetch "^14.0.0"
- proc-log "^3.0.0"
-
-npm-registry-fetch@^14.0.0, npm-registry-fetch@^14.0.3:
- version "14.0.3"
- resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz#8545e321c2b36d2c6fe6e009e77e9f0e527f547b"
- integrity sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==
- dependencies:
- make-fetch-happen "^11.0.0"
- minipass "^4.0.0"
- minipass-fetch "^3.0.0"
- minipass-json-stream "^1.0.1"
- minizlib "^2.1.2"
- npm-package-arg "^10.0.0"
- proc-log "^3.0.0"
-
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -4927,169 +4905,82 @@ npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
-npm-run-path@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00"
- integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==
- dependencies:
- path-key "^4.0.0"
-
-npm-user-validate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-2.0.0.tgz#7b69bbbff6f7992a1d9a8968d52fd6b6db5431b6"
- integrity sha512-sSWeqAYJ2dUPStJB+AEj0DyLRltr/f6YNcvCA7phkB8/RMLMnVsQ41GMwHo/ERZLYNDsyB2wPm7pZo1mqPOl7Q==
-
-npm@^9.5.0:
- version "9.6.2"
- resolved "https://registry.yarnpkg.com/npm/-/npm-9.6.2.tgz#b7858ab694c4335778c6d91e2310a61f2e369dac"
- integrity sha512-TnXoXhlFkH/9wI4+aXSq0aPLwKG7Ge17t1ME4/rQt+0DZWQCRk9PwhBuX/shqdUiHeKicSLSkzWx+QZgTRE+/A==
- dependencies:
- "@isaacs/string-locale-compare" "^1.1.0"
- "@npmcli/arborist" "^6.2.5"
- "@npmcli/config" "^6.1.4"
- "@npmcli/map-workspaces" "^3.0.2"
- "@npmcli/package-json" "^3.0.0"
- "@npmcli/run-script" "^6.0.0"
- abbrev "^2.0.0"
- archy "~1.0.0"
- cacache "^17.0.4"
- chalk "^4.1.2"
- ci-info "^3.8.0"
- cli-columns "^4.0.0"
- cli-table3 "^0.6.3"
- columnify "^1.6.0"
- fastest-levenshtein "^1.0.16"
- fs-minipass "^3.0.1"
- glob "^8.1.0"
- graceful-fs "^4.2.10"
- hosted-git-info "^6.1.1"
- ini "^3.0.1"
- init-package-json "^5.0.0"
- is-cidr "^4.0.2"
- json-parse-even-better-errors "^3.0.0"
- libnpmaccess "^7.0.2"
- libnpmdiff "^5.0.13"
- libnpmexec "^5.0.13"
- libnpmfund "^4.0.13"
- libnpmhook "^9.0.3"
- libnpmorg "^5.0.3"
- libnpmpack "^5.0.13"
- libnpmpublish "^7.1.2"
- libnpmsearch "^6.0.2"
- libnpmteam "^5.0.3"
- libnpmversion "^4.0.2"
- make-fetch-happen "^11.0.3"
- minimatch "^6.2.0"
- minipass "^4.2.4"
- minipass-pipeline "^1.2.4"
- ms "^2.1.2"
- node-gyp "^9.3.1"
- nopt "^7.0.0"
- npm-audit-report "^4.0.0"
- npm-install-checks "^6.0.0"
- npm-package-arg "^10.1.0"
- npm-pick-manifest "^8.0.1"
- npm-profile "^7.0.1"
- npm-registry-fetch "^14.0.3"
- npm-user-validate "^2.0.0"
- npmlog "^7.0.1"
- p-map "^4.0.0"
- pacote "^15.1.1"
- parse-conflict-json "^3.0.0"
- proc-log "^3.0.0"
- qrcode-terminal "^0.12.0"
- read "^2.0.0"
- read-package-json "^6.0.0"
- read-package-json-fast "^3.0.2"
- semver "^7.3.8"
- ssri "^10.0.1"
- tar "^6.1.13"
- text-table "~0.2.0"
- tiny-relative-date "^1.3.0"
- treeverse "^3.0.0"
- validate-npm-package-name "^5.0.0"
- which "^3.0.0"
- write-file-atomic "^5.0.0"
-
-npmlog@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830"
- integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
- dependencies:
- are-we-there-yet "^3.0.0"
- console-control-strings "^1.1.0"
- gauge "^4.0.3"
- set-blocking "^2.0.0"
-
-npmlog@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-7.0.1.tgz#7372151a01ccb095c47d8bf1d0771a4ff1f53ac8"
- integrity sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg==
- dependencies:
- are-we-there-yet "^4.0.0"
- console-control-strings "^1.1.0"
- gauge "^5.0.0"
- set-blocking "^2.0.0"
-
-object-assign@^4.1.1:
+object-assign@^4, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
-object-inspect@^1.12.2, object-inspect@^1.9.0:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
- integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
+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.13.3:
+ version "1.13.3"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a"
+ integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-object.assign@^4.1.2, object.assign@^4.1.4:
- version "4.1.4"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
- integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
+object.assign@^4.1.2, object.assign@^4.1.7:
+ version "4.1.7"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d"
+ integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- has-symbols "^1.0.3"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+ has-symbols "^1.1.0"
object-keys "^1.1.1"
-object.entries@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23"
- integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==
+object.entries@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41"
+ integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
-object.fromentries@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73"
- integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==
+object.fromentries@^2.0.8:
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65"
+ integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-object-atoms "^1.0.0"
-object.hasown@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92"
- integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==
+object.groupby@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e"
+ integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==
dependencies:
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
-object.values@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d"
- integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==
+object.values@^1.2.0, object.values@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216"
+ integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+
+on-finished@2.4.1, on-finished@^2.3.0, 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.3.1, once@^1.4.0:
version "1.4.0"
@@ -5098,20 +4989,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
-onetime@^5.1.2:
+onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
-onetime@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
- integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
- dependencies:
- mimic-fn "^4.0.0"
-
optionator@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
@@ -5124,34 +5008,69 @@ optionator@^0.9.3:
prelude-ls "^1.2.1"
type-check "^0.4.0"
+ora@^5.4.1:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
+ integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
+ dependencies:
+ bl "^4.1.0"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-spinners "^2.5.0"
+ is-interactive "^1.0.0"
+ is-unicode-supported "^0.1.0"
+ log-symbols "^4.1.0"
+ strip-ansi "^6.0.0"
+ wcwidth "^1.0.1"
+
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
+
+outvariant@^1.2.1, outvariant@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.0.tgz#e742e4bda77692da3eca698ef5bfac62d9fba06e"
+ integrity sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==
+
+own-keys@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358"
+ integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==
+ dependencies:
+ get-intrinsic "^1.2.6"
+ object-keys "^1.1.1"
+ safe-push-apply "^1.0.0"
+
+ox@0.6.7:
+ version "0.6.7"
+ resolved "https://registry.yarnpkg.com/ox/-/ox-0.6.7.tgz#afd53f2ecef68b8526660e9d29dee6e6b599a832"
+ integrity sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==
+ dependencies:
+ "@adraffy/ens-normalize" "^1.10.1"
+ "@noble/curves" "^1.6.0"
+ "@noble/hashes" "^1.5.0"
+ "@scure/bip32" "^1.5.0"
+ "@scure/bip39" "^1.4.0"
+ abitype "^1.0.6"
+ eventemitter3 "5.0.1"
+
p-cancelable@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
-p-each-series@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-3.0.0.tgz#d1aed5e96ef29864c897367a7d2a628fdc960806"
- integrity sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==
-
-p-filter@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-3.0.0.tgz#ce50e03b24b23930e11679ab8694bd09a2d7ed35"
- integrity sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==
+p-event@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
+ integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
dependencies:
- p-map "^5.1.0"
-
-p-is-promise@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971"
- integrity sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==
+ p-timeout "^3.1.0"
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
- dependencies:
- p-try "^1.0.0"
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+ integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
p-limit@^2.2.0:
version "2.3.0"
@@ -5167,20 +5086,6 @@ p-limit@^3.0.2, p-limit@^3.1.0:
dependencies:
yocto-queue "^0.1.0"
-p-limit@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644"
- integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==
- dependencies:
- yocto-queue "^1.0.0"
-
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==
- dependencies:
- p-limit "^1.1.0"
-
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
@@ -5195,66 +5100,18 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
-p-locate@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f"
- integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==
- dependencies:
- p-limit "^4.0.0"
-
-p-map@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
- integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
- dependencies:
- aggregate-error "^3.0.0"
-
-p-map@^5.1.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-5.5.0.tgz#054ca8ca778dfa4cf3f8db6638ccb5b937266715"
- integrity sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==
+p-timeout@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
+ integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
dependencies:
- aggregate-error "^4.0.0"
-
-p-reduce@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-3.0.0.tgz#f11773794792974bd1f7a14c72934248abff4160"
- integrity sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==
-
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==
+ p-finally "^1.0.0"
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-pacote@^15.0.0, pacote@^15.0.8, pacote@^15.1.1:
- version "15.1.1"
- resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.1.1.tgz#94d8c6e0605e04d427610b3aacb0357073978348"
- integrity sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==
- dependencies:
- "@npmcli/git" "^4.0.0"
- "@npmcli/installed-package-contents" "^2.0.1"
- "@npmcli/promise-spawn" "^6.0.1"
- "@npmcli/run-script" "^6.0.0"
- cacache "^17.0.0"
- fs-minipass "^3.0.0"
- minipass "^4.0.0"
- npm-package-arg "^10.0.0"
- npm-packlist "^7.0.0"
- npm-pick-manifest "^8.0.0"
- npm-registry-fetch "^14.0.0"
- proc-log "^3.0.0"
- promise-retry "^2.0.1"
- read-package-json "^6.0.0"
- read-package-json-fast "^3.0.0"
- sigstore "^1.0.0"
- ssri "^10.0.0"
- tar "^6.1.11"
-
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -5262,23 +5119,6 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
-parse-conflict-json@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c"
- integrity sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==
- dependencies:
- json-parse-even-better-errors "^3.0.0"
- just-diff "^6.0.0"
- just-diff-apply "^5.2.0"
-
-parse-json@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
- integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==
- dependencies:
- error-ex "^1.3.1"
- json-parse-better-errors "^1.0.1"
-
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
@@ -5289,32 +5129,16 @@ parse-json@^5.0.0, parse-json@^5.2.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
-parse-json@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-7.0.0.tgz#51c0713f233b804eb5adee3ef1e75d3243e0ff06"
- integrity sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==
- dependencies:
- "@babel/code-frame" "^7.21.4"
- error-ex "^1.3.2"
- json-parse-even-better-errors "^3.0.0"
- lines-and-columns "^2.0.3"
- type-fest "^3.8.0"
-
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==
+parseurl@^1.3.3, 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-exists@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7"
- integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==
-
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"
@@ -5325,57 +5149,53 @@ path-key@^3.0.0, path-key@^3.1.0:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-path-key@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
- integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
-
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-path-scurry@^1.6.1:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.6.3.tgz#4eba7183d64ef88b63c7d330bddc3ba279dc6c40"
- integrity sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==
- dependencies:
- lru-cache "^7.14.1"
- minipass "^4.0.2"
+path-to-regexp@0.1.12:
+ version "0.1.12"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
+ integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
+
+path-to-regexp@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4"
+ integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==
+
+path-to-regexp@^8.0.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4"
+ integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==
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==
+pause-stream@0.0.11:
+ version "0.0.11"
+ resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
+ integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==
+ dependencies:
+ through "~2.3"
+
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-pify@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
- integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
-
pirates@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b"
integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==
-pkg-conf@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058"
- integrity sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==
- dependencies:
- find-up "^2.0.0"
- load-json-file "^4.0.0"
-
pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@@ -5383,71 +5203,35 @@ pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
-postcss-selector-parser@^6.0.10:
- version "6.0.11"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc"
- integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==
- dependencies:
- cssesc "^3.0.0"
- util-deprecate "^1.0.2"
+possible-typed-array-names@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
+ integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
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==
-prettier@^2.8.8:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
- integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+prettier@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
+ integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
-pretty-format@^29.0.0, pretty-format@^29.6.1:
- version "29.6.1"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.1.tgz#ec838c288850b7c4f9090b867c2d4f4edbfb0f3e"
- integrity sha512-7jRj+yXO0W7e4/tSJKoR7HRIHLPPjtNaUGG2xxKQnGvPNRkgWcQ0AZX6P4KBRJN4FcTBWb3sa7DVUJmocYuoog==
+pretty-format@^29.0.0, pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
dependencies:
- "@jest/schemas" "^29.6.0"
+ "@jest/schemas" "^29.6.3"
ansi-styles "^5.0.0"
react-is "^18.0.0"
-proc-log@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8"
- integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==
-
-process-nextick-args@~2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
- integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
-promise-all-reject-late@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2"
- integrity sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==
-
-promise-call-limit@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-call-limit/-/promise-call-limit-1.0.1.tgz#4bdee03aeb85674385ca934da7114e9bcd3c6e24"
- integrity sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==
-
-promise-inflight@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
- integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
-
-promise-retry@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
- integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
- dependencies:
- err-code "^2.0.2"
- retry "^0.12.0"
-
prompts@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
@@ -5456,13 +5240,6 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
-promzard@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/promzard/-/promzard-1.0.0.tgz#3246f8e6c9895a77c0549cefb65828ac0f6c006b"
- integrity sha512-KQVDEubSUHGSt5xLakaToDFrSoZhStB8dXLzk2xvwR67gJktrHFvpR63oZgHyK19WKbHFLXJqCPXdVR3aBP8Ig==
- dependencies:
- read "^2.0.0"
-
prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
@@ -5472,10 +5249,45 @@ prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
-proto-list@~1.2.1:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
- integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
+proto3-json-serializer@^1.1.1:
+ 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@7.2.4, protobufjs@^7.0.0:
+ version "7.2.4"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
+ integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
+ 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, 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"
+
+ps-tree@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd"
+ integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==
+ dependencies:
+ event-stream "=3.3.4"
pump@^3.0.0:
version "3.0.0"
@@ -5485,6 +5297,15 @@ pump@^3.0.0:
end-of-stream "^1.1.0"
once "^1.3.1"
+pumpify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-2.0.1.tgz#abfc7b5a621307c728b551decbbefb51f0e4aa1e"
+ integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==
+ dependencies:
+ duplexify "^4.1.1"
+ inherits "^2.0.3"
+ pump "^3.0.0"
+
punycode@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
@@ -5495,40 +5316,59 @@ pure-rand@^6.0.0:
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.1.tgz#31207dddd15d43f299fdcdb2f572df65030c19af"
integrity sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==
-q@^1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
- integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
-
qrcode-terminal@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
+qs@6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
+ integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
+ dependencies:
+ side-channel "^1.0.6"
+
+qs@^6.11.0, qs@^6.14.0:
+ version "6.14.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
+ integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
+ dependencies:
+ side-channel "^1.1.0"
+
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==
-quick-lru@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
- integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
-
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
-rc@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
- integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+range-parser@^1.2.1, 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.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
- deep-extend "^0.6.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+raw-body@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f"
+ integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.6.3"
+ unpipe "1.0.0"
react-is@^16.13.1:
version "16.13.1"
@@ -5540,38 +5380,6 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
-read-cmd-shim@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb"
- integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==
-
-read-package-json-fast@^3.0.0, read-package-json-fast@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049"
- integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==
- dependencies:
- json-parse-even-better-errors "^3.0.0"
- npm-normalize-package-bin "^3.0.0"
-
-read-package-json@^6.0.0:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.1.tgz#566cb06bc05dbddefba4607e9096d5a9efbcd836"
- integrity sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==
- dependencies:
- glob "^9.3.0"
- json-parse-even-better-errors "^3.0.0"
- normalize-package-data "^5.0.0"
- npm-normalize-package-bin "^3.0.0"
-
-read-pkg-up@^10.0.0:
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-10.0.0.tgz#0542d21ff1001d2bfff1f6eac8b4d1d1dc486617"
- integrity sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==
- dependencies:
- find-up "^6.3.0"
- read-pkg "^8.0.0"
- type-fest "^3.12.0"
-
read-pkg-up@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
@@ -5581,15 +5389,6 @@ read-pkg-up@^7.0.1:
read-pkg "^5.2.0"
type-fest "^0.8.1"
-read-pkg-up@^9.0.0:
- version "9.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-9.1.0.tgz#38ca48e0bc6c6b260464b14aad9bcd4e5b1fbdc3"
- integrity sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==
- dependencies:
- find-up "^6.3.0"
- read-pkg "^7.1.0"
- type-fest "^2.5.0"
-
read-pkg@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@@ -5600,34 +5399,7 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
-read-pkg@^7.0.0, read-pkg@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-7.1.0.tgz#438b4caed1ad656ba359b3e00fd094f3c427a43e"
- integrity sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==
- dependencies:
- "@types/normalize-package-data" "^2.4.1"
- normalize-package-data "^3.0.2"
- parse-json "^5.2.0"
- type-fest "^2.0.0"
-
-read-pkg@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-8.0.0.tgz#78b93774c15a3f151b56d5790d5127a5cb9fc507"
- integrity sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==
- dependencies:
- "@types/normalize-package-data" "^2.4.1"
- normalize-package-data "^5.0.0"
- parse-json "^7.0.0"
- type-fest "^3.8.0"
-
-read@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/read/-/read-2.0.0.tgz#1d469a7321088e53b86ca77bf60a609e02f4eed8"
- integrity sha512-88JMmpeeRYzW9gvIpYyXlYadWanW4vB2CYtDDVBfbRpbSogUNjTWEBXxJXMIVFSLjWVdCcdcIjI3+VV3Z2e9mw==
- dependencies:
- mute-stream "~1.0.0"
-
-readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.6.0:
+readable-stream@^3.1.1, readable-stream@^3.4.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@@ -5636,28 +5408,12 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.6.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
-readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@~2.3.6:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
- integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba"
- integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==
+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:
- abort-controller "^3.0.0"
- buffer "^6.0.3"
- events "^3.3.0"
- process "^0.11.10"
+ picomatch "^2.2.1"
rechoir@^0.6.2:
version "0.6.2"
@@ -5666,42 +5422,45 @@ rechoir@^0.6.2:
dependencies:
resolve "^1.1.6"
-redent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
- integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
- dependencies:
- indent-string "^4.0.0"
- strip-indent "^3.0.0"
-
-redeyed@~2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b"
- integrity sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==
- dependencies:
- esprima "~4.0.0"
-
-regexp.prototype.flags@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
- integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- functions-have-names "^1.2.2"
-
-registry-auth-token@^5.0.0:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756"
- integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==
- dependencies:
- "@pnpm/npm-conf" "^2.1.0"
+reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.8, reflect.getprototypeof@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz#c905f3386008de95a62315f3ea8630404be19e2f"
+ integrity sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==
+ dependencies:
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ dunder-proto "^1.0.1"
+ es-abstract "^1.23.6"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ gopd "^1.2.0"
+ which-builtin-type "^1.2.1"
+
+regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+regexp.prototype.flags@^1.5.3:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42"
+ integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-errors "^1.3.0"
+ set-function-name "^2.0.2"
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==
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
resolve-alpn@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
@@ -5729,21 +5488,21 @@ resolve.exports@^2.0.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e"
integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.4:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
dependencies:
- is-core-module "^2.9.0"
+ is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-resolve@^2.0.0-next.4:
- version "2.0.0-next.4"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
- integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==
+resolve@^2.0.0-next.5:
+ version "2.0.0-next.5"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c"
+ integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==
dependencies:
- is-core-module "^2.9.0"
+ is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
@@ -5754,10 +5513,21 @@ responselike@^2.0.0:
dependencies:
lowercase-keys "^2.0.0"
-retry@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
- integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
+retry-request@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-6.0.0.tgz#a74dbbab421b51daefa20228f6036e6e2a0f1169"
+ integrity sha512-24kaFMd3wCnT3n4uPnsQh90ZSV8OISpfTFXJ00Wi+/oD2OPrp63EQ8hznk6rhxdlpwx2QBhQSDz2Fg46ki852g==
+ dependencies:
+ debug "^4.1.1"
+ extend "^3.0.2"
reusify@^1.0.4:
version "1.0.4"
@@ -5771,6 +5541,29 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
+rimraf@~2.4.0:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da"
+ integrity sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==
+ dependencies:
+ glob "^6.0.1"
+
+router@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef"
+ integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==
+ dependencies:
+ debug "^4.4.0"
+ depd "^2.0.0"
+ is-promise "^4.0.0"
+ parseurl "^1.3.3"
+ path-to-regexp "^8.0.0"
+
+run-async@^2.4.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
+
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -5778,92 +5571,163 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
-safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+rxjs@^7.5.5:
+ version "7.8.1"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+ integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+ dependencies:
+ tslib "^2.1.0"
+
+safe-array-concat@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3"
+ integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ get-intrinsic "^1.2.6"
+ has-symbols "^1.1.0"
+ isarray "^2.0.5"
+
+safe-buffer@5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-regex-test@^1.0.0:
+safe-json-stringify@~1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd"
+ integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==
+
+safe-push-apply@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
- integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==
+ resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5"
+ integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==
dependencies:
- call-bind "^1.0.2"
- get-intrinsic "^1.1.3"
- is-regex "^1.1.4"
+ es-errors "^1.3.0"
+ isarray "^2.0.5"
+
+safe-regex-test@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1"
+ integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ is-regex "^1.2.1"
-"safer-buffer@>= 2.1.2 < 3.0.0":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-semantic-release@^21.0.7:
- version "21.0.7"
- resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-21.0.7.tgz#deac6f4908bbd3c03c9a3ba41ae402b4305bf115"
- integrity sha512-peRDSXN+hF8EFSKzze90ff/EnAmgITHQ/a3SZpRV3479ny0BIZWEJ33uX6/GlOSKdaSxo9hVRDyv2/u2MuF+Bw==
- dependencies:
- "@semantic-release/commit-analyzer" "^10.0.0"
- "@semantic-release/error" "^4.0.0"
- "@semantic-release/github" "^9.0.0"
- "@semantic-release/npm" "^10.0.2"
- "@semantic-release/release-notes-generator" "^11.0.0"
- aggregate-error "^4.0.1"
- cosmiconfig "^8.0.0"
- debug "^4.0.0"
- env-ci "^9.0.0"
- execa "^7.0.0"
- figures "^5.0.0"
- find-versions "^5.1.0"
- get-stream "^6.0.0"
- git-log-parser "^1.2.0"
- hook-std "^3.0.0"
- hosted-git-info "^6.0.0"
- lodash-es "^4.17.21"
- marked "^5.0.0"
- marked-terminal "^5.1.1"
- micromatch "^4.0.2"
- p-each-series "^3.0.0"
- p-reduce "^3.0.0"
- read-pkg-up "^10.0.0"
- resolve-from "^5.0.0"
- semver "^7.3.2"
- semver-diff "^4.0.0"
- signale "^1.2.1"
- yargs "^17.5.1"
-
-semver-diff@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-4.0.0.tgz#3afcf5ed6d62259f5c72d0d5d50dffbdc9680df5"
- integrity sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==
+"semver@2 || 3 || 4 || 5":
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@^7.7.1:
+ version "7.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
+ integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
+
+send@0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
+ integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
+ 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"
+
+send@^1.1.0, send@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212"
+ integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==
+ dependencies:
+ debug "^4.3.5"
+ encodeurl "^2.0.0"
+ escape-html "^1.0.3"
+ etag "^1.8.1"
+ fresh "^2.0.0"
+ http-errors "^2.0.0"
+ mime-types "^3.0.1"
+ ms "^2.1.3"
+ on-finished "^2.4.1"
+ range-parser "^1.2.1"
+ statuses "^2.0.1"
+
+serve-static@1.16.2:
+ version "1.16.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
+ integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
+ dependencies:
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.19.0"
+
+serve-static@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9"
+ integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==
dependencies:
- semver "^7.3.5"
+ encodeurl "^2.0.0"
+ escape-html "^1.0.3"
+ parseurl "^1.3.3"
+ send "^1.2.0"
-semver-regex@^4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-4.0.5.tgz#fbfa36c7ba70461311f5debcb3928821eb4f9180"
- integrity sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==
-
-"semver@2 || 3 || 4 || 5":
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+set-cookie-parser@^2.4.6:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51"
+ integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==
-semver@^6.0.0, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+set-function-length@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
-semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3:
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
- integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+set-function-name@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985"
+ integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==
dependencies:
- lru-cache "^6.0.0"
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ functions-have-names "^1.2.3"
+ has-property-descriptors "^1.0.2"
-set-blocking@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
shebang-command@^2.0.0:
version "2.0.0"
@@ -5886,37 +5750,50 @@ shelljs@^0.8.5:
interpret "^1.0.0"
rechoir "^0.6.2"
-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==
+side-channel-list@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
+ integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
dependencies:
- call-bind "^1.0.0"
- get-intrinsic "^1.0.2"
- object-inspect "^1.9.0"
+ es-errors "^1.3.0"
+ object-inspect "^1.13.3"
-signal-exit@^3.0.3, signal-exit@^3.0.7:
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
- integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+side-channel-map@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
+ integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.5"
+ object-inspect "^1.13.3"
-signale@^1.2.1:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1"
- integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==
+side-channel-weakmap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
+ integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
dependencies:
- chalk "^2.3.2"
- figures "^2.0.0"
- pkg-conf "^2.1.0"
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.5"
+ object-inspect "^1.13.3"
+ side-channel-map "^1.0.1"
-sigstore@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.2.0.tgz#ae5b31dac75c2d31e7873897e2862f0d0b205bce"
- integrity sha512-Fr9+W1nkBSIZCkJQR7jDn/zI0UXNsVpp+7mDQkCnZOIxG9p6yNXBx9xntHsfUyYHE55XDkkVV3+rYbrkzAeesA==
+side-channel@^1.0.6, side-channel@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
+ integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
dependencies:
- "@sigstore/protobuf-specs" "^0.1.0"
- make-fetch-happen "^11.0.1"
- tuf-js "^1.0.0"
+ es-errors "^1.3.0"
+ object-inspect "^1.13.3"
+ side-channel-list "^1.0.0"
+ side-channel-map "^1.0.1"
+ side-channel-weakmap "^1.0.2"
+
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
sisteransi@^1.0.5:
version "1.0.5"
@@ -5928,33 +5805,6 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-slash@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
- integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
-
-smart-buffer@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
- integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
-
-socks-proxy-agent@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6"
- integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==
- dependencies:
- agent-base "^6.0.2"
- debug "^4.3.3"
- socks "^2.6.2"
-
-socks@^2.6.2:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
- integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
- dependencies:
- ip "^2.0.0"
- smart-buffer "^4.2.0"
-
source-map-support@0.5.13:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -5968,11 +5818,6 @@ source-map@^0.6.0, source-map@^0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-spawn-error-forwarder@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz#1afd94738e999b0346d7b9fc373be55e07577029"
- integrity sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==
-
spdx-correct@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
@@ -5999,24 +5844,10 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5"
integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==
-split2@^3.0.0, split2@^3.2.2:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
- integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
- dependencies:
- readable-stream "^3.0.0"
-
-split2@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/split2/-/split2-1.0.0.tgz#52e2e221d88c75f9a73f90556e263ff96772b314"
- integrity sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==
- dependencies:
- through2 "~2.0.0"
-
-split@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
- integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
+split@0.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
+ integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==
dependencies:
through "2"
@@ -6025,20 +5856,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
-ssri@^10.0.0, ssri@^10.0.1:
- version "10.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.1.tgz#c61f85894bbc6929fc3746f05e31cf5b44c030d5"
- integrity sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==
- dependencies:
- minipass "^4.0.0"
-
-ssri@^9.0.0:
- version "9.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057"
- integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==
- dependencies:
- minipass "^3.1.1"
-
stack-utils@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5"
@@ -6046,13 +5863,46 @@ stack-utils@^2.0.3:
dependencies:
escape-string-regexp "^2.0.0"
-stream-combiner2@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe"
- integrity sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==
+statuses@2.0.1, 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-combiner@~0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
+ integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==
+ dependencies:
+ duplexer "~0.1.1"
+
+stream-events@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5"
+ integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==
+ dependencies:
+ stubs "^3.0.0"
+
+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==
+
+strict-event-emitter@^0.2.4:
+ version "0.2.8"
+ resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz#b4e768927c67273c14c13d20e19d5e6c934b47ca"
+ integrity sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==
dependencies:
- duplexer2 "~0.1.0"
- readable-stream "^2.0.2"
+ events "^3.3.0"
+
+strict-event-emitter@^0.4.3:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz#ff347c8162b3e931e3ff5f02cfce6772c3b07eb3"
+ integrity sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==
+
+string-argv@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
+ integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
string-length@^4.0.1:
version "4.0.2"
@@ -6062,7 +5912,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
-"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+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==
@@ -6071,39 +5921,66 @@ string-length@^4.0.1:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string.prototype.matchall@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3"
- integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==
+string.prototype.matchall@^4.0.12:
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0"
+ integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.6"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.6"
+ gopd "^1.2.0"
+ has-symbols "^1.1.0"
+ internal-slot "^1.1.0"
+ regexp.prototype.flags "^1.5.3"
+ set-function-name "^2.0.2"
+ side-channel "^1.1.0"
+
+string.prototype.repeat@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a"
+ integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.20.4"
- get-intrinsic "^1.1.3"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- regexp.prototype.flags "^1.4.3"
- side-channel "^1.0.4"
-
-string.prototype.trimend@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
- integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+string.prototype.trim@^1.2.10:
+ version "1.2.10"
+ resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81"
+ integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ define-data-property "^1.1.4"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-object-atoms "^1.0.0"
+ has-property-descriptors "^1.0.2"
+
+string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942"
+ integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
-string.prototype.trimstart@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
- integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
+string.prototype.trimstart@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde"
+ integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==
dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
-string_decoder@^1.1.1, string_decoder@~1.1.1:
+string_decoder@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
@@ -6132,27 +6009,39 @@ strip-final-newline@^2.0.0:
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-strip-final-newline@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
- integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
-
-strip-indent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
- integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
- dependencies:
- min-indent "^1.0.0"
-
-strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+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==
-strip-json-comments@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
+stubs@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b"
+ integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==
+
+superagent@^9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/superagent/-/superagent-9.0.1.tgz#660773036c03728a1a88649a5d7e15d89b1d6961"
+ integrity sha512-CcRSdb/P2oUVaEpQ87w9Obsl+E9FruRd6b2b7LdiBtJoyMr2DQt7a89anAfiX/EL59j9b2CbRFvf2S91DhuCww==
+ dependencies:
+ component-emitter "^1.3.0"
+ cookiejar "^2.1.4"
+ debug "^4.3.4"
+ fast-safe-stringify "^2.1.1"
+ form-data "^4.0.0"
+ formidable "^3.5.1"
+ methods "^1.1.2"
+ mime "2.6.0"
+ qs "^6.11.0"
+ semver "^7.3.8"
+
+supertest@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/supertest/-/supertest-7.1.0.tgz#09b273174a8820e57ccdb03d9ca0d96c08c96b52"
+ integrity sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==
+ dependencies:
+ methods "^1.1.2"
+ superagent "^9.0.1"
supports-color@^5.3.0:
version "5.5.0"
@@ -6161,7 +6050,7 @@ supports-color@^5.3.0:
dependencies:
has-flag "^3.0.0"
-supports-color@^7.0.0, supports-color@^7.1.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==
@@ -6175,45 +6064,28 @@ supports-color@^8.0.0:
dependencies:
has-flag "^4.0.0"
-supports-hyperlinks@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624"
- integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==
- dependencies:
- has-flag "^4.0.0"
- supports-color "^7.0.0"
-
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-tar@^6.1.11, tar@^6.1.13, tar@^6.1.2:
- version "6.1.13"
- resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b"
- integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==
+teeny-request@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-9.0.0.tgz#18140de2eb6595771b1b02203312dfad79a4716d"
+ integrity sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==
dependencies:
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- minipass "^4.0.0"
- minizlib "^2.1.1"
- mkdirp "^1.0.3"
- yallist "^4.0.0"
-
-temp-dir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
- integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==
+ http-proxy-agent "^5.0.0"
+ https-proxy-agent "^5.0.0"
+ node-fetch "^2.6.9"
+ stream-events "^1.0.5"
+ uuid "^9.0.0"
-tempy@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/tempy/-/tempy-3.0.0.tgz#a6c0a15f5534a820e92c3e1369f1c1e87ebd6b68"
- integrity sha512-B2I9X7+o2wOaW4r/CWMkpOO9mdiTRCxXNgob6iGvPmfPWgH/KyUD6Uy5crtWBxIBe3YrNZKR2lSzv1JJKWD4vA==
+terminate@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/terminate/-/terminate-2.8.0.tgz#12f0315ba2e383f1b7a062a300417151819f458e"
+ integrity sha512-bcbjJEg0wY5nuJXvGxxHfmoEPkyHLCctUKO6suwtxy7jVSgGcgPeGwpbLDLELFhIaxCGRr3dPvyNg1yuz2V0eg==
dependencies:
- is-stream "^3.0.0"
- temp-dir "^2.0.0"
- type-fest "^2.12.2"
- unique-string "^3.0.0"
+ ps-tree "^1.2.0"
test-exclude@^6.0.0:
version "6.0.0"
@@ -6224,40 +6096,22 @@ test-exclude@^6.0.0:
glob "^7.1.4"
minimatch "^3.0.4"
-text-extensions@^1.0.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26"
- integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==
-
-text-table@^0.2.0, text-table@~0.2.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==
-through2@^4.0.0:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764"
- integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==
- dependencies:
- readable-stream "3"
-
-through2@~2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
- integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
- dependencies:
- readable-stream "~2.3.6"
- xtend "~4.0.1"
-
-through@2, "through@>=2.2.7 <3":
+through@2, through@^2.3.6, through@~2.3, through@~2.3.1:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
-tiny-relative-date@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
- integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
tmpl@1.0.5:
version "1.0.5"
@@ -6276,44 +6130,46 @@ to-regex-range@^5.0.1:
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==
+
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
-traverse@~0.6.6:
- version "0.6.7"
- resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe"
- integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==
-
-treeverse@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8"
- integrity sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==
+ts-api-utils@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
+ integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
-trim-newlines@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
- integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
+ts-api-utils@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd"
+ integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==
-ts-jest@^29.1.1:
- version "29.1.1"
- resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b"
- integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==
+ts-jest@^29.3.0:
+ version "29.3.0"
+ resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.3.0.tgz#8fc867616619dafeac150b818056badfe07708d5"
+ integrity sha512-4bfGBX7Gd1Aqz3SyeDS9O276wEU/BInZxskPrbhZLyv+c1wskDCqDFMJQJLWrIr/fKoAH4GE5dKUlrdyvo+39A==
dependencies:
- bs-logger "0.x"
- fast-json-stable-stringify "2.x"
+ bs-logger "^0.2.6"
+ ejs "^3.1.10"
+ fast-json-stable-stringify "^2.1.0"
jest-util "^29.0.0"
json5 "^2.2.3"
- lodash.memoize "4.x"
- make-error "1.x"
- semver "^7.5.3"
- yargs-parser "^21.0.1"
+ lodash.memoize "^4.1.2"
+ make-error "^1.3.6"
+ semver "^7.7.1"
+ type-fest "^4.37.0"
+ yargs-parser "^21.1.1"
-ts-node@^10.9.1:
- version "10.9.1"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
- integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
+ts-node@^10.9.2:
+ version "10.9.2"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f"
+ integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
@@ -6329,13 +6185,23 @@ ts-node@^10.9.1:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
-tsconfig-paths@^3.14.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
- integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
+tsc-watch@^6.2.1:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/tsc-watch/-/tsc-watch-6.2.1.tgz#861801be929b2fd3d597c5f608db2b7ddba503db"
+ integrity sha512-GLwdz5Dy9K3sVm3RzgkLcyDpl5cvU9HEcE1A3gf5rqEwlUe7gDLxNCgcuNEw3zoKOiegMo3LnbF1t6HLqxhrSA==
+ dependencies:
+ cross-spawn "^7.0.3"
+ node-cleanup "^2.1.2"
+ ps-tree "^1.2.0"
+ string-argv "^0.3.1"
+
+tsconfig-paths@^3.15.0:
+ version "3.15.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
+ integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
dependencies:
"@types/json5" "^0.0.29"
- json5 "^1.0.1"
+ json5 "^1.0.2"
minimist "^1.2.6"
strip-bom "^3.0.0"
@@ -6344,6 +6210,11 @@ tslib@^1.8.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+tslib@^2.1.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"
@@ -6351,14 +6222,6 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
-tuf-js@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-1.1.2.tgz#09ca04a89783b739e67dd796f6562e3940628aea"
- integrity sha512-gBfbnS6khluxjvoFCpRV0fhWT265xNfpiNXOcBX0Ze6HGbPhe93UG5V5DdKcgm/aXsMadnY76l/h6j63GmJS5g==
- dependencies:
- "@tufjs/models" "1.0.1"
- make-fetch-happen "^11.0.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"
@@ -6371,11 +6234,6 @@ type-detect@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.18.0:
- version "0.18.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
- integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
-
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@@ -6396,85 +6254,97 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-type-fest@^1.0.1, type-fest@^1.0.2:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
- integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
-
-type-fest@^2.0.0, type-fest@^2.12.2, type-fest@^2.5.0:
+type-fest@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
-type-fest@^3.12.0, type-fest@^3.8.0:
- version "3.13.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.0.tgz#b088347ae73779a750c461694b264340c4c8c0d7"
- integrity sha512-Gur3yQGM9qiLNs0KPP7LPgeRbio2QTt4xXouobMCarR0/wyW3F+F/+OWwshg3NG0Adon7uQfSZBpB46NfhoF1A==
-
-typescript@^5.1.6:
- version "5.1.6"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
- integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
-
-uglify-js@^3.1.4:
- version "3.17.4"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
- integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
+type-fest@^4.37.0:
+ version "4.38.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.38.0.tgz#659fa14d1a71c2811400aa3b5272627e0c1e6b96"
+ integrity sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==
-unbox-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
- integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
- dependencies:
- call-bind "^1.0.2"
- has-bigints "^1.0.2"
- has-symbols "^1.0.3"
- which-boxed-primitive "^1.0.2"
-
-unique-filename@^2.0.0:
+type-is@^2.0.0, type-is@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2"
- integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97"
+ integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==
dependencies:
- unique-slug "^3.0.0"
+ content-type "^1.0.5"
+ media-typer "^1.1.0"
+ mime-types "^3.0.0"
-unique-filename@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea"
- integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==
+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:
- unique-slug "^4.0.0"
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
-unique-slug@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9"
- integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==
+typed-array-buffer@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536"
+ integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==
dependencies:
- imurmurhash "^0.1.4"
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ is-typed-array "^1.1.14"
-unique-slug@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3"
- integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==
+typed-array-byte-length@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce"
+ integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==
dependencies:
- imurmurhash "^0.1.4"
+ call-bind "^1.0.8"
+ for-each "^0.3.3"
+ gopd "^1.2.0"
+ has-proto "^1.2.0"
+ is-typed-array "^1.1.14"
-unique-string@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a"
- integrity sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==
+typed-array-byte-offset@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355"
+ integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==
+ dependencies:
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.8"
+ for-each "^0.3.3"
+ gopd "^1.2.0"
+ has-proto "^1.2.0"
+ is-typed-array "^1.1.15"
+ reflect.getprototypeof "^1.0.9"
+
+typed-array-length@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d"
+ integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==
+ dependencies:
+ call-bind "^1.0.7"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ is-typed-array "^1.1.13"
+ possible-typed-array-names "^1.0.0"
+ reflect.getprototypeof "^1.0.6"
+
+typescript@*, typescript@^5.8.2:
+ version "5.8.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
+ integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
+
+unbox-primitive@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2"
+ integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==
dependencies:
- crypto-random-string "^4.0.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==
+ call-bound "^1.0.3"
+ has-bigints "^1.0.2"
+ has-symbols "^1.1.0"
+ which-boxed-primitive "^1.1.1"
-universalify@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
- integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+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"
@@ -6483,16 +6353,37 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-url-join@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/url-join/-/url-join-5.0.0.tgz#c2f1e5cbd95fa91082a93b58a1f42fecb4bdbcf1"
- integrity sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==
-
-util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+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==
+util@^0.12.3, util@^0.12.4:
+ version "0.12.5"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
+ integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
+ dependencies:
+ inherits "^2.0.3"
+ is-arguments "^1.0.4"
+ is-generator-function "^1.0.7"
+ is-typed-array "^1.1.3"
+ which-typed-array "^1.1.2"
+
+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==
+
+uuid@^8.0.0, uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+uuid@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
+ integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
+
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"
@@ -6507,7 +6398,7 @@ v8-to-istanbul@^9.0.1:
"@types/istanbul-lib-coverage" "^2.0.1"
convert-source-map "^1.6.0"
-validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4:
+validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
@@ -6515,32 +6406,24 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
-validate-npm-package-name@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713"
- integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==
- dependencies:
- builtins "^5.0.0"
-
-viem@^1.2.12:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.13.tgz#03d20066a12e32d2205d8a32ec4c5a00ed1e1f00"
- integrity sha512-BhBbL/JieVZvM1hiSvzoQCsj96j7HoOx/apvl4YYIR/0m/tue4JK/a03P1GKPJ9S316HEB/bT6AIJMlXS/SyiQ==
- dependencies:
- "@adraffy/ens-normalize" "1.9.0"
- "@noble/curves" "1.0.0"
- "@noble/hashes" "1.3.0"
- "@scure/bip32" "1.3.0"
- "@scure/bip39" "1.2.0"
- "@wagmi/chains" "1.2.0"
- abitype "0.8.11"
- isomorphic-ws "5.0.0"
- ws "8.12.0"
-
-walk-up-path@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e"
- integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==
+vary@^1, vary@^1.1.2, 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==
+
+viem@^2.23.2:
+ version "2.23.2"
+ resolved "https://registry.yarnpkg.com/viem/-/viem-2.23.2.tgz#db395c8cf5f4fb5572914b962fb8ce5db09f681c"
+ integrity sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==
+ dependencies:
+ "@noble/curves" "1.8.1"
+ "@noble/hashes" "1.7.1"
+ "@scure/bip32" "1.6.2"
+ "@scure/bip39" "1.5.4"
+ abitype "1.0.8"
+ isows "1.0.6"
+ ox "0.6.7"
+ ws "8.18.0"
walker@^1.0.8:
version "1.0.8"
@@ -6549,13 +6432,22 @@ walker@^1.0.8:
dependencies:
makeerror "1.0.12"
-wcwidth@^1.0.0:
+wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==
dependencies:
defaults "^1.0.3"
+web-encoding@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864"
+ integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==
+ dependencies:
+ util "^0.12.3"
+ optionalDependencies:
+ "@zxing/text-encoding" "0.9.0"
+
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
@@ -6569,43 +6461,65 @@ whatwg-url@^5.0.0:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
-which-boxed-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
- integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e"
+ integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==
dependencies:
- is-bigint "^1.0.1"
- is-boolean-object "^1.1.0"
- is-number-object "^1.0.4"
- is-string "^1.0.5"
- is-symbol "^1.0.3"
+ is-bigint "^1.1.0"
+ is-boolean-object "^1.2.1"
+ is-number-object "^1.1.1"
+ is-string "^1.1.1"
+ is-symbol "^1.1.1"
+
+which-builtin-type@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e"
+ integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==
+ dependencies:
+ call-bound "^1.0.2"
+ function.prototype.name "^1.1.6"
+ has-tostringtag "^1.0.2"
+ is-async-function "^2.0.0"
+ is-date-object "^1.1.0"
+ is-finalizationregistry "^1.1.0"
+ is-generator-function "^1.0.10"
+ is-regex "^1.2.1"
+ is-weakref "^1.0.2"
+ isarray "^2.0.5"
+ which-boxed-primitive "^1.1.0"
+ which-collection "^1.0.2"
+ which-typed-array "^1.1.16"
-which@^2.0.1, which@^2.0.2:
+which-collection@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0"
+ integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
+ dependencies:
+ is-map "^2.0.3"
+ is-set "^2.0.3"
+ is-weakmap "^2.0.2"
+ is-weakset "^2.0.3"
+
+which-typed-array@^1.1.16, which-typed-array@^1.1.18, which-typed-array@^1.1.2:
+ version "1.1.18"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad"
+ integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==
+ dependencies:
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ for-each "^0.3.3"
+ gopd "^1.2.0"
+ has-tostringtag "^1.0.2"
+
+which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
-which@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/which/-/which-3.0.0.tgz#a9efd016db59728758a390d23f1687b6e8f59f8e"
- integrity sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==
- dependencies:
- isexe "^2.0.0"
-
-wide-align@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
- integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
- dependencies:
- string-width "^1.0.2 || 2 || 3 || 4"
-
-wordwrap@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
- integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
-
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@@ -6628,23 +6542,10 @@ write-file-atomic@^4.0.2:
imurmurhash "^0.1.4"
signal-exit "^3.0.7"
-write-file-atomic@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.0.tgz#54303f117e109bf3d540261125c8ea5a7320fab0"
- integrity sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==
- dependencies:
- imurmurhash "^0.1.4"
- signal-exit "^3.0.7"
-
-ws@8.12.0:
- version "8.12.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8"
- integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==
-
-xtend@~4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+ws@8.18.0:
+ version "8.18.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"
+ integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
y18n@^5.0.5:
version "5.0.8"
@@ -6656,17 +6557,12 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yargs-parser@^20.2.3:
- 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.0.1, yargs-parser@^21.1.1:
+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@^17.3.1, yargs@^17.5.1, yargs@^17.7.2:
+yargs@^17.3.1, 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==
@@ -6689,7 +6585,7 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-yocto-queue@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
- integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
+zod@^3.24.2:
+ version "3.24.2"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.2.tgz#8efa74126287c675e92f46871cfc8d15c34372b3"
+ integrity sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==