diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..16d0b27b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,92 @@ +name: Test +on: + pull_request: + push: +env: + CARGO_TERM_COLOR: always +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: Install cargo nextest + uses: baptiste0928/cargo-install@v1 + with: + crate: cargo-nextest + locked: true + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + - name: Run tests + run: cargo nextest run + env: + # Enable sccache + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + check-formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + - name: Check formatting + run: cargo fmt --check + env: + # Enable sccache + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + cargo-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + - name: Cargo Check + run: cargo check --all + env: + # Enable sccache + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + clippy-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + - name: Clippy Check + run: cargo clippy --all + env: + # Enable sccache + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" \ No newline at end of file diff --git a/.gitignore b/.gitignore index e69de29b..fa4419bb 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,4 @@ +target +Cargo.lock +.idea +*.bkp \ No newline at end of file diff --git a/.vscode/rust.code-snippets b/.vscode/rust.code-snippets new file mode 100644 index 00000000..de97c2c6 --- /dev/null +++ b/.vscode/rust.code-snippets @@ -0,0 +1,17 @@ +{ + "Scrypto TestEnvironment Test": { + "prefix": ["ig-test"], + "body": [ + "#[test]", + "fn ${0:test_name}() -> Result<(), RuntimeError> {", + "\t// Arrange", + "\tlet Environment { environment: ref mut env, protocol, resources, ociswap, caviarnine } = Environment::new()?;", + "\t// Act", + "\t// Assert", + "", + "\tOk(())", + "}" + ], + "description": "The boilderplate code of a simple ignition test." + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 3905ae4c..2e06caaf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,23 @@ { - "editor.rulers": [80] + "editor.rulers": [ + 80 + ], + "[markdown]": { + "editor.wordWrap": "bounded", + "editor.wordWrapColumn": 80 + }, + "cSpell.words": [ + "caviarnine", + "coffieicnet", + "humantime", + "ociswap", + "OLYPS", + "ruid", + "uninit" + ], + // The gateway client directory is too large and slows down navigation + // to different files. Thus, we execlude it from search. + "search.exclude": { + "libraries/gateway-client/**/*.rs": true + } } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..13d13884 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,53 @@ +[workspace] +resolver = "2" +members = [ + # Packages + "packages/ignition", + "packages/simple-oracle", + "packages/ociswap-v1-adapter-v1", + "packages/ociswap-v2-adapter-v1", + "packages/caviarnine-v1-adapter-v1", + # Libraries + "libraries/common", + "libraries/package-loader", + "libraries/gateway-client", + "libraries/scrypto-interface", + "libraries/ports-interface", + "libraries/scrypto-math", + # Tools + "tools/bootstrap", + # Tests + "tests" +] + +[workspace.package] +version = "0.1.0" +edition = "2021" +description = "The implementation of project Ignition in Scrypto for the Radix Ledger" + +[workspace.dependencies] +sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +utils = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +transaction = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-common = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-stores = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-derive = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-queries = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-interface = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +radix-engine-store-interface = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } + +scrypto-unit = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } +scrypto-test = { git = "https://github.com/radixdlt/radixdlt-scrypto", rev = "ef169b1e1348b8dbad977ba81d086ee1e80d6ff8" } + +[profile.release] +opt-level = 'z' +lto = true +codegen-units = 1 +panic = 'abort' +strip = true +overflow-checks = true + +[workspace.lints.clippy] +arithmetic_side_effects = "warn" \ No newline at end of file diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 00000000..24d4c392 --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,41 @@ +[config] +default_to_workspace = false + +[tasks.test] +command = "cargo" +args = [ + "nextest", + "run", + "--features", + "package-loader/build-time-blueprints", + "--no-fail-fast", +] + +[tasks.check] +install_crate = "clippy" +command = "cargo" +args = ["clippy", "--all"] + +[tasks.format] +install_crate = "rustfmt" +command = "cargo" +args = ["fmt"] + +[tasks.fmt] +alias = "format" + +[tasks.publish-stokenet] +command = "cargo" +args = [ + "run", + "--package", + "bootstrapper", + "--", + "publish-test-to-stokenet", + "./frontend/public/config.json", + "./frontend/src/config.json", +] + +[tasks.frontend-start] +command = "npm" +args = ["start", "--prefix", "./frontend"] diff --git a/blueprints/.keep b/blueprints/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/diagrams/.keep b/diagrams/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/diagrams/caviarnine-basic.png b/diagrams/caviarnine-basic.png new file mode 100644 index 00000000..bcd05e63 Binary files /dev/null and b/diagrams/caviarnine-basic.png differ diff --git a/diagrams/caviarnine-price-increase.png b/diagrams/caviarnine-price-increase.png new file mode 100644 index 00000000..c8e72896 Binary files /dev/null and b/diagrams/caviarnine-price-increase.png differ diff --git a/diagrams/caviarnine.drawio b/diagrams/caviarnine.drawio new file mode 100644 index 00000000..9709d5ee --- /dev/null +++ b/diagrams/caviarnine.drawio @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..4d29575d --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..b87cb004 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 00000000..4fbbba45 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,18445 @@ +{ + "name": "frontend", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.1.0", + "dependencies": { + "@radixdlt/radix-dapp-toolkit": "^1.4.1", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.18.70", + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "bootstrap": "^5.3.2", + "gh-pages": "^6.1.1", + "react": "^18.2.0", + "react-bootstrap": "^2.9.2", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "rxjs": "^7.8.1", + "typescript": "^4.9.5", + "web-vitals": "^2.1.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", + "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz", + "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", + "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", + "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.7.tgz", + "integrity": "sha512-b1s5JyeMvqj7d9m9KhJNHKc18gEJiSyVzVX3bwbiPalQBQpuvfPh6lA9F7Kk/dWH0TIiXRpB9yicwijY6buPng==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.23.7", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-decorators": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz", + "integrity": "sha512-cf7Niq4/+/juY67E0PbgH0TDhLQ5J7zS8C/Q5FFx+DWyrRa9sUQdTXkjqKu8zGvuqr7vw1muKiukseihU+PJDA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz", + "integrity": "sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", + "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.23.3.tgz", + "integrity": "sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.23.3.tgz", + "integrity": "sha512-zP0QKq/p6O42OL94udMgSfKXyse4RyJ0JqbQ34zDAONWjyrEsghYEyTSK5FIpmXmCpB55SHokL1cRRKHv8L2Qw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", + "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", + "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", + "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@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.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "node_modules/@csstools/normalize.css": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.1.1.tgz", + "integrity": "sha512-YAYeJ+Xqh7fUou1d1j9XHl44BmsuThiTr4iNrgCQ3J27IbhXsxXDGZ1cXv8Qvs99d4rBbLiSKy3+WZiet32PcQ==" + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==" + }, + "node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", + "integrity": "sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==", + "dependencies": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@radixdlt/babylon-gateway-api-sdk": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radixdlt/babylon-gateway-api-sdk/-/babylon-gateway-api-sdk-1.2.5.tgz", + "integrity": "sha512-N1r5/gkYvzQ/5K9IQvA3SFjv1Iwrl2wv61X4FxrNeS6fjpYWvcrfUbZsjPHZFppzKO3wup5MueDxYmhMxz3iGg==" + }, + "node_modules/@radixdlt/connect-button": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radixdlt/connect-button/-/connect-button-1.0.3.tgz", + "integrity": "sha512-cQbl7wtxpc1yshgdpN3p4937iJ8SFkKp6vbktNeqjzO6IML8G6QwkeaU5gPTx58EvVh7ePnqFhfuYOlpZTlAtg==", + "dependencies": { + "lit": "^2.7.5" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@radixdlt/radix-dapp-toolkit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@radixdlt/radix-dapp-toolkit/-/radix-dapp-toolkit-1.4.1.tgz", + "integrity": "sha512-Tsp3DMqYHJOIO7US2MKs3ha4BOrAjIXu+2JyRtuV3hRcrMPtv3ty1KMYq3gX4E8EYEeUvThUbgLTcraz9n4e4A==", + "dependencies": { + "@radixdlt/babylon-gateway-api-sdk": "^1.2.0", + "@radixdlt/connect-button": "^1.0.3", + "@radixdlt/wallet-sdk": "1.0.1", + "immer": "^10.0.2", + "lodash.isequal": "^4.5.0", + "neverthrow": "^6.0.0", + "rxjs": "^7.8.1", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@radixdlt/radix-dapp-toolkit/node_modules/immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@radixdlt/wallet-sdk": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radixdlt/wallet-sdk/-/wallet-sdk-1.0.1.tgz", + "integrity": "sha512-g6TY1kUihJrECKBKs+dbTFrfzUU3bj1H2ySeaiHRNs/40eRH2Vw6heyb8DRHSkfhTzhPxXBzQxQdk908RgktUA==", + "dependencies": { + "neverthrow": "^6.0.0", + "rxjs": "^7.8.1", + "tslog": "^4.8.2", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.1.tgz", + "integrity": "sha512-NqzkLFP8ZVI4GSorS0AYljC13QW2sc8bDqJOkBvkAt3M8gbcAXJWVRGtZBCRscki9RZF+rNlnPdg0G0jYkhJcg==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.15.tgz", + "integrity": "sha512-cZFXYTxbpzYcieq/mBwSyXgqnGMHoBVh3J7MU0CCoIB4NRZxV9/TuwTBAaLMqpNhC3zTPMCgkQ5Ey07L02Xmcw==", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", + "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "peerDependencies": { + "react": ">=16.14.0" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz", + "integrity": "sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dependencies": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dependencies": { + "@babel/types": "^7.12.6" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dependencies": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", + "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "peer": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", + "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@testing-library/jest-dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", + "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.5.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", + "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/react/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/react/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/react/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/react/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/react/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@testing-library/react/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", + "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + }, + "node_modules/@types/node": { + "version": "16.18.70", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.70.tgz", + "integrity": "sha512-8eIk20G5VVVQNZNouHjLA2b8utE2NvGybLjMaF4lyhA9uhGwnmXF8o+icdXKGSQSNANJewXva/sFUoZLwAaYAg==" + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + }, + "node_modules/@types/q": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", + "integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==" + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + }, + "node_modules/@types/react": { + "version": "18.2.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", + "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", + "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", + "dependencies": { + "@types/jest": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", + "integrity": "sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "dependencies": { + "@typescript-eslint/utils": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dependencies": { + "@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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "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.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", + "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==" + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dependencies": { + "has-symbols": "^1.0.3" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "peerDependencies": { + "@babel/core": "^7.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz", + "integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.4", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", + "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz", + "integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bfj": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz", + "integrity": "sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==", + "dependencies": { + "bluebird": "^3.7.2", + "check-types": "^11.2.3", + "hoopy": "^0.1.4", + "jsonpath": "^1.1.1", + "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/bootstrap": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/check-types": { + "version": "11.2.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", + "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", + "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", + "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.35.0.tgz", + "integrity": "sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.9.0.tgz", + "integrity": "sha512-3I5Nu4ytWlHvOP6zItjiHlefBNtrH+oehq8tnQa2kO305qpVyx9XNIT1CXIj5bgCJs7qICBCkgCYxQLKPANoLA==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.31", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.1.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" + }, + "node_modules/cssdb": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.10.0.tgz", + "integrity": "sha512-yGZ5tmA57gWh/uvdQBHs45wwFY0IBh3ypABk5sEubPBPSzXzkNgsWReqx7gdx6uhC+QoFBe+V8JwBB9/hQ6cIA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/csso/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.630", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.630.tgz", + "integrity": "sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==" + }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "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-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", + "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.0.1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@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.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", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "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.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "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", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz", + "integrity": "sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==", + "dependencies": { + "@typescript-eslint/utils": "^5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gh-pages": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.1.1.tgz", + "integrity": "sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw==", + "dependencies": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^6.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gh-pages/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-pages/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/gh-pages/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/gh-pages/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "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" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "dependencies": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-watch-typeahead/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "dependencies": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, + "node_modules/jsonpath/node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-element": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz", + "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-html": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz", + "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.7", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.7.tgz", + "integrity": "sha512-+0n11YGyRavUR3IlaOzJ0/4Il1avMvJ1VJfhWfCn24ITQXhRr1gghbhhrda6tgtNcpZaWKdSuwKq20Jb7fnlyw==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/neverthrow": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/neverthrow/-/neverthrow-6.1.0.tgz", + "integrity": "sha512-xNbNjp/6M5vUV+mststgneJN9eJeJCDSYSBTaf3vxgvcKooP+8L0ATFpM8DGfmH7UWKJeoa24Qi33tBP9Ya3zA==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", + "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", + "dependencies": { + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "browserslist": ">=4", + "postcss": ">=8" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "peerDependencies": { + "postcss": "^8.1.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.0.tgz", + "integrity": "sha512-SaIbK8XW+MZbd0xHPf7kdfA/3eOt7vxJ72IRecn3EzuZVLr1r0orzf0MX/pN8m+NMDoo6X/SQd8oeKqGZd8PXg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "dependencies": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "browserslist": ">= 4", + "postcss": ">= 8" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/postcss-svgo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/prop-types-extra/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "dependencies": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-app-polyfill/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/react-bootstrap": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.9.2.tgz", + "integrity": "sha512-a36B+EHsAI/aH+ZhXNILBFnqscE3zr10dWmjBmfhIb2QR7KSXJiGzYd6Faf/25G8G7/CP9TCL2B0WhUBOD2UBQ==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.6", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-dev-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-dev-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/react-dev-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/react-dev-utils/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "dependencies": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "bin": { + "react-scripts": "bin/react-scripts.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + }, + "peerDependencies": { + "react": ">= 16", + "typescript": "^3.2.1 || ^4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=8.9" + }, + "peerDependencies": { + "rework": "1.0.1", + "rework-visit": "1.0.0" + }, + "peerDependenciesMeta": { + "rework": { + "optional": true + }, + "rework-visit": { + "optional": true + } + } + }, + "node_modules/resolve-url-loader/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/resolve-url-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "node_modules/static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "dependencies": { + "escodegen": "^1.8.1" + } + }, + "node_modules/static-eval/node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/static-eval/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/static-eval/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/static-eval/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/static-eval/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/static-eval/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-eval/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/svgo/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/svgo/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tslog": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.2.tgz", + "integrity": "sha512-wBM+LRJoNl34Bdu8mYEFxpvmOUedpNUwMNQB/NcuPIZKwdDde6xLHUev3bBjXQU7gdurX++X/YE7gLH8eXYsiQ==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/fullstack-build/tslog?sponsor=1" + } + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-vitals": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", + "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dependencies": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" + }, + "node_modules/workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "dependencies": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "dependencies": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "node_modules/workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" + }, + "node_modules/workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 00000000..8eb48b6a --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,54 @@ +{ + "name": "frontend", + "version": "0.1.0", + "private": true, + "homepage": "https://radixdlt.github.io/Ignition", + "dependencies": { + "@radixdlt/radix-dapp-toolkit": "^1.4.1", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.18.70", + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "bootstrap": "^5.3.2", + "gh-pages": "^6.1.1", + "react": "^18.2.0", + "react-bootstrap": "^2.9.2", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "rxjs": "^7.8.1", + "typescript": "^4.9.5", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject", + "predeploy": "npm run build", + "deploy": "gh-pages -d build" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "prettier": { + "printWidth": 80 + } +} diff --git a/frontend/public/config.json b/frontend/public/config.json new file mode 100644 index 00000000..bb67e984 --- /dev/null +++ b/frontend/public/config.json @@ -0,0 +1,65 @@ +{ + "network_id": 1, + "resources": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": { + "divisibility": 6, + "name": "USDT", + "symbol": "USDT", + "icon_url": "https://assets.instabridge.io/tokens/icons/xUSDT.png" + }, + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": { + "divisibility": 18, + "name": "Ethereum", + "symbol": "ETH", + "icon_url": "https://assets.instabridge.io/tokens/icons/xETH.png" + }, + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": { + "divisibility": 6, + "name": "USDC", + "symbol": "USDC", + "icon_url": "https://assets.instabridge.io/tokens/icons/xUSDC.png" + }, + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": { + "divisibility": 6, + "name": "Bitcoin", + "symbol": "BTC", + "icon_url": "https://assets.instabridge.io/tokens/icons/xwBTC.png" + } + }, + "protocol": { + "ignition_package_address": "package_rdx1pha09dtl3zmp4cjeurttsx52k3d2f2wu5nxlpdvvsupzsj3ekh04rp", + "ignition": "component_rdx1czwd54pv35dx8cgrt5p2gn52ryd98keep7slghhvwv2et5y79ml6uw", + "protocol_resource": "resource_rdx1t4dekrf58h0r28s3c93z92w3jt5ngx87jzd63mgc597zmf3534rxfv", + "oracle_package_address": "package_rdx1pkuzv0njgy4w30hyq8z8cs4t4mknx7flf0lv52gp56y93fyzkymy8n", + "oracle": "component_rdx1cq8k08lfvwfwd3qfmpfj6w6e2z2y9m9y72zyujrnxycg7885xnk8tc", + "dapp_definition": "account_rdx1cx9gtftg0lylun6jxglkgd0c9qnwe2j3p0kfg5us747nyfplzdz439", + "reward_rates": { + "0": "0.125", + "60": "0.15" + } + }, + "caviarnine": { + "package": "package_rdx1p4r9rkp0cq67wmlve544zgy0l45mswn6h798qdqm47x4762h383wa3", + "pools": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": "component_rdx1cqfszkwhtxm2wwl9puae9n833j8c5hrp9tasw9escun2nvkptj7ggz", + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": "component_rdx1cr7scefltr6y9ljknuctd9j2qdc9k53063p635xwlrk50msfksna6m", + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": "component_rdx1cpl4pf7sh766cnd6wjcwkc6tx54ze3qy4jf50d22wc2nuz54zzpa0q", + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": "component_rdx1crx32l52mep7j7jyljv2j9nfp983yakvm6qcydc7zwrp7tzlxdfkvk" + }, + "adapter_package": "package_rdx1p5dve4800m3tx65ns2qvqr4plgrjc5gkucwuwl62ezewtjz443xn6r", + "adapter": "component_rdx1cqddn4r9asgz36z27wzfd9848erm8cdh8j6j5t03clgl8ec59e0kez", + "receipt_resource": "resource_rdx1n2t8c52rdraa3wcehpckp8k9katl098gmrcyr59u7txv5t68w804cq" + }, + "ociswap": { + "package": "package_rdx1p5l6dp3slnh9ycd7gk700czwlck9tujn0zpdnd0efw09n2zdnn0lzx", + "pools": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": "component_rdx1cq96chge0q6kkk962heg0mgfl82gjw7x25dp9jv80gkx90mc3hk2ua", + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": "component_rdx1cqylpcl8p45l2h5ew0qrkwyz23dky3e6ucs7kkhrtm90k9z3kzeztn", + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": "component_rdx1cz3fa8qtfgfwjt3fzrtm544a89p5laerww7590g2tfcradqwdv3laq", + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": "component_rdx1cr5uxxjq4a0r3gfn6yd62lk96fqca34tnmyqdxkwefhckcjea4t3am" + }, + "adapter_package": "package_rdx1p5ds7ljdf26zdg6dsve764ksdz58ydegwjd24djcz034eepqrl7p8q", + "adapter": "component_rdx1czgd9jpdkaac6xwq6t5dc0hzvhggme4ahxeedma6p98ma3ylr7arz6", + "receipt_resource": "resource_rdx1n2n52tx9y2phac6tyfjncksmh6hpujgztunxrxyh8y92frzf8duzr2" + } +} \ No newline at end of file diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 00000000..a11777cc Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/index.html b/frontend/public/index.html new file mode 100644 index 00000000..a8570f2b --- /dev/null +++ b/frontend/public/index.html @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + Ignition + + + +
+ + + diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png new file mode 100644 index 00000000..fc44b0a3 Binary files /dev/null and b/frontend/public/logo192.png differ diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png new file mode 100644 index 00000000..a4e47a65 Binary files /dev/null and b/frontend/public/logo512.png differ diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 00000000..080d6c77 --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/frontend/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/src/App.css b/frontend/src/App.css new file mode 100644 index 00000000..74b5e053 --- /dev/null +++ b/frontend/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx new file mode 100644 index 00000000..9382b9ad --- /dev/null +++ b/frontend/src/App.test.tsx @@ -0,0 +1,8 @@ +import { render, screen } from "@testing-library/react"; +import App from "./App"; + +test("renders learn react link", () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 00000000..3cb4b618 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,79 @@ +import { useReducer } from "react"; +import "./App.css"; +import { CloseLiquidityPosition } from "./components/CloseLiquidityPosition"; + +import { OpenLiquidityPosition } from "./components/OpenLiquidityPosition"; +import { useConnectedAccounts } from "./hooks/ConnectedAccounts"; +import { useLastTransactionHash } from "./hooks/LastTransactionHash"; +import { MintUtility } from "./components/MintUtility"; + +declare global { + namespace JSX { + interface IntrinsicElements { + "radix-connect-button": React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLElement + >; + "radix-dapps-dropdown": React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLElement + >; + "radix-tabs-menu": React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLElement + >; + } + } +} + +function App() { + useConnectedAccounts(); + + const [lastTx, setLastTx] = useLastTransactionHash(); + + return ( + <> +
+ +
+
+

+ 🔥 Ignition +

+

+ Double your liquidity contributions and get protection from + impermanent loss. +

+ + {/* Main Body */} +
+
+ +
+ +
+ +
+
+
+ + ); +} + +export default App; diff --git a/frontend/src/BootstrapInformation.ts b/frontend/src/BootstrapInformation.ts new file mode 100644 index 00000000..c74e4fea --- /dev/null +++ b/frontend/src/BootstrapInformation.ts @@ -0,0 +1,36 @@ +import config from "./config.json" + +export const bootstrapInformation: TestingBootstrapInformation = config; + +export interface TestingBootstrapInformation { + network_id: number; + resources: Record; + protocol: ProtocolConfiguration; + caviarnine: DexEntities; + ociswap: DexEntities; +} + +export interface ProtocolConfiguration { + ignition_package_address: string; + ignition: string; + protocol_resource: string; + oracle_package_address: string; + oracle: string; + dapp_definition: string; + reward_rates: Record +} + +export interface DexEntities { + package: string; + pools: Record; + adapter_package: string; + adapter: string; + receipt_resource: string; +} + +export interface ResourceInformation { + divisibility: number; + name: string; + symbol: string; + icon_url: string; +} diff --git a/frontend/src/RadixDappToolkit.ts b/frontend/src/RadixDappToolkit.ts new file mode 100644 index 00000000..57e7c5f8 --- /dev/null +++ b/frontend/src/RadixDappToolkit.ts @@ -0,0 +1,18 @@ +import { + DataRequestBuilder, + RadixDappToolkit, +} from "@radixdlt/radix-dapp-toolkit"; +import { bootstrapInformation } from "./BootstrapInformation"; + +export const dAppToolkit: RadixDappToolkit = (() => { + const dappToolkit = RadixDappToolkit({ + networkId: bootstrapInformation.network_id, + dAppDefinitionAddress: bootstrapInformation.protocol.dapp_definition, + applicationName: "Ignition", + applicationVersion: "1.0.0", + }) + dappToolkit.walletApi.setRequestData( + DataRequestBuilder.accounts().exactly(1) + ); + return dappToolkit +})() diff --git a/frontend/src/components/CloseLiquidityPosition.tsx b/frontend/src/components/CloseLiquidityPosition.tsx new file mode 100644 index 00000000..30b2c0e4 --- /dev/null +++ b/frontend/src/components/CloseLiquidityPosition.tsx @@ -0,0 +1,285 @@ +import { + ProgrammaticScryptoSborValueTuple, + RadixDappToolkit, + StateNonFungibleDetailsResponseItem, +} from "@radixdlt/radix-dapp-toolkit"; +import { SUPPORTED_EXCHANGES } from "../constants"; +import { + DexEntities, + TestingBootstrapInformation, + bootstrapInformation, +} from "../BootstrapInformation"; +import { useConnectedAccounts } from "../hooks/ConnectedAccounts"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Button } from "react-bootstrap"; +import { dAppToolkit } from "../RadixDappToolkit"; + +export const CloseLiquidityPosition = (props: Props) => { + // Map> + const [state, setState] = useState< + Record> + >({}); + // Getting the state + const configuration = bootstrapInformation; + const connectedAccount = useConnectedAccounts(); + + useEffect(() => { + if (connectedAccount.status === "success") { + const accountAddress = connectedAccount.account; + + const liquidityReceiptResources = Object.entries(SUPPORTED_EXCHANGES).map( + ([logicalName, physicalName]): [string, string] => [ + ( + configuration[ + physicalName as keyof TestingBootstrapInformation + ] as DexEntities + ).receipt_resource, + logicalName, + ], + ); + + dAppToolkit.gatewayApi.state + .getEntityDetailsVaultAggregated(accountAddress) + .then((response) => response.non_fungible_resources.items) + .then(async (nonFungibles) => { + // Map> + let record: Record> = {}; + + const liquidityReceiptResourceAddresses = + liquidityReceiptResources.map(([address, _]) => address); + for (const item of nonFungibles) { + const resourceAddress = item.resource_address; + if (liquidityReceiptResourceAddresses.includes(resourceAddress)) { + const localIds = item.vaults.items + .map((item) => item.items || []) + .flat(); + + // Getting the data of the non-fungibles + const nonFungibleData = + await dAppToolkit.gatewayApi.state.getNonFungibleData( + resourceAddress, + localIds, + ); + + const data: Record = {}; + + for (const nftData of nonFungibleData) { + const localId = nftData.non_fungible_id; + + const receipt: LiquidityReceipt = { + name: getValue("name", nftData), + description: getValue("description", nftData), + keyImageUrl: getValue("key_image_url", nftData), + lockupPeriod: getValue("lockup_period", nftData), + redemptionUrl: getValue("redemption_url", nftData), + poolAddress: getValue("pool_address", nftData), + userResourceAddress: getValue( + "user_resource_address", + nftData, + ), + userContributionAmount: getValue( + "user_contribution_amount", + nftData, + ), + protocolContributionAmount: getValue( + "protocol_contribution_amount", + nftData, + ), + maturityTimestamp: getValue("maturity_date", nftData), + }; + + data[localId] = receipt; + } + + record[resourceAddress] = data; + } + } + + return record; + }) + .then(setState); + } + }, [connectedAccount, configuration, props.lastTx]); + + if (connectedAccount.status === "success") { + return ( +
+

+ {props.title || "Remove Liquidity"} +

+ + + + + + + + + + + + + {Object.entries(state).map(([liquidityResourceAddress, data]) => + Object.entries(data).map(([localId, receiptData]) => { + return ( + + + + + + + + ); + }), + )} + +
ExchangeResourceUser ContributionMaturity Date
+ { + Object.fromEntries( + Object.entries(SUPPORTED_EXCHANGES).map( + ([logicalName, physicalName]): [string, string] => [ + ( + configuration[ + physicalName as keyof TestingBootstrapInformation + ] as DexEntities + ).receipt_resource, + logicalName, + ], + ), + )[liquidityResourceAddress] + } + + { + configuration.resources[receiptData.userResourceAddress] + .name + } + {receiptData.userContributionAmount} + {new Date( + parseInt(receiptData.maturityTimestamp) * 1000, + ).toLocaleString()} + + +
+
+ ); + } else { + return ( +
+

+ {props.title || "Remove Liquidity"} +

+
+ ); + } +}; + +interface Props { + title?: string; + style?: React.CSSProperties; + /* Callbacks */ + onExchangeChange?: (newExchange?: string) => void; + onUserResourceChange?: (newResourceAddress?: string) => void; + onAmountChange?: (newAmount?: string) => void; + /* Last Tx */ + lastTx: string | null; + setLastTx: Dispatch>; +} + +interface LiquidityReceipt { + name: string; + description: string; + keyImageUrl: string; + lockupPeriod: string; + redemptionUrl: string; + poolAddress: string; + userResourceAddress: string; + userContributionAmount: string; + protocolContributionAmount: string; + maturityTimestamp: string; +} + +const getValue = ( + fieldName: string, + value: StateNonFungibleDetailsResponseItem, +): string => { + // @ts-ignore + return ( + value.data?.programmatic_json as ProgrammaticScryptoSborValueTuple + ).fields.find((item) => item.field_name === fieldName)["value"]; +}; + +const constructManifest = ( + connectedAccount: string, + ignitionAddress: string, + liquidityReceipt: string, + localId: string, +): string => { + return ` + CALL_METHOD + Address("${connectedAccount}") + "withdraw_non_fungibles" + Address("${liquidityReceipt}") + Array( + NonFungibleLocalId("${localId}") + ) + ; + + TAKE_NON_FUNGIBLES_FROM_WORKTOP + Address("${liquidityReceipt}") + Array( + NonFungibleLocalId("${localId}") + ) + Bucket("bucket") + ; + + CALL_METHOD + Address("${ignitionAddress}") + "close_liquidity_position" + Bucket("bucket") + ; + + CALL_METHOD + Address("${connectedAccount}") + "try_deposit_batch_or_abort" + Expression("ENTIRE_WORKTOP") + None + ; + `; +}; + +const constructAndSendManifestToWallet = ( + dAppToolkit: RadixDappToolkit, + connectedAccount: string, + ignitionAddress: string, + liquidityReceipt: string, + localId: string, + setLastTxHash: Dispatch>, +) => { + const manifest = constructManifest( + connectedAccount, + ignitionAddress, + liquidityReceipt, + localId, + ); + console.log(manifest); + dAppToolkit.walletApi + .sendTransaction({ transactionManifest: manifest }) + .map((item) => setLastTxHash(item.transactionIntentHash)); +}; diff --git a/frontend/src/components/MintUtility.tsx b/frontend/src/components/MintUtility.tsx new file mode 100644 index 00000000..310f97f8 --- /dev/null +++ b/frontend/src/components/MintUtility.tsx @@ -0,0 +1,113 @@ +import Container from "react-bootstrap/Container"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import Form from "react-bootstrap/Form"; +import { Button } from "react-bootstrap"; + +import { + DexEntities, + TestingBootstrapInformation, + bootstrapInformation, +} from "../BootstrapInformation"; +import { + ConnectedAccount, + useConnectedAccounts, +} from "../hooks/ConnectedAccounts"; +import { RadixDappToolkit } from "@radixdlt/radix-dapp-toolkit"; +import { SUPPORTED_EXCHANGES } from "../constants"; +import { dAppToolkit } from "../RadixDappToolkit"; +import { Dispatch, SetStateAction } from "react"; + +const NO_X_AXIS_BORDERS_CLASS_NAME: string = "mx-0 px-0"; + +export const MintUtility = (props: Props) => { + const connectedAccount = useConnectedAccounts(); + + const isAccountConnected = connectedAccount.status === "success"; + + if (connectedAccount.status === "success") { + return ( +
+

+ {props.title || "Mint Utility"} +

+ +
+ {[ + [bootstrapInformation.protocol.protocol_resource, "XRD"], + ...Object.entries(bootstrapInformation.resources).map( + ([address, information]) => [address, information.symbol], + ), + ].map(([resourceAddress, symbol]) => ( + + ))} +
+
+ ); + } else { + return ( +
+

+ {props.title || "Mint Utility"} +

+ +
+ {[ + [bootstrapInformation.protocol.protocol_resource, "XRD"], + ...Object.entries(bootstrapInformation.resources).map( + ([address, information]) => [address, information.symbol], + ), + ].map(([resourceAddress, symbol]) => ( + + ))} +
+
+ ); + } +}; + +interface Props { + title?: string; + style?: React.CSSProperties; +} + +const constructManifest = ( + connectedAccount: string, + resourceAddress: string, +): string => { + return ` + MINT_FUNGIBLE + Address("${resourceAddress}") + Decimal("100000000000") + ; + + CALL_METHOD + Address("${connectedAccount}") + "try_deposit_batch_or_abort" + Expression("ENTIRE_WORKTOP") + None + ; + `; +}; + +const constructAndSendManifestToWallet = ( + connectedAccount: string, + resourceAddress: string, +) => { + const manifest = constructManifest(connectedAccount, resourceAddress); + console.log(manifest); + dAppToolkit.walletApi.sendTransaction({ transactionManifest: manifest }); +}; diff --git a/frontend/src/components/OpenLiquidityPosition.tsx b/frontend/src/components/OpenLiquidityPosition.tsx new file mode 100644 index 00000000..59fa80b3 --- /dev/null +++ b/frontend/src/components/OpenLiquidityPosition.tsx @@ -0,0 +1,345 @@ +import Container from "react-bootstrap/Container"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import Form from "react-bootstrap/Form"; +import { Button } from "react-bootstrap"; + +import { + DexEntities, + TestingBootstrapInformation, + bootstrapInformation, +} from "../BootstrapInformation"; +import { + OpenLiquidityPositionData, + useOpenLiquidityPositionData, +} from "../hooks/OpenLiquidityPositionData"; +import { + ConnectedAccount, + useConnectedAccounts, +} from "../hooks/ConnectedAccounts"; +import { RadixDappToolkit } from "@radixdlt/radix-dapp-toolkit"; +import { SUPPORTED_EXCHANGES } from "../constants"; +import { dAppToolkit } from "../RadixDappToolkit"; +import { Dispatch, SetStateAction } from "react"; + +const NO_X_AXIS_BORDERS_CLASS_NAME: string = "mx-0 px-0"; + +export const OpenLiquidityPosition = (props: Props) => { + const [openLiquidityPositionData, setOpenLiquidityPositionData] = + useOpenLiquidityPositionData(); + + const connectedAccount = useConnectedAccounts(); + + const allDataDefined = !Object.entries(openLiquidityPositionData).some( + ([_, v]) => v === undefined, + ); + const isAccountConnected = connectedAccount.status === "success"; + + return ( +
+

+ {props.title || "Provide Liquidity"} +

+ + + + +
Exchange
+ + +
User Resource
+ + +
Lockup Period
+ + +
Amount
+ + +
+ + + { + const selectedValue = event.target.value; + const evaluatedValue = + selectedValue === "none" ? undefined : selectedValue; + + // Set the state + setOpenLiquidityPositionData({ + ...openLiquidityPositionData, + exchange: evaluatedValue, + }); + + // Fire an event + if (props.onExchangeChange !== undefined) { + props.onExchangeChange(evaluatedValue); + } + }} + > + + {Object.entries(SUPPORTED_EXCHANGES).map( + ([logicalName, physicalName]) => { + return ( + + ); + }, + )} + + + + { + const selectedValue = event.target.value; + const evaluatedValue = + selectedValue === "none" ? undefined : selectedValue; + + // Set the state + setOpenLiquidityPositionData({ + ...openLiquidityPositionData, + resourceAddress: evaluatedValue, + }); + + // Fire an event + if (props.onUserResourceChange !== undefined) { + props.onUserResourceChange(evaluatedValue); + } + }} + > + + {Object.entries(bootstrapInformation?.resources || {}).map( + ([address, information]) => { + return ( + + ); + }, + )} + + + + { + const selectedValue = event.target.value; + const evaluatedValue = + selectedValue === "none" ? undefined : selectedValue; + + // Set the state + setOpenLiquidityPositionData({ + ...openLiquidityPositionData, + lockupPeriodSeconds: evaluatedValue, + }); + + // Fire an event + if (props.onUserResourceChange !== undefined) { + props.onUserResourceChange(evaluatedValue); + } + }} + > + + {Object.entries( + bootstrapInformation?.protocol.reward_rates || {}, + ).map(([periodInSeconds, percentage]) => { + return ( + + ); + })} + + + + + { + // Remove anything that is not a number + let numbers = Array.from({ length: 10 }, (_, i) => + i.toString(), + ); + let string = Array.from(event.target.value).filter((char) => + numbers.includes(char), + ); + + // Add the comma separator + const evaluatedValue = string.join(""); + event.target.value = evaluatedValue + .toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ","); + + // Set the state + setOpenLiquidityPositionData({ + ...openLiquidityPositionData, + amount: evaluatedValue, + }); + + // Fire an event + if (props.onAmountChange !== undefined) { + props.onAmountChange(evaluatedValue); + } + }} + /> + + + + + + +
+
+ ); +}; + +interface Props { + title?: string; + style?: React.CSSProperties; + /* Callbacks */ + onExchangeChange?: (newExchange?: string) => void; + onUserResourceChange?: (newResourceAddress?: string) => void; + onAmountChange?: (newAmount?: string) => void; + /* Last Tx */ + lastTx: string | null; + setLastTx: Dispatch>; +} + +const constructManifest = ( + ignitionAddress: string, + connectedAccount: string, + selections: { + pool: string; + resourceAddress: string; + amount: string; + lockupPeriodInSeconds: string; + }, +): string => { + return ` + MINT_FUNGIBLE + Address("${selections.resourceAddress}") + Decimal("${selections.amount}") + ; + + TAKE_FROM_WORKTOP + Address("${selections.resourceAddress}") + Decimal("${selections.amount}") + Bucket("bucket") + ; + + CALL_METHOD + Address("${ignitionAddress}") + "open_liquidity_position" + Bucket("bucket") + Address("${selections.pool}") + ${selections.lockupPeriodInSeconds}u64 + ; + + CALL_METHOD + Address("${connectedAccount}") + "try_deposit_batch_or_abort" + Expression("ENTIRE_WORKTOP") + None + ; + `; +}; + +const constructAndSendManifestToWallet = ( + dAppToolkit: RadixDappToolkit, + ignitionAddress: string, + connectedAccount: string, + selections: { + pool: string; + resourceAddress: string; + amount: string; + lockupPeriodInSeconds: string; + }, + setLastTxHash: Dispatch>, +) => { + const manifest = constructManifest( + ignitionAddress, + connectedAccount, + selections, + ); + console.log(manifest); + dAppToolkit.walletApi + .sendTransaction({ transactionManifest: manifest }) + .map((item) => item.transactionIntentHash) + .map(setLastTxHash); +}; + +const highLevelConstructAndSendManifestToWallet = ( + dAppToolkit: RadixDappToolkit | undefined, + bootstrapInformation: TestingBootstrapInformation | null, + connectedAccount: ConnectedAccount, + selectedInformation: OpenLiquidityPositionData, + setLastTxHash: Dispatch>, +) => { + if ( + selectedInformation.amount !== undefined && + selectedInformation.exchange !== undefined && + selectedInformation.resourceAddress !== undefined && + selectedInformation.lockupPeriodSeconds !== undefined && + bootstrapInformation !== null && + dAppToolkit !== undefined && + connectedAccount.status === "success" + ) { + const exchangePhysicalName = + selectedInformation.exchange as keyof TestingBootstrapInformation; + + const exchangeEntries = bootstrapInformation[ + exchangePhysicalName + ] as DexEntities; + + const ignitionAddress = bootstrapInformation.protocol.ignition; + const account = connectedAccount.account; + + const poolAddress = + exchangeEntries.pools[selectedInformation.resourceAddress]; + + constructAndSendManifestToWallet( + dAppToolkit, + ignitionAddress, + account, + { + pool: poolAddress, + resourceAddress: selectedInformation.resourceAddress, + amount: selectedInformation.amount, + lockupPeriodInSeconds: selectedInformation.lockupPeriodSeconds, + }, + setLastTxHash, + ); + } else { + console.error( + "Something was undefined when attempting to construct and send the transaction", + ); + } +}; diff --git a/frontend/src/config.json b/frontend/src/config.json new file mode 100644 index 00000000..bb67e984 --- /dev/null +++ b/frontend/src/config.json @@ -0,0 +1,65 @@ +{ + "network_id": 1, + "resources": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": { + "divisibility": 6, + "name": "USDT", + "symbol": "USDT", + "icon_url": "https://assets.instabridge.io/tokens/icons/xUSDT.png" + }, + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": { + "divisibility": 18, + "name": "Ethereum", + "symbol": "ETH", + "icon_url": "https://assets.instabridge.io/tokens/icons/xETH.png" + }, + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": { + "divisibility": 6, + "name": "USDC", + "symbol": "USDC", + "icon_url": "https://assets.instabridge.io/tokens/icons/xUSDC.png" + }, + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": { + "divisibility": 6, + "name": "Bitcoin", + "symbol": "BTC", + "icon_url": "https://assets.instabridge.io/tokens/icons/xwBTC.png" + } + }, + "protocol": { + "ignition_package_address": "package_rdx1pha09dtl3zmp4cjeurttsx52k3d2f2wu5nxlpdvvsupzsj3ekh04rp", + "ignition": "component_rdx1czwd54pv35dx8cgrt5p2gn52ryd98keep7slghhvwv2et5y79ml6uw", + "protocol_resource": "resource_rdx1t4dekrf58h0r28s3c93z92w3jt5ngx87jzd63mgc597zmf3534rxfv", + "oracle_package_address": "package_rdx1pkuzv0njgy4w30hyq8z8cs4t4mknx7flf0lv52gp56y93fyzkymy8n", + "oracle": "component_rdx1cq8k08lfvwfwd3qfmpfj6w6e2z2y9m9y72zyujrnxycg7885xnk8tc", + "dapp_definition": "account_rdx1cx9gtftg0lylun6jxglkgd0c9qnwe2j3p0kfg5us747nyfplzdz439", + "reward_rates": { + "0": "0.125", + "60": "0.15" + } + }, + "caviarnine": { + "package": "package_rdx1p4r9rkp0cq67wmlve544zgy0l45mswn6h798qdqm47x4762h383wa3", + "pools": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": "component_rdx1cqfszkwhtxm2wwl9puae9n833j8c5hrp9tasw9escun2nvkptj7ggz", + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": "component_rdx1cr7scefltr6y9ljknuctd9j2qdc9k53063p635xwlrk50msfksna6m", + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": "component_rdx1cpl4pf7sh766cnd6wjcwkc6tx54ze3qy4jf50d22wc2nuz54zzpa0q", + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": "component_rdx1crx32l52mep7j7jyljv2j9nfp983yakvm6qcydc7zwrp7tzlxdfkvk" + }, + "adapter_package": "package_rdx1p5dve4800m3tx65ns2qvqr4plgrjc5gkucwuwl62ezewtjz443xn6r", + "adapter": "component_rdx1cqddn4r9asgz36z27wzfd9848erm8cdh8j6j5t03clgl8ec59e0kez", + "receipt_resource": "resource_rdx1n2t8c52rdraa3wcehpckp8k9katl098gmrcyr59u7txv5t68w804cq" + }, + "ociswap": { + "package": "package_rdx1p5l6dp3slnh9ycd7gk700czwlck9tujn0zpdnd0efw09n2zdnn0lzx", + "pools": { + "resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s": "component_rdx1cq96chge0q6kkk962heg0mgfl82gjw7x25dp9jv80gkx90mc3hk2ua", + "resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm": "component_rdx1cqylpcl8p45l2h5ew0qrkwyz23dky3e6ucs7kkhrtm90k9z3kzeztn", + "resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf": "component_rdx1cz3fa8qtfgfwjt3fzrtm544a89p5laerww7590g2tfcradqwdv3laq", + "resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8": "component_rdx1cr5uxxjq4a0r3gfn6yd62lk96fqca34tnmyqdxkwefhckcjea4t3am" + }, + "adapter_package": "package_rdx1p5ds7ljdf26zdg6dsve764ksdz58ydegwjd24djcz034eepqrl7p8q", + "adapter": "component_rdx1czgd9jpdkaac6xwq6t5dc0hzvhggme4ahxeedma6p98ma3ylr7arz6", + "receipt_resource": "resource_rdx1n2n52tx9y2phac6tyfjncksmh6hpujgztunxrxyh8y92frzf8duzr2" + } +} \ No newline at end of file diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts new file mode 100644 index 00000000..5f2ce5eb --- /dev/null +++ b/frontend/src/constants.ts @@ -0,0 +1,5 @@ +/// Logical Name => Physical Name +export const SUPPORTED_EXCHANGES: Record = { + Caviarnine: "caviarnine", + Ociswap: "ociswap", +}; \ No newline at end of file diff --git a/frontend/src/hooks/ConnectedAccounts.ts b/frontend/src/hooks/ConnectedAccounts.ts new file mode 100644 index 00000000..bb4d4aa1 --- /dev/null +++ b/frontend/src/hooks/ConnectedAccounts.ts @@ -0,0 +1,33 @@ +import { useState, useEffect } from 'react'; +import { switchMap, map } from 'rxjs' +import { dAppToolkit } from '../RadixDappToolkit'; + +export const useConnectedAccounts = () => { + const [state, setState] = useState({ status: 'pending' }) + + useEffect(() => { + const subscription = dAppToolkit.walletApi.walletData$ + .pipe( + map((walletData) => walletData.accounts), + switchMap((accounts) => { + if (accounts?.[0]?.address !== undefined) { + setState({ status: 'success', account: accounts?.[0]?.address }) + } + + return accounts + }) + ) + .subscribe() + + return () => { + subscription.unsubscribe() + } + }, [dAppToolkit]) + + return state +} + +export type ConnectedAccount = + { status: 'success', account: string } + | { status: 'pending' } + | { status: 'error' } diff --git a/frontend/src/hooks/LastTransactionHash.ts b/frontend/src/hooks/LastTransactionHash.ts new file mode 100644 index 00000000..4f577ffb --- /dev/null +++ b/frontend/src/hooks/LastTransactionHash.ts @@ -0,0 +1,5 @@ +import { useState } from "react" + +export const useLastTransactionHash = () => { + return useState(null); +} \ No newline at end of file diff --git a/frontend/src/hooks/OpenLiquidityPositionData.ts b/frontend/src/hooks/OpenLiquidityPositionData.ts new file mode 100644 index 00000000..8a5a8ae6 --- /dev/null +++ b/frontend/src/hooks/OpenLiquidityPositionData.ts @@ -0,0 +1,17 @@ +import { useState } from "react"; + +export const useOpenLiquidityPositionData = () => { + return useState({ + exchange: undefined, + resourceAddress: undefined, + amount: undefined, + lockupPeriodSeconds: undefined + }); +}; + +export interface OpenLiquidityPositionData { + exchange: string | undefined; + resourceAddress: string | undefined; + amount: string | undefined; + lockupPeriodSeconds: string | undefined +} diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 00000000..f62968f0 --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,31 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: "Iosevka", source-code-pro, Menlo, Monaco, Consolas, + "Courier New", monospace; +} + +.iosevka { + font-family: "Iosevka"; +} + +.ibm-plex-sans { + font-family: "Ibm Plex Sans"; +} + +#ignition-root { + background-color: white; + height: 100vh; + width: 100vw; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx new file mode 100644 index 00000000..ccbac81f --- /dev/null +++ b/frontend/src/index.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; + +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement +); +root.render( + + + +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/frontend/src/logo.svg b/frontend/src/logo.svg new file mode 100644 index 00000000..9dfc1c05 --- /dev/null +++ b/frontend/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/react-app-env.d.ts b/frontend/src/react-app-env.d.ts new file mode 100644 index 00000000..6431bc5f --- /dev/null +++ b/frontend/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/src/reportWebVitals.ts b/frontend/src/reportWebVitals.ts new file mode 100644 index 00000000..5fa3583b --- /dev/null +++ b/frontend/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from "web-vitals"; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/frontend/src/setupTests.ts b/frontend/src/setupTests.ts new file mode 100644 index 00000000..1dd407a6 --- /dev/null +++ b/frontend/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import "@testing-library/jest-dom"; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 00000000..9d379a3c --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"] +} diff --git a/libraries/common/Cargo.toml b/libraries/common/Cargo.toml new file mode 100644 index 00000000..3140d6bf --- /dev/null +++ b/libraries/common/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "common" +version.workspace = true +edition.workspace = true +description = "A crate that defines types used by the other crates." + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +transaction = { workspace = true, optional = true } +radix-engine-common = { workspace = true } +radix-engine-derive = { workspace = true } +radix-engine-interface = { workspace = true } + +# Used to print the lockup period in a readable format. +humantime = { version = "2.1.0" } + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/libraries/common/src/any_value.rs b/libraries/common/src/any_value.rs new file mode 100644 index 00000000..2c8e5997 --- /dev/null +++ b/libraries/common/src/any_value.rs @@ -0,0 +1,61 @@ +use radix_engine_interface::prelude::*; + +#[derive(Clone, Debug, ScryptoSbor, PartialEq, Eq)] +#[sbor(transparent)] +pub struct AnyValue((ScryptoValue,)); + +impl AnyValue { + pub fn from_typed(typed: &T) -> Result + where + T: ScryptoEncode, + { + scrypto_encode(typed) + .map_err(Into::into) + .and_then(|value| scrypto_decode(&value).map_err(Into::into)) + .map(|value| Self((value,))) + } + + pub fn as_typed(&self) -> Result + where + T: ScryptoDecode, + { + scrypto_encode(&self.0 .0) + .map_err(Into::into) + .and_then(|value| scrypto_decode(&value).map_err(Into::into)) + } +} + +#[derive(Clone, Debug)] +pub enum AnyValueError { + EncodeError(EncodeError), + DecodeError(DecodeError), +} + +impl From for AnyValueError { + fn from(value: EncodeError) -> Self { + Self::EncodeError(value) + } +} + +impl From for AnyValueError { + fn from(value: DecodeError) -> Self { + Self::DecodeError(value) + } +} + +#[cfg(test)] +mod test { + use super::AnyValue; + + #[test] + fn simple_roundtrip_test() { + // Arrange + let value = 12; + + // Act + let any_value = AnyValue::from_typed(&value).unwrap(); + + // Assert + assert_eq!(any_value.as_typed::().unwrap(), value) + } +} diff --git a/libraries/common/src/lib.rs b/libraries/common/src/lib.rs new file mode 100644 index 00000000..2965da90 --- /dev/null +++ b/libraries/common/src/lib.rs @@ -0,0 +1,7 @@ +mod any_value; +mod liquidity_receipt; +mod lockup_period; +mod price; +mod volatility; + +pub mod prelude; diff --git a/libraries/common/src/liquidity_receipt.rs b/libraries/common/src/liquidity_receipt.rs new file mode 100644 index 00000000..5994503e --- /dev/null +++ b/libraries/common/src/liquidity_receipt.rs @@ -0,0 +1,79 @@ +use crate::prelude::*; +use scrypto::prelude::*; + +/// The data of the liquidity positions given to the users of Ignition. +#[derive(ScryptoSbor, Clone, Debug, PartialEq, Eq, NonFungibleData)] +pub struct LiquidityReceipt +where + T: ScryptoSbor, +{ + /* Metadata/NonFungibleData standard */ + pub name: String, + + /* Display Data - Just for wallet display, no logic depends on this. */ + /// A string of the lockup period of the liquidity provided through the + /// protocol (e.g., "6 Months"). + pub lockup_period: String, + + /* Application data */ + /// The pool that the resources were contributed to. + pub pool_address: ComponentAddress, + + /// The address of the resource that the user contributed through the + /// protocol. + pub user_resource_address: ResourceAddress, + + /// The amount of the resource that the user contributed through the + /// protocol. + pub user_contribution_amount: Decimal, + + /// The volatility classification of the user resource at the time when the + /// liquidity position was opened. This will be used to later deposit any + /// protocol assets back into the same vault. + pub user_resource_volatility_classification: Volatility, + + /// The amount of XRD that was contributed by the Ignition protocol to + /// match the users contribution. + pub protocol_contribution_amount: Decimal, + + /// The date after which this liquidity position can be closed. + pub maturity_date: Instant, + + /// This is adapter specific data passed by the adapter when a position is + /// opened. This is information that the adapter expects to be passed back + /// when a liquidity position is closed. This is used in calculating the + /// fees. + pub adapter_specific_information: T, +} + +impl LiquidityReceipt +where + T: ScryptoSbor, +{ + pub fn new( + lockup_period: LockupPeriod, + pool_address: ComponentAddress, + user_resource_address: ResourceAddress, + user_contribution_amount: Decimal, + user_volatility_classification: Volatility, + protocol_contribution_amount: Decimal, + adapter_specific_information: T, + ) -> Self { + let maturity_date = Clock::current_time_rounded_to_minutes() + .add_seconds(*lockup_period.seconds() as i64) + .unwrap(); + + Self { + name: "Liquidity Contribution".to_owned(), + lockup_period: lockup_period.to_string(), + pool_address, + user_resource_address, + user_contribution_amount, + maturity_date, + protocol_contribution_amount, + user_resource_volatility_classification: + user_volatility_classification, + adapter_specific_information, + } + } +} diff --git a/libraries/common/src/lockup_period.rs b/libraries/common/src/lockup_period.rs new file mode 100644 index 00000000..e8a2e54c --- /dev/null +++ b/libraries/common/src/lockup_period.rs @@ -0,0 +1,81 @@ +use scrypto::prelude::*; +use std::ops::*; + +use humantime::format_duration; + +/// A type used for the lockup period that can be creates from various time +/// durations and that implements display in the desired way. +#[derive(Clone, Copy, Sbor, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[sbor(transparent)] +pub struct LockupPeriod(u64); + +impl LockupPeriod { + pub const fn from_seconds(seconds: u64) -> Self { + Self(seconds) + } + + pub const fn from_minutes(minutes: u64) -> Option { + let value = minutes.checked_mul(60); + match value { + Some(value) => Some(Self::from_seconds(value)), + None => None, + } + } + + pub const fn from_hours(hours: u64) -> Option { + let value = hours.checked_mul(60); + match value { + Some(value) => Self::from_minutes(value), + None => None, + } + } + + pub const fn from_days(days: u64) -> Option { + let value = days.checked_mul(24); + match value { + Some(value) => Self::from_hours(value), + None => None, + } + } + + pub const fn from_weeks(weeks: u64) -> Option { + let value = weeks.checked_mul(7); + match value { + Some(value) => Self::from_days(value), + None => None, + } + } + + // One month approx 30.44 days + pub const fn from_months(months: u64) -> Option { + let value = months.checked_mul(2_630_016); + match value { + Some(value) => Some(Self::from_seconds(value)), + None => None, + } + } + + pub const fn seconds(&self) -> &u64 { + &self.0 + } +} + +impl Display for LockupPeriod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&format_duration(std::time::Duration::new(self.0, 0)), f) + } +} + +impl Debug for LockupPeriod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} seconds", self.0) + } +} + +impl Deref for LockupPeriod { + type Target = u64; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/libraries/common/src/prelude.rs b/libraries/common/src/prelude.rs new file mode 100644 index 00000000..d9383b20 --- /dev/null +++ b/libraries/common/src/prelude.rs @@ -0,0 +1,5 @@ +pub use crate::any_value::*; +pub use crate::liquidity_receipt::*; +pub use crate::lockup_period::*; +pub use crate::price::*; +pub use crate::volatility::*; diff --git a/libraries/common/src/price.rs b/libraries/common/src/price.rs new file mode 100644 index 00000000..18e9c38f --- /dev/null +++ b/libraries/common/src/price.rs @@ -0,0 +1,234 @@ +use radix_engine_derive::*; +use scrypto::prelude::*; + +/// A price type representing the price in terms of some base and quote assets. +/// +/// The information of the base and quote assets is captured by this type to +/// make certain calculations easier and to also allow for some checks to make +/// sure that an incorrect price is not used for calculations. +#[derive(Clone, Copy, Debug, PartialEq, Eq, ScryptoSbor)] +pub struct Price { + pub base: ResourceAddress, + pub quote: ResourceAddress, + pub price: Decimal, +} + +impl Price { + /// Computes the difference ratio between `self` and `other`. + /// + /// Attempts to compute the difference ratio between the two prices: `self` + /// and `other`. If the base and the quote are different then a inverse of + /// the price is used to calculate the difference. A [`None`] is returned if + /// `other` has a base or quote resource address that is neither the base + /// nor the quote of `self`. + /// + /// The equation used for the ratio calculation is obtained from this + /// [article] can is provided below: + /// + /// ```math + /// ratio = |other.price - self.price| / self.price + /// ``` + /// + /// # Arguments + /// + /// * `other`: [`&Self`] - A reference to another [`Price`] object to + /// compute the difference ratio between. + /// + /// # Returns: + /// + /// [`Option`] - An optional [`Decimal`] value is returned which is + /// in the range [0, ∞] which is of the difference ratio and not percentage + /// and thus, it is not multiplied by 100. This means that a return of 0 + /// indicates no difference, a return of 1 indicated 100% difference, and + /// so on. If [`None`] is returned then these two prices where of two + /// different pairs. + /// + /// [article]: https://en.wikipedia.org/wiki/Relative_change + pub fn relative_difference(&self, other: &Self) -> Option { + if self.base == other.base && self.quote == other.quote { + other + .price + .checked_sub(self.price) + .and_then(|value| value.checked_abs()) + .and_then(|value| value.checked_div(self.price)) + } else if self.base == other.quote && self.quote == other.base { + self.relative_difference(&other.inverse()) + } else { + None + } + } + + /// Computes the output amount based on some input amount. + /// + /// This method calculates the output if an exchange happens at this price + /// where the output has a [`ResourceAddress`] to make it clear what unit + /// the output is in. If a resource that is neither the base nor the quote + /// is passed then [`None`] is returned. + /// + /// In a price that is BASE/QUOTE the unit is QUOTE/BASE. Therefore, if the + /// base tokens are passed, their amount is multiplied by the price and then + /// returned. If the quote tokens are passed, the inverse of the price is + /// multiplied by the passed amount. Otherwise, the resource does not belong + /// to this price. + /// + /// # Arguments + /// + /// `resource_address`: [`ResourceAddress`] - The address of the input + /// resources. + /// `amount`: [`Decimal`] - The amount of the input resources. + /// + /// # Returns + /// + /// [`Option<(ResourceAddress, Decimal)>`] - The address and amount of the + /// output if the input resource is either the base or the quote asset. Else + /// this is [`None`]. + pub fn exchange( + &self, + resource_address: ResourceAddress, + amount: Decimal, + ) -> Option<(ResourceAddress, Decimal)> { + if resource_address == self.base { + Some((self.quote, self.price.checked_mul(amount)?)) + } else if resource_address == self.quote { + Some((self.base, amount.checked_div(self.price)?)) + } else { + None + } + } + + /// Computes the inverse of the address. + /// + /// This method computes the price's inverse by exchanging the base with + /// the quote and diving 1 by the price. + /// + /// # Returns + /// + /// [`Price`] - The inverse of the price. + pub fn inverse(&self) -> Price { + Price { + base: self.quote, + quote: self.base, + // Panics if price is zero. + price: dec!(1).checked_div(self.price).unwrap(), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + const BITCOIN: ResourceAddress = ResourceAddress::new_or_panic([ + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, + ]); + const USD: ResourceAddress = ResourceAddress::new_or_panic([ + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, + ]); + + #[test] + fn percentage_difference_with_opposite_base_and_quote_is_calculated_correctly( + ) { + // Arrange + let p1 = Price { + base: BITCOIN, + quote: USD, + price: dec!(100), + }; + let p2 = Price { + base: USD, + quote: BITCOIN, + price: dec!(1) / dec!(100), + }; + + // Act + let difference = p1.relative_difference(&p2).unwrap(); + + // Assert + assert_eq!(difference, dec!(0)) + } + + #[test] + fn simple_percentage_difference_is_calculated_correctly() { + // Arrange + let p1 = Price { + base: BITCOIN, + quote: USD, + price: dec!(100), + }; + let p2 = Price { + base: BITCOIN, + quote: USD, + price: dec!(50), + }; + + // Act + let difference = p1.relative_difference(&p2).unwrap(); + + // Assert + assert_eq!(difference, dec!(0.5)) + } + + #[test] + fn exchange_method_calculates_as_expected1() { + // Arrange + let btc = BITCOIN; + let usd = USD; + + let price = Price { + base: btc, + quote: usd, + price: dec!(43000), + }; + + // Act + let (out_address, out_amount) = price.exchange(btc, dec!(1)).unwrap(); + + // Assert + assert_eq!(out_address, usd); + assert_eq!(out_amount, dec!(43000)); + } + + #[test] + fn exchange_method_calculates_as_expected2() { + // Arrange + let btc = BITCOIN; + let usd = USD; + + let price = Price { + base: btc, + quote: usd, + price: dec!(43000), + }; + + // Act + let (out_address, out_amount) = + price.exchange(usd, dec!(43000)).unwrap(); + + // Assert + assert_eq!(out_address, btc); + assert_eq!(out_amount, dec!(1)); + } + + #[test] + fn price_inverse_is_what_we_expect_it_to_be() { + // Arrange + let btc = BITCOIN; + let usd = USD; + + let price = Price { + base: btc, + quote: usd, + price: dec!(2), + }; + + // Act + let inverse = price.inverse(); + + // Assert + assert_eq!(inverse.base, price.quote); + assert_eq!(inverse.quote, price.base); + assert_eq!(inverse.price, dec!(1) / price.price); + } +} diff --git a/libraries/common/src/volatility.rs b/libraries/common/src/volatility.rs new file mode 100644 index 00000000..b022ee3c --- /dev/null +++ b/libraries/common/src/volatility.rs @@ -0,0 +1,8 @@ +use scrypto::prelude::*; + +/// An enum that describes the volatility of an asset. +#[derive(Clone, Copy, Debug, PartialEq, Eq, ScryptoSbor, ManifestSbor)] +pub enum Volatility { + Volatile, + NonVolatile, +} diff --git a/libraries/gateway-client/Cargo.toml b/libraries/gateway-client/Cargo.toml new file mode 100644 index 00000000..38eb1630 --- /dev/null +++ b/libraries/gateway-client/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "gateway-client" +description = "An auto-generated gateway client used by the various Ignition tools." +version.workspace = true +edition.workspace = true + +[dependencies] +serde = { version = "1.0.195", features = ["derive"] } +serde_with = { version = "3.5.1", features = ["hex"] } +serde_json = { version = "1.0.111" } +url = { version = "2.5.0" } +uuid = { version = "1.7.0", features = ["serde", "v4"] } +reqwest = { version = "0.11.23", features = ["json", "blocking", "multipart"] } + +[lints] +workspace = true \ No newline at end of file diff --git a/libraries/gateway-client/src/apis/configuration.rs b/libraries/gateway-client/src/apis/configuration.rs new file mode 100644 index 00000000..9e0df6d2 --- /dev/null +++ b/libraries/gateway-client/src/apis/configuration.rs @@ -0,0 +1,38 @@ +#[derive(Debug, Clone)] +pub struct Configuration { + pub base_path: String, + pub user_agent: Option, + pub client: reqwest::blocking::Client, + pub basic_auth: Option, + pub oauth_access_token: Option, + pub bearer_access_token: Option, + pub api_key: Option, +} + +pub type BasicAuth = (String, Option); + +#[derive(Debug, Clone)] +pub struct ApiKey { + pub prefix: Option, + pub key: String, +} + +impl Configuration { + pub fn new() -> Configuration { + Configuration::default() + } +} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + base_path: "http://localhost".to_owned(), + user_agent: Some("OpenAPI-Generator/v1.2.2/rust".to_owned()), + client: reqwest::blocking::Client::new(), + basic_auth: None, + oauth_access_token: None, + bearer_access_token: None, + api_key: None, + } + } +} diff --git a/libraries/gateway-client/src/apis/mod.rs b/libraries/gateway-client/src/apis/mod.rs new file mode 100644 index 00000000..a9ebf3e9 --- /dev/null +++ b/libraries/gateway-client/src/apis/mod.rs @@ -0,0 +1,109 @@ +use std::error; +use std::fmt; + +#[derive(Debug, Clone)] +pub struct ResponseContent { + pub status: reqwest::StatusCode, + pub content: String, + pub entity: Option, +} + +#[derive(Debug)] +pub enum Error { + Reqwest(reqwest::Error), + Serde(serde_json::Error), + Io(std::io::Error), + ResponseError(ResponseContent), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (module, e) = match self { + Error::Reqwest(e) => ("reqwest", e.to_string()), + Error::Serde(e) => ("serde", e.to_string()), + Error::Io(e) => ("IO", e.to_string()), + Error::ResponseError(e) => { + ("response", format!("status code {}", e.status)) + } + }; + write!(f, "error in {}: {}", module, e) + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match self { + Error::Reqwest(e) => e, + Error::Serde(e) => e, + Error::Io(e) => e, + Error::ResponseError(_) => return None, + }) + } +} + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Error::Reqwest(e) + } +} + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + Error::Serde(e) + } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::Io(e) + } +} + +pub fn urlencode>(s: T) -> String { + ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect() +} + +pub fn parse_deep_object( + prefix: &str, + value: &serde_json::Value, +) -> Vec<(String, String)> { + if let serde_json::Value::Object(object) = value { + let mut params = vec![]; + + for (key, value) in object { + match value { + serde_json::Value::Object(_) => { + params.append(&mut parse_deep_object( + &format!("{}[{}]", prefix, key), + value, + )) + } + serde_json::Value::Array(array) => { + for (i, value) in array.iter().enumerate() { + params.append(&mut parse_deep_object( + &format!("{}[{}][{}]", prefix, key, i), + value, + )); + } + } + serde_json::Value::String(s) => { + params.push((format!("{}[{}]", prefix, key), s.clone())) + } + _ => params + .push((format!("{}[{}]", prefix, key), value.to_string())), + } + } + + return params; + } + + unimplemented!("Only objects are supported with style=deepObject") +} + +pub mod state_api; +pub mod statistics_api; +pub mod status_api; +pub mod stream_api; +pub mod transaction_api; + +pub mod configuration; diff --git a/libraries/gateway-client/src/apis/state_api.rs b/libraries/gateway-client/src/apis/state_api.rs new file mode 100644 index 00000000..72ba9c7d --- /dev/null +++ b/libraries/gateway-client/src/apis/state_api.rs @@ -0,0 +1,650 @@ +use reqwest; + +use super::{configuration, Error}; +use crate::apis::ResponseContent; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityFungibleResourceVaultPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityFungiblesPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityMetadataPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityNonFungibleIdsPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityNonFungibleResourceVaultPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum EntityNonFungiblesPageError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum KeyValueStoreDataError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum NonFungibleDataError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum NonFungibleIdsError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum NonFungibleLocationError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum StateEntityDetailsError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum StateValidatorsListError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +pub fn entity_fungible_resource_vault_page( + configuration: &configuration::Configuration, + state_entity_fungible_resource_vaults_page_request: crate::models::StateEntityFungibleResourceVaultsPageRequest, +) -> Result< + crate::models::StateEntityFungibleResourceVaultsPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/fungible-vaults/", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = local_var_req_builder + .json(&state_entity_fungible_resource_vaults_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn entity_fungibles_page( + configuration: &configuration::Configuration, + state_entity_fungibles_page_request: crate::models::StateEntityFungiblesPageRequest, +) -> Result< + crate::models::StateEntityFungiblesPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/fungibles/", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_entity_fungibles_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn entity_metadata_page( + configuration: &configuration::Configuration, + state_entity_metadata_page_request: crate::models::StateEntityMetadataPageRequest, +) -> Result< + crate::models::StateEntityMetadataPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/metadata", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_entity_metadata_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn entity_non_fungible_ids_page( + configuration: &configuration::Configuration, + state_entity_non_fungible_ids_page_request: crate::models::StateEntityNonFungibleIdsPageRequest, +) -> Result< + crate::models::StateEntityNonFungibleIdsPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/non-fungible-vault/ids", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_entity_non_fungible_ids_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn entity_non_fungible_resource_vault_page( + configuration: &configuration::Configuration, + state_entity_non_fungible_resource_vaults_page_request: crate::models::StateEntityNonFungibleResourceVaultsPageRequest, +) -> Result< + crate::models::StateEntityNonFungibleResourceVaultsPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/non-fungible-vaults/", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = local_var_req_builder + .json(&state_entity_non_fungible_resource_vaults_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn entity_non_fungibles_page( + configuration: &configuration::Configuration, + state_entity_non_fungibles_page_request: crate::models::StateEntityNonFungiblesPageRequest, +) -> Result< + crate::models::StateEntityNonFungiblesPageResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/entity/page/non-fungibles/", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_entity_non_fungibles_page_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn key_value_store_data( + configuration: &configuration::Configuration, + state_key_value_store_data_request: crate::models::StateKeyValueStoreDataRequest, +) -> Result< + crate::models::StateKeyValueStoreDataResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/key-value-store/data", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_key_value_store_data_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn non_fungible_data( + configuration: &configuration::Configuration, + state_non_fungible_data_request: crate::models::StateNonFungibleDataRequest, +) -> Result< + crate::models::StateNonFungibleDataResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/non-fungible/data", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_non_fungible_data_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn non_fungible_ids( + configuration: &configuration::Configuration, + state_non_fungible_ids_request: crate::models::StateNonFungibleIdsRequest, +) -> Result< + crate::models::StateNonFungibleIdsResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/non-fungible/ids", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_non_fungible_ids_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn non_fungible_location( + configuration: &configuration::Configuration, + state_non_fungible_location_request: crate::models::StateNonFungibleLocationRequest, +) -> Result< + crate::models::StateNonFungibleLocationResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/non-fungible/location", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_non_fungible_location_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn state_entity_details( + configuration: &configuration::Configuration, + state_entity_details_request: crate::models::StateEntityDetailsRequest, +) -> Result< + crate::models::StateEntityDetailsResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = + format!("{}/state/entity/details", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_entity_details_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn state_validators_list( + configuration: &configuration::Configuration, + state_validators_list_request: crate::models::StateValidatorsListRequest, +) -> Result< + crate::models::StateValidatorsListResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/state/validators/list", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&state_validators_list_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} diff --git a/libraries/gateway-client/src/apis/statistics_api.rs b/libraries/gateway-client/src/apis/statistics_api.rs new file mode 100644 index 00000000..66d92e6f --- /dev/null +++ b/libraries/gateway-client/src/apis/statistics_api.rs @@ -0,0 +1,56 @@ +use reqwest; + +use super::{configuration, Error}; +use crate::apis::ResponseContent; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum ValidatorsUptimeError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +pub fn validators_uptime( + configuration: &configuration::Configuration, + validators_uptime_request: crate::models::ValidatorsUptimeRequest, +) -> Result> +{ + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/statistics/validators/uptime", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&validators_uptime_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} diff --git a/libraries/gateway-client/src/apis/status_api.rs b/libraries/gateway-client/src/apis/status_api.rs new file mode 100644 index 00000000..8fee4a44 --- /dev/null +++ b/libraries/gateway-client/src/apis/status_api.rs @@ -0,0 +1,101 @@ +use reqwest; + +use super::{configuration, Error}; +use crate::apis::ResponseContent; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum GatewayStatusError { + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum NetworkConfigurationError { + UnknownValue(serde_json::Value), +} + +pub fn gateway_status( + configuration: &configuration::Configuration, +) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/status/gateway-status", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn network_configuration( + configuration: &configuration::Configuration, +) -> Result< + crate::models::NetworkConfigurationResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/status/network-configuration", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} diff --git a/libraries/gateway-client/src/apis/stream_api.rs b/libraries/gateway-client/src/apis/stream_api.rs new file mode 100644 index 00000000..dae72fda --- /dev/null +++ b/libraries/gateway-client/src/apis/stream_api.rs @@ -0,0 +1,56 @@ +use reqwest; + +use super::{configuration, Error}; +use crate::apis::ResponseContent; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum StreamTransactionsError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +pub fn stream_transactions( + configuration: &configuration::Configuration, + stream_transactions_request: crate::models::StreamTransactionsRequest, +) -> Result< + crate::models::StreamTransactionsResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = + format!("{}/stream/transactions", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&stream_transactions_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} diff --git a/libraries/gateway-client/src/apis/transaction_api.rs b/libraries/gateway-client/src/apis/transaction_api.rs new file mode 100644 index 00000000..ed3cc3db --- /dev/null +++ b/libraries/gateway-client/src/apis/transaction_api.rs @@ -0,0 +1,264 @@ +use reqwest; + +use super::{configuration, Error}; +use crate::apis::ResponseContent; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TransactionCommittedDetailsError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TransactionConstructionError { + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TransactionPreviewError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TransactionStatusError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +pub enum TransactionSubmitError { + Status4XX(crate::models::ErrorResponse), + UnknownValue(serde_json::Value), +} + +pub fn transaction_committed_details( + configuration: &configuration::Configuration, + transaction_committed_details_request: crate::models::TransactionCommittedDetailsRequest, +) -> Result< + crate::models::TransactionCommittedDetailsResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/transaction/committed-details", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&transaction_committed_details_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn transaction_construction( + configuration: &configuration::Configuration, +) -> Result< + crate::models::TransactionConstructionResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!( + "{}/transaction/construction", + local_var_configuration.base_path + ); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn transaction_preview( + configuration: &configuration::Configuration, + transaction_preview_request: crate::models::TransactionPreviewRequest, +) -> Result< + crate::models::TransactionPreviewResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = + format!("{}/transaction/preview", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&transaction_preview_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn transaction_status( + configuration: &configuration::Configuration, + transaction_status_request: crate::models::TransactionStatusRequest, +) -> Result< + crate::models::TransactionStatusResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = + format!("{}/transaction/status", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&transaction_status_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub fn transaction_submit( + configuration: &configuration::Configuration, + transaction_submit_request: crate::models::TransactionSubmitRequest, +) -> Result< + crate::models::TransactionSubmitResponse, + Error, +> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = + format!("{}/transaction/submit", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client + .request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder + .header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + local_var_req_builder = + local_var_req_builder.json(&transaction_submit_request); + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req)?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text()?; + + if !local_var_status.is_client_error() + && !local_var_status.is_server_error() + { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = + serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { + status: local_var_status, + content: local_var_content, + entity: local_var_entity, + }; + Err(Error::ResponseError(local_var_error)) + } +} diff --git a/libraries/gateway-client/src/lib.rs b/libraries/gateway-client/src/lib.rs new file mode 100644 index 00000000..3ce6649f --- /dev/null +++ b/libraries/gateway-client/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(clippy::too_many_arguments)] + +extern crate reqwest; +extern crate serde; +extern crate serde_json; +extern crate url; + +pub mod apis; +pub mod models; diff --git a/libraries/gateway-client/src/models/at_ledger_state_mixin.rs b/libraries/gateway-client/src/models/at_ledger_state_mixin.rs new file mode 100644 index 00000000..41feda68 --- /dev/null +++ b/libraries/gateway-client/src/models/at_ledger_state_mixin.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct AtLedgerStateMixin { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, +} + +impl Default for AtLedgerStateMixin { + fn default() -> Self { + Self::new() + } +} + +impl AtLedgerStateMixin { + pub fn new() -> AtLedgerStateMixin { + AtLedgerStateMixin { + at_ledger_state: None, + } + } +} diff --git a/libraries/gateway-client/src/models/committed_transaction_info.rs b/libraries/gateway-client/src/models/committed_transaction_info.rs new file mode 100644 index 00000000..2c4f2281 --- /dev/null +++ b/libraries/gateway-client/src/models/committed_transaction_info.rs @@ -0,0 +1,85 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct CommittedTransactionInfo { + #[serde(rename = "state_version")] + pub state_version: i64, + #[serde(rename = "epoch")] + pub epoch: i64, + #[serde(rename = "round")] + pub round: i64, + #[serde(rename = "round_timestamp")] + pub round_timestamp: String, + #[serde(rename = "transaction_status")] + pub transaction_status: crate::models::TransactionStatus, + + #[serde(rename = "payload_hash", skip_serializing_if = "Option::is_none")] + pub payload_hash: Option, + + #[serde(rename = "intent_hash", skip_serializing_if = "Option::is_none")] + pub intent_hash: Option, + + #[serde(rename = "fee_paid", skip_serializing_if = "Option::is_none")] + pub fee_paid: Option, + #[serde( + rename = "affected_global_entities", + skip_serializing_if = "Option::is_none" + )] + pub affected_global_entities: Option>, + #[serde( + rename = "confirmed_at", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub confirmed_at: Option>, + #[serde( + rename = "error_message", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub error_message: Option>, + + #[serde(rename = "raw_hex", skip_serializing_if = "Option::is_none")] + pub raw_hex: Option, + #[serde(rename = "receipt", skip_serializing_if = "Option::is_none")] + pub receipt: Option>, + + #[serde(rename = "message", skip_serializing_if = "Option::is_none")] + pub message: Option, + #[serde( + rename = "balance_changes", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub balance_changes: + Option>>, +} + +impl CommittedTransactionInfo { + pub fn new( + state_version: i64, + epoch: i64, + round: i64, + round_timestamp: String, + transaction_status: crate::models::TransactionStatus, + ) -> CommittedTransactionInfo { + CommittedTransactionInfo { + state_version, + epoch, + round, + round_timestamp, + transaction_status, + payload_hash: None, + intent_hash: None, + fee_paid: None, + affected_global_entities: None, + confirmed_at: None, + error_message: None, + raw_hex: None, + receipt: None, + message: None, + balance_changes: None, + } + } +} diff --git a/libraries/gateway-client/src/models/component_entity_role_assignment_entry.rs b/libraries/gateway-client/src/models/component_entity_role_assignment_entry.rs new file mode 100644 index 00000000..ccbcda5d --- /dev/null +++ b/libraries/gateway-client/src/models/component_entity_role_assignment_entry.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ComponentEntityRoleAssignmentEntry { + #[serde(rename = "role_key")] + pub role_key: Box, + #[serde(rename = "assignment")] + pub assignment: + Box, + #[serde(rename = "updater_roles", skip_serializing_if = "Option::is_none")] + pub updater_roles: Option>, +} + +impl ComponentEntityRoleAssignmentEntry { + pub fn new( + role_key: crate::models::RoleKey, + assignment: crate::models::ComponentEntityRoleAssignmentEntryAssignment, + ) -> ComponentEntityRoleAssignmentEntry { + ComponentEntityRoleAssignmentEntry { + role_key: Box::new(role_key), + assignment: Box::new(assignment), + updater_roles: None, + } + } +} diff --git a/libraries/gateway-client/src/models/component_entity_role_assignment_entry_assignment.rs b/libraries/gateway-client/src/models/component_entity_role_assignment_entry_assignment.rs new file mode 100644 index 00000000..cb0fae03 --- /dev/null +++ b/libraries/gateway-client/src/models/component_entity_role_assignment_entry_assignment.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ComponentEntityRoleAssignmentEntryAssignment { + #[serde(rename = "resolution")] + pub resolution: crate::models::RoleAssignmentResolution, + + #[serde(rename = "explicit_rule", skip_serializing_if = "Option::is_none")] + pub explicit_rule: Option, +} + +impl ComponentEntityRoleAssignmentEntryAssignment { + pub fn new( + resolution: crate::models::RoleAssignmentResolution, + ) -> ComponentEntityRoleAssignmentEntryAssignment { + ComponentEntityRoleAssignmentEntryAssignment { + resolution, + explicit_rule: None, + } + } +} diff --git a/libraries/gateway-client/src/models/component_entity_role_assignments.rs b/libraries/gateway-client/src/models/component_entity_role_assignments.rs new file mode 100644 index 00000000..04ba0a6f --- /dev/null +++ b/libraries/gateway-client/src/models/component_entity_role_assignments.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ComponentEntityRoleAssignments { + #[serde(rename = "owner")] + pub owner: serde_json::Value, + #[serde(rename = "entries")] + pub entries: Vec, +} + +impl ComponentEntityRoleAssignments { + pub fn new( + owner: serde_json::Value, + entries: Vec, + ) -> ComponentEntityRoleAssignments { + ComponentEntityRoleAssignments { owner, entries } + } +} diff --git a/libraries/gateway-client/src/models/cursor_limit_mixin.rs b/libraries/gateway-client/src/models/cursor_limit_mixin.rs new file mode 100644 index 00000000..73a905c5 --- /dev/null +++ b/libraries/gateway-client/src/models/cursor_limit_mixin.rs @@ -0,0 +1,33 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct CursorLimitMixin { + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, +} + +impl Default for CursorLimitMixin { + fn default() -> Self { + Self::new() + } +} + +impl CursorLimitMixin { + pub fn new() -> CursorLimitMixin { + CursorLimitMixin { + cursor: None, + limit_per_page: None, + } + } +} diff --git a/libraries/gateway-client/src/models/entity_metadata_collection.rs b/libraries/gateway-client/src/models/entity_metadata_collection.rs new file mode 100644 index 00000000..8e178b8a --- /dev/null +++ b/libraries/gateway-client/src/models/entity_metadata_collection.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EntityMetadataCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl EntityMetadataCollection { + pub fn new( + items: Vec, + ) -> EntityMetadataCollection { + EntityMetadataCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/entity_metadata_item.rs b/libraries/gateway-client/src/models/entity_metadata_item.rs new file mode 100644 index 00000000..4b3a52c9 --- /dev/null +++ b/libraries/gateway-client/src/models/entity_metadata_item.rs @@ -0,0 +1,28 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EntityMetadataItem { + #[serde(rename = "key")] + pub key: String, + #[serde(rename = "value")] + pub value: Box, + #[serde(rename = "is_locked")] + pub is_locked: bool, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl EntityMetadataItem { + pub fn new( + key: String, + value: crate::models::EntityMetadataItemValue, + is_locked: bool, + last_updated_at_state_version: i64, + ) -> EntityMetadataItem { + EntityMetadataItem { + key, + value: Box::new(value), + is_locked, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/entity_metadata_item_value.rs b/libraries/gateway-client/src/models/entity_metadata_item_value.rs new file mode 100644 index 00000000..b078aaff --- /dev/null +++ b/libraries/gateway-client/src/models/entity_metadata_item_value.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EntityMetadataItemValue { + #[serde(rename = "raw_hex")] + pub raw_hex: String, + #[serde(rename = "programmatic_json")] + pub programmatic_json: Box, + #[serde(rename = "typed")] + pub typed: Box, +} + +impl EntityMetadataItemValue { + pub fn new( + raw_hex: String, + programmatic_json: crate::models::ProgrammaticScryptoSborValue, + typed: crate::models::MetadataTypedValue, + ) -> EntityMetadataItemValue { + EntityMetadataItemValue { + raw_hex, + programmatic_json: Box::new(programmatic_json), + typed: Box::new(typed), + } + } +} diff --git a/libraries/gateway-client/src/models/entity_not_found_error.rs b/libraries/gateway-client/src/models/entity_not_found_error.rs new file mode 100644 index 00000000..317b2335 --- /dev/null +++ b/libraries/gateway-client/src/models/entity_not_found_error.rs @@ -0,0 +1,14 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EntityNotFoundError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "address")] + pub address: String, +} + +impl EntityNotFoundError { + pub fn new(r#type: String, address: String) -> EntityNotFoundError { + EntityNotFoundError { r#type, address } + } +} diff --git a/libraries/gateway-client/src/models/error_response.rs b/libraries/gateway-client/src/models/error_response.rs new file mode 100644 index 00000000..0288265f --- /dev/null +++ b/libraries/gateway-client/src/models/error_response.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ErrorResponse { + #[serde(rename = "message")] + pub message: String, + + #[serde(rename = "code", skip_serializing_if = "Option::is_none")] + pub code: Option, + #[serde(rename = "details", skip_serializing_if = "Option::is_none")] + pub details: Option>, + + #[serde(rename = "trace_id", skip_serializing_if = "Option::is_none")] + pub trace_id: Option, +} + +impl ErrorResponse { + pub fn new(message: String) -> ErrorResponse { + ErrorResponse { + message, + code: None, + details: None, + trace_id: None, + } + } +} diff --git a/libraries/gateway-client/src/models/events_item.rs b/libraries/gateway-client/src/models/events_item.rs new file mode 100644 index 00000000..cf99446b --- /dev/null +++ b/libraries/gateway-client/src/models/events_item.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EventsItem { + #[serde(rename = "name")] + pub name: String, + + #[serde(rename = "emitter")] + pub emitter: serde_json::Value, + #[serde(rename = "data")] + pub data: Box, +} + +impl EventsItem { + pub fn new( + name: String, + emitter: serde_json::Value, + data: serde_json::Value, + ) -> EventsItem { + EventsItem { + name, + emitter, + data: Box::new(data), + } + } +} diff --git a/libraries/gateway-client/src/models/from_ledger_state_mixin.rs b/libraries/gateway-client/src/models/from_ledger_state_mixin.rs new file mode 100644 index 00000000..67e20943 --- /dev/null +++ b/libraries/gateway-client/src/models/from_ledger_state_mixin.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FromLedgerStateMixin { + #[serde( + rename = "from_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub from_ledger_state: + Option>>, +} + +impl Default for FromLedgerStateMixin { + fn default() -> Self { + Self::new() + } +} + +impl FromLedgerStateMixin { + pub fn new() -> FromLedgerStateMixin { + FromLedgerStateMixin { + from_ledger_state: None, + } + } +} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection.rs b/libraries/gateway-client/src/models/fungible_resources_collection.rs new file mode 100644 index 00000000..01e1470d --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FungibleResourcesCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl FungibleResourcesCollection { + pub fn new( + items: Vec, + ) -> FungibleResourcesCollection { + FungibleResourcesCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection_item.rs b/libraries/gateway-client/src/models/fungible_resources_collection_item.rs new file mode 100644 index 00000000..3267c9f4 --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection_item.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum FungibleResourcesCollectionItem {} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection_item_globally_aggregated.rs b/libraries/gateway-client/src/models/fungible_resources_collection_item_globally_aggregated.rs new file mode 100644 index 00000000..17660dc6 --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection_item_globally_aggregated.rs @@ -0,0 +1,36 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FungibleResourcesCollectionItemGloballyAggregated { + #[serde(rename = "aggregation_level")] + pub aggregation_level: crate::models::ResourceAggregationLevel, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, + + #[serde(rename = "amount")] + pub amount: String, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl FungibleResourcesCollectionItemGloballyAggregated { + pub fn new( + aggregation_level: crate::models::ResourceAggregationLevel, + resource_address: String, + amount: String, + last_updated_at_state_version: i64, + ) -> FungibleResourcesCollectionItemGloballyAggregated { + FungibleResourcesCollectionItemGloballyAggregated { + aggregation_level, + resource_address, + explicit_metadata: None, + amount, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated.rs b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated.rs new file mode 100644 index 00000000..a8fc4fe8 --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated.rs @@ -0,0 +1,31 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FungibleResourcesCollectionItemVaultAggregated { + #[serde(rename = "aggregation_level")] + pub aggregation_level: crate::models::ResourceAggregationLevel, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, + #[serde(rename = "vaults")] + pub vaults: + Box, +} + +impl FungibleResourcesCollectionItemVaultAggregated { + pub fn new( + aggregation_level: crate::models::ResourceAggregationLevel, + resource_address: String, + vaults: crate::models::FungibleResourcesCollectionItemVaultAggregatedVault, + ) -> FungibleResourcesCollectionItemVaultAggregated { + FungibleResourcesCollectionItemVaultAggregated { + aggregation_level, + resource_address, + explicit_metadata: None, + vaults: Box::new(vaults), + } + } +} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault.rs b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault.rs new file mode 100644 index 00000000..5e13613f --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault.rs @@ -0,0 +1,34 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FungibleResourcesCollectionItemVaultAggregatedVault { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec< + crate::models::FungibleResourcesCollectionItemVaultAggregatedVaultItem, + >, +} + +impl FungibleResourcesCollectionItemVaultAggregatedVault { + pub fn new( + items: Vec, + ) -> FungibleResourcesCollectionItemVaultAggregatedVault { + FungibleResourcesCollectionItemVaultAggregatedVault { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault_item.rs b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault_item.rs new file mode 100644 index 00000000..583a5d2b --- /dev/null +++ b/libraries/gateway-client/src/models/fungible_resources_collection_item_vault_aggregated_vault_item.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FungibleResourcesCollectionItemVaultAggregatedVaultItem { + #[serde(rename = "vault_address")] + pub vault_address: String, + + #[serde(rename = "amount")] + pub amount: String, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl FungibleResourcesCollectionItemVaultAggregatedVaultItem { + pub fn new( + vault_address: String, + amount: String, + last_updated_at_state_version: i64, + ) -> FungibleResourcesCollectionItemVaultAggregatedVaultItem { + FungibleResourcesCollectionItemVaultAggregatedVaultItem { + vault_address, + amount, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/gateway_error.rs b/libraries/gateway-client/src/models/gateway_error.rs new file mode 100644 index 00000000..1f391a20 --- /dev/null +++ b/libraries/gateway-client/src/models/gateway_error.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum GatewayError {} diff --git a/libraries/gateway-client/src/models/gateway_info_response_known_target.rs b/libraries/gateway-client/src/models/gateway_info_response_known_target.rs new file mode 100644 index 00000000..a2469e25 --- /dev/null +++ b/libraries/gateway-client/src/models/gateway_info_response_known_target.rs @@ -0,0 +1,11 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct GatewayInfoResponseKnownTarget { + #[serde(rename = "state_version")] + pub state_version: i64, +} + +impl GatewayInfoResponseKnownTarget { + pub fn new(state_version: i64) -> GatewayInfoResponseKnownTarget { + GatewayInfoResponseKnownTarget { state_version } + } +} diff --git a/libraries/gateway-client/src/models/gateway_info_response_release_info.rs b/libraries/gateway-client/src/models/gateway_info_response_release_info.rs new file mode 100644 index 00000000..91f183f0 --- /dev/null +++ b/libraries/gateway-client/src/models/gateway_info_response_release_info.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct GatewayInfoResponseReleaseInfo { + #[serde(rename = "release_version")] + pub release_version: String, + + #[serde(rename = "open_api_schema_version")] + pub open_api_schema_version: String, + + #[serde(rename = "image_tag")] + pub image_tag: String, +} + +impl GatewayInfoResponseReleaseInfo { + pub fn new( + release_version: String, + open_api_schema_version: String, + image_tag: String, + ) -> GatewayInfoResponseReleaseInfo { + GatewayInfoResponseReleaseInfo { + release_version, + open_api_schema_version, + image_tag, + } + } +} diff --git a/libraries/gateway-client/src/models/gateway_status_response.rs b/libraries/gateway-client/src/models/gateway_status_response.rs new file mode 100644 index 00000000..f9922fba --- /dev/null +++ b/libraries/gateway-client/src/models/gateway_status_response.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct GatewayStatusResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "release_info")] + pub release_info: Box, +} + +impl GatewayStatusResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + release_info: crate::models::GatewayInfoResponseReleaseInfo, + ) -> GatewayStatusResponse { + GatewayStatusResponse { + ledger_state: Box::new(ledger_state), + release_info: Box::new(release_info), + } + } +} diff --git a/libraries/gateway-client/src/models/internal_server_error.rs b/libraries/gateway-client/src/models/internal_server_error.rs new file mode 100644 index 00000000..29a5e0bc --- /dev/null +++ b/libraries/gateway-client/src/models/internal_server_error.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct InternalServerError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "exception")] + pub exception: String, + + #[serde(rename = "cause")] + pub cause: String, +} + +impl InternalServerError { + pub fn new( + r#type: String, + exception: String, + cause: String, + ) -> InternalServerError { + InternalServerError { + r#type, + exception, + cause, + } + } +} diff --git a/libraries/gateway-client/src/models/invalid_entity_error.rs b/libraries/gateway-client/src/models/invalid_entity_error.rs new file mode 100644 index 00000000..994cf367 --- /dev/null +++ b/libraries/gateway-client/src/models/invalid_entity_error.rs @@ -0,0 +1,14 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct InvalidEntityError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "address")] + pub address: String, +} + +impl InvalidEntityError { + pub fn new(r#type: String, address: String) -> InvalidEntityError { + InvalidEntityError { r#type, address } + } +} diff --git a/libraries/gateway-client/src/models/invalid_request_error.rs b/libraries/gateway-client/src/models/invalid_request_error.rs new file mode 100644 index 00000000..3d1bb659 --- /dev/null +++ b/libraries/gateway-client/src/models/invalid_request_error.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct InvalidRequestError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "validation_errors")] + pub validation_errors: Vec, +} + +impl InvalidRequestError { + pub fn new( + r#type: String, + validation_errors: Vec, + ) -> InvalidRequestError { + InvalidRequestError { + r#type, + validation_errors, + } + } +} diff --git a/libraries/gateway-client/src/models/invalid_transaction_error.rs b/libraries/gateway-client/src/models/invalid_transaction_error.rs new file mode 100644 index 00000000..86821d9e --- /dev/null +++ b/libraries/gateway-client/src/models/invalid_transaction_error.rs @@ -0,0 +1,11 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct InvalidTransactionError { + #[serde(rename = "type")] + pub r#type: String, +} + +impl InvalidTransactionError { + pub fn new(r#type: String) -> InvalidTransactionError { + InvalidTransactionError { r#type } + } +} diff --git a/libraries/gateway-client/src/models/ledger_state.rs b/libraries/gateway-client/src/models/ledger_state.rs new file mode 100644 index 00000000..0b53c9ce --- /dev/null +++ b/libraries/gateway-client/src/models/ledger_state.rs @@ -0,0 +1,35 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct LedgerState { + #[serde(rename = "network")] + pub network: String, + + #[serde(rename = "state_version")] + pub state_version: i64, + + #[serde(rename = "proposer_round_timestamp")] + pub proposer_round_timestamp: String, + + #[serde(rename = "epoch")] + pub epoch: i64, + + #[serde(rename = "round")] + pub round: i64, +} + +impl LedgerState { + pub fn new( + network: String, + state_version: i64, + proposer_round_timestamp: String, + epoch: i64, + round: i64, + ) -> LedgerState { + LedgerState { + network, + state_version, + proposer_round_timestamp, + epoch, + round, + } + } +} diff --git a/libraries/gateway-client/src/models/ledger_state_mixin.rs b/libraries/gateway-client/src/models/ledger_state_mixin.rs new file mode 100644 index 00000000..3de000c1 --- /dev/null +++ b/libraries/gateway-client/src/models/ledger_state_mixin.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct LedgerStateMixin { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, +} + +impl LedgerStateMixin { + pub fn new(ledger_state: crate::models::LedgerState) -> LedgerStateMixin { + LedgerStateMixin { + ledger_state: Box::new(ledger_state), + } + } +} diff --git a/libraries/gateway-client/src/models/ledger_state_selector.rs b/libraries/gateway-client/src/models/ledger_state_selector.rs new file mode 100644 index 00000000..c515c031 --- /dev/null +++ b/libraries/gateway-client/src/models/ledger_state_selector.rs @@ -0,0 +1,51 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct LedgerStateSelector { + #[serde( + rename = "state_version", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub state_version: Option>, + + #[serde( + rename = "timestamp", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub timestamp: Option>, + + #[serde( + rename = "epoch", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub epoch: Option>, + + #[serde( + rename = "round", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub round: Option>, +} + +impl Default for LedgerStateSelector { + fn default() -> Self { + Self::new() + } +} + +impl LedgerStateSelector { + pub fn new() -> LedgerStateSelector { + LedgerStateSelector { + state_version: None, + timestamp: None, + epoch: None, + round: None, + } + } +} diff --git a/libraries/gateway-client/src/models/metadata_bool_array_value.rs b/libraries/gateway-client/src/models/metadata_bool_array_value.rs new file mode 100644 index 00000000..e1b2d93b --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_bool_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataBoolArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataBoolArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataBoolArrayValue { + MetadataBoolArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_bool_value.rs b/libraries/gateway-client/src/models/metadata_bool_value.rs new file mode 100644 index 00000000..486e8758 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_bool_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataBoolValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: bool, +} + +impl MetadataBoolValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: bool, + ) -> MetadataBoolValue { + MetadataBoolValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_decimal_array_value.rs b/libraries/gateway-client/src/models/metadata_decimal_array_value.rs new file mode 100644 index 00000000..8c14a68c --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_decimal_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataDecimalArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataDecimalArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataDecimalArrayValue { + MetadataDecimalArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_decimal_value.rs b/libraries/gateway-client/src/models/metadata_decimal_value.rs new file mode 100644 index 00000000..1ab60d6b --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_decimal_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataDecimalValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataDecimalValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataDecimalValue { + MetadataDecimalValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_global_address_array_value.rs b/libraries/gateway-client/src/models/metadata_global_address_array_value.rs new file mode 100644 index 00000000..427ba5a5 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_global_address_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataGlobalAddressArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataGlobalAddressArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataGlobalAddressArrayValue { + MetadataGlobalAddressArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_global_address_value.rs b/libraries/gateway-client/src/models/metadata_global_address_value.rs new file mode 100644 index 00000000..00c4c415 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_global_address_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataGlobalAddressValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataGlobalAddressValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataGlobalAddressValue { + MetadataGlobalAddressValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_i32_array_value.rs b/libraries/gateway-client/src/models/metadata_i32_array_value.rs new file mode 100644 index 00000000..121c015b --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_i32_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataI32ArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataI32ArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataI32ArrayValue { + MetadataI32ArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_i32_value.rs b/libraries/gateway-client/src/models/metadata_i32_value.rs new file mode 100644 index 00000000..ebf07a51 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_i32_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataI32Value { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataI32Value { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataI32Value { + MetadataI32Value { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_i64_array_value.rs b/libraries/gateway-client/src/models/metadata_i64_array_value.rs new file mode 100644 index 00000000..6b2d648c --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_i64_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataI64ArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataI64ArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataI64ArrayValue { + MetadataI64ArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_i64_value.rs b/libraries/gateway-client/src/models/metadata_i64_value.rs new file mode 100644 index 00000000..6926f8cb --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_i64_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataI64Value { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataI64Value { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataI64Value { + MetadataI64Value { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_instant_array_value.rs b/libraries/gateway-client/src/models/metadata_instant_array_value.rs new file mode 100644 index 00000000..507ee704 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_instant_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataInstantArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataInstantArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataInstantArrayValue { + MetadataInstantArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_instant_value.rs b/libraries/gateway-client/src/models/metadata_instant_value.rs new file mode 100644 index 00000000..fcbc362e --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_instant_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataInstantValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataInstantValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataInstantValue { + MetadataInstantValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value.rs b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value.rs new file mode 100644 index 00000000..389b8397 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataNonFungibleGlobalIdArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: + Vec, +} + +impl MetadataNonFungibleGlobalIdArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec< + crate::models::MetadataNonFungibleGlobalIdArrayValueAllOfValues, + >, + ) -> MetadataNonFungibleGlobalIdArrayValue { + MetadataNonFungibleGlobalIdArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value_all_of_values.rs b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value_all_of_values.rs new file mode 100644 index 00000000..158f2ca7 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_array_value_all_of_values.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataNonFungibleGlobalIdArrayValueAllOfValues { + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "non_fungible_id")] + pub non_fungible_id: String, +} + +impl MetadataNonFungibleGlobalIdArrayValueAllOfValues { + pub fn new( + resource_address: String, + non_fungible_id: String, + ) -> MetadataNonFungibleGlobalIdArrayValueAllOfValues { + MetadataNonFungibleGlobalIdArrayValueAllOfValues { + resource_address, + non_fungible_id, + } + } +} diff --git a/libraries/gateway-client/src/models/metadata_non_fungible_global_id_value.rs b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_value.rs new file mode 100644 index 00000000..6a5d7859 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_non_fungible_global_id_value.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataNonFungibleGlobalIdValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "non_fungible_id")] + pub non_fungible_id: String, +} + +impl MetadataNonFungibleGlobalIdValue { + pub fn new( + r#type: crate::models::MetadataValueType, + resource_address: String, + non_fungible_id: String, + ) -> MetadataNonFungibleGlobalIdValue { + MetadataNonFungibleGlobalIdValue { + r#type, + resource_address, + non_fungible_id, + } + } +} diff --git a/libraries/gateway-client/src/models/metadata_non_fungible_local_id_array_value.rs b/libraries/gateway-client/src/models/metadata_non_fungible_local_id_array_value.rs new file mode 100644 index 00000000..4a8148d3 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_non_fungible_local_id_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataNonFungibleLocalIdArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataNonFungibleLocalIdArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataNonFungibleLocalIdArrayValue { + MetadataNonFungibleLocalIdArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_non_fungible_local_id_value.rs b/libraries/gateway-client/src/models/metadata_non_fungible_local_id_value.rs new file mode 100644 index 00000000..52aaf12a --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_non_fungible_local_id_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataNonFungibleLocalIdValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataNonFungibleLocalIdValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataNonFungibleLocalIdValue { + MetadataNonFungibleLocalIdValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_origin_array_value.rs b/libraries/gateway-client/src/models/metadata_origin_array_value.rs new file mode 100644 index 00000000..d44650be --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_origin_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataOriginArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataOriginArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataOriginArrayValue { + MetadataOriginArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_origin_value.rs b/libraries/gateway-client/src/models/metadata_origin_value.rs new file mode 100644 index 00000000..e71dbfff --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_origin_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataOriginValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataOriginValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataOriginValue { + MetadataOriginValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_public_key_array_value.rs b/libraries/gateway-client/src/models/metadata_public_key_array_value.rs new file mode 100644 index 00000000..37f326fa --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_public_key_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataPublicKeyArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataPublicKeyArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataPublicKeyArrayValue { + MetadataPublicKeyArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_public_key_hash_array_value.rs b/libraries/gateway-client/src/models/metadata_public_key_hash_array_value.rs new file mode 100644 index 00000000..ac5ddfbb --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_public_key_hash_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataPublicKeyHashArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataPublicKeyHashArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataPublicKeyHashArrayValue { + MetadataPublicKeyHashArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_public_key_hash_value.rs b/libraries/gateway-client/src/models/metadata_public_key_hash_value.rs new file mode 100644 index 00000000..4a73928c --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_public_key_hash_value.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataPublicKeyHashValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: Box, +} + +impl MetadataPublicKeyHashValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: crate::models::PublicKeyHash, + ) -> MetadataPublicKeyHashValue { + MetadataPublicKeyHashValue { + r#type, + value: Box::new(value), + } + } +} diff --git a/libraries/gateway-client/src/models/metadata_public_key_value.rs b/libraries/gateway-client/src/models/metadata_public_key_value.rs new file mode 100644 index 00000000..954807d6 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_public_key_value.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataPublicKeyValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: Box, +} + +impl MetadataPublicKeyValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: crate::models::PublicKey, + ) -> MetadataPublicKeyValue { + MetadataPublicKeyValue { + r#type, + value: Box::new(value), + } + } +} diff --git a/libraries/gateway-client/src/models/metadata_string_array_value.rs b/libraries/gateway-client/src/models/metadata_string_array_value.rs new file mode 100644 index 00000000..abd000f2 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_string_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataStringArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataStringArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataStringArrayValue { + MetadataStringArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_string_value.rs b/libraries/gateway-client/src/models/metadata_string_value.rs new file mode 100644 index 00000000..42f50f06 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_string_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataStringValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataStringValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataStringValue { + MetadataStringValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_typed_value.rs b/libraries/gateway-client/src/models/metadata_typed_value.rs new file mode 100644 index 00000000..33bc133e --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_typed_value.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum MetadataTypedValue {} diff --git a/libraries/gateway-client/src/models/metadata_u32_array_value.rs b/libraries/gateway-client/src/models/metadata_u32_array_value.rs new file mode 100644 index 00000000..66a00446 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u32_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU32ArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataU32ArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataU32ArrayValue { + MetadataU32ArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_u32_value.rs b/libraries/gateway-client/src/models/metadata_u32_value.rs new file mode 100644 index 00000000..4780010c --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u32_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU32Value { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataU32Value { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataU32Value { + MetadataU32Value { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_u64_array_value.rs b/libraries/gateway-client/src/models/metadata_u64_array_value.rs new file mode 100644 index 00000000..43bd8764 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u64_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU64ArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataU64ArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataU64ArrayValue { + MetadataU64ArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_u64_value.rs b/libraries/gateway-client/src/models/metadata_u64_value.rs new file mode 100644 index 00000000..5ad0d4e4 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u64_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU64Value { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataU64Value { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataU64Value { + MetadataU64Value { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_u8_array_value.rs b/libraries/gateway-client/src/models/metadata_u8_array_value.rs new file mode 100644 index 00000000..01379a84 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u8_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU8ArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value_hex")] + pub value_hex: String, +} + +impl MetadataU8ArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value_hex: String, + ) -> MetadataU8ArrayValue { + MetadataU8ArrayValue { r#type, value_hex } + } +} diff --git a/libraries/gateway-client/src/models/metadata_u8_value.rs b/libraries/gateway-client/src/models/metadata_u8_value.rs new file mode 100644 index 00000000..ae0310a2 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_u8_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataU8Value { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataU8Value { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataU8Value { + MetadataU8Value { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_url_array_value.rs b/libraries/gateway-client/src/models/metadata_url_array_value.rs new file mode 100644 index 00000000..b9ab6fc0 --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_url_array_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataUrlArrayValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "values")] + pub values: Vec, +} + +impl MetadataUrlArrayValue { + pub fn new( + r#type: crate::models::MetadataValueType, + values: Vec, + ) -> MetadataUrlArrayValue { + MetadataUrlArrayValue { r#type, values } + } +} diff --git a/libraries/gateway-client/src/models/metadata_url_value.rs b/libraries/gateway-client/src/models/metadata_url_value.rs new file mode 100644 index 00000000..0596401f --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_url_value.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MetadataUrlValue { + #[serde(rename = "type")] + pub r#type: crate::models::MetadataValueType, + #[serde(rename = "value")] + pub value: String, +} + +impl MetadataUrlValue { + pub fn new( + r#type: crate::models::MetadataValueType, + value: String, + ) -> MetadataUrlValue { + MetadataUrlValue { r#type, value } + } +} diff --git a/libraries/gateway-client/src/models/metadata_value_type.rs b/libraries/gateway-client/src/models/metadata_value_type.rs new file mode 100644 index 00000000..c35e768c --- /dev/null +++ b/libraries/gateway-client/src/models/metadata_value_type.rs @@ -0,0 +1,127 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum MetadataValueType { + #[serde(rename = "String")] + String, + #[serde(rename = "Bool")] + Bool, + #[serde(rename = "U8")] + U8, + #[serde(rename = "U32")] + U32, + #[serde(rename = "U64")] + U64, + #[serde(rename = "I32")] + I32, + #[serde(rename = "I64")] + I64, + #[serde(rename = "Decimal")] + Decimal, + #[serde(rename = "GlobalAddress")] + GlobalAddress, + #[serde(rename = "PublicKey")] + PublicKey, + #[serde(rename = "NonFungibleGlobalId")] + NonFungibleGlobalId, + #[serde(rename = "NonFungibleLocalId")] + NonFungibleLocalId, + #[serde(rename = "Instant")] + Instant, + #[serde(rename = "Url")] + Url, + #[serde(rename = "Origin")] + Origin, + #[serde(rename = "PublicKeyHash")] + PublicKeyHash, + #[serde(rename = "StringArray")] + StringArray, + #[serde(rename = "BoolArray")] + BoolArray, + #[serde(rename = "U8Array")] + U8Array, + #[serde(rename = "U32Array")] + U32Array, + #[serde(rename = "U64Array")] + U64Array, + #[serde(rename = "I32Array")] + I32Array, + #[serde(rename = "I64Array")] + I64Array, + #[serde(rename = "DecimalArray")] + DecimalArray, + #[serde(rename = "GlobalAddressArray")] + GlobalAddressArray, + #[serde(rename = "PublicKeyArray")] + PublicKeyArray, + #[serde(rename = "NonFungibleGlobalIdArray")] + NonFungibleGlobalIdArray, + #[serde(rename = "NonFungibleLocalIdArray")] + NonFungibleLocalIdArray, + #[serde(rename = "InstantArray")] + InstantArray, + #[serde(rename = "UrlArray")] + UrlArray, + #[serde(rename = "OriginArray")] + OriginArray, + #[serde(rename = "PublicKeyHashArray")] + PublicKeyHashArray, +} + +impl ToString for MetadataValueType { + fn to_string(&self) -> String { + match self { + Self::String => String::from("String"), + Self::Bool => String::from("Bool"), + Self::U8 => String::from("U8"), + Self::U32 => String::from("U32"), + Self::U64 => String::from("U64"), + Self::I32 => String::from("I32"), + Self::I64 => String::from("I64"), + Self::Decimal => String::from("Decimal"), + Self::GlobalAddress => String::from("GlobalAddress"), + Self::PublicKey => String::from("PublicKey"), + Self::NonFungibleGlobalId => String::from("NonFungibleGlobalId"), + Self::NonFungibleLocalId => String::from("NonFungibleLocalId"), + Self::Instant => String::from("Instant"), + Self::Url => String::from("Url"), + Self::Origin => String::from("Origin"), + Self::PublicKeyHash => String::from("PublicKeyHash"), + Self::StringArray => String::from("StringArray"), + Self::BoolArray => String::from("BoolArray"), + Self::U8Array => String::from("U8Array"), + Self::U32Array => String::from("U32Array"), + Self::U64Array => String::from("U64Array"), + Self::I32Array => String::from("I32Array"), + Self::I64Array => String::from("I64Array"), + Self::DecimalArray => String::from("DecimalArray"), + Self::GlobalAddressArray => String::from("GlobalAddressArray"), + Self::PublicKeyArray => String::from("PublicKeyArray"), + Self::NonFungibleGlobalIdArray => { + String::from("NonFungibleGlobalIdArray") + } + Self::NonFungibleLocalIdArray => { + String::from("NonFungibleLocalIdArray") + } + Self::InstantArray => String::from("InstantArray"), + Self::UrlArray => String::from("UrlArray"), + Self::OriginArray => String::from("OriginArray"), + Self::PublicKeyHashArray => String::from("PublicKeyHashArray"), + } + } +} + +impl Default for MetadataValueType { + fn default() -> MetadataValueType { + Self::String + } +} diff --git a/libraries/gateway-client/src/models/mod.rs b/libraries/gateway-client/src/models/mod.rs new file mode 100644 index 00000000..759d34fc --- /dev/null +++ b/libraries/gateway-client/src/models/mod.rs @@ -0,0 +1,404 @@ +pub mod at_ledger_state_mixin; +pub use self::at_ledger_state_mixin::AtLedgerStateMixin; +pub mod committed_transaction_info; +pub use self::committed_transaction_info::CommittedTransactionInfo; +pub mod component_entity_role_assignment_entry; +pub use self::component_entity_role_assignment_entry::ComponentEntityRoleAssignmentEntry; +pub mod component_entity_role_assignment_entry_assignment; +pub use self::component_entity_role_assignment_entry_assignment::ComponentEntityRoleAssignmentEntryAssignment; +pub mod component_entity_role_assignments; +pub use self::component_entity_role_assignments::ComponentEntityRoleAssignments; +pub mod cursor_limit_mixin; +pub use self::cursor_limit_mixin::CursorLimitMixin; +pub mod entity_metadata_collection; +pub use self::entity_metadata_collection::EntityMetadataCollection; +pub mod entity_metadata_item; +pub use self::entity_metadata_item::EntityMetadataItem; +pub mod entity_metadata_item_value; +pub use self::entity_metadata_item_value::EntityMetadataItemValue; +pub mod entity_not_found_error; +pub use self::entity_not_found_error::EntityNotFoundError; +pub mod error_response; +pub use self::error_response::ErrorResponse; +pub mod events_item; +pub use self::events_item::EventsItem; +pub mod from_ledger_state_mixin; +pub use self::from_ledger_state_mixin::FromLedgerStateMixin; +pub mod fungible_resources_collection; +pub use self::fungible_resources_collection::FungibleResourcesCollection; +pub mod fungible_resources_collection_item; +pub use self::fungible_resources_collection_item::FungibleResourcesCollectionItem; +pub mod fungible_resources_collection_item_globally_aggregated; +pub use self::fungible_resources_collection_item_globally_aggregated::FungibleResourcesCollectionItemGloballyAggregated; +pub mod fungible_resources_collection_item_vault_aggregated; +pub use self::fungible_resources_collection_item_vault_aggregated::FungibleResourcesCollectionItemVaultAggregated; +pub mod fungible_resources_collection_item_vault_aggregated_vault; +pub use self::fungible_resources_collection_item_vault_aggregated_vault::FungibleResourcesCollectionItemVaultAggregatedVault; +pub mod fungible_resources_collection_item_vault_aggregated_vault_item; +pub use self::fungible_resources_collection_item_vault_aggregated_vault_item::FungibleResourcesCollectionItemVaultAggregatedVaultItem; +pub mod gateway_error; +pub use self::gateway_error::GatewayError; +pub mod gateway_info_response_known_target; +pub use self::gateway_info_response_known_target::GatewayInfoResponseKnownTarget; +pub mod gateway_info_response_release_info; +pub use self::gateway_info_response_release_info::GatewayInfoResponseReleaseInfo; +pub mod gateway_status_response; +pub use self::gateway_status_response::GatewayStatusResponse; +pub mod internal_server_error; +pub use self::internal_server_error::InternalServerError; +pub mod invalid_entity_error; +pub use self::invalid_entity_error::InvalidEntityError; +pub mod invalid_request_error; +pub use self::invalid_request_error::InvalidRequestError; +pub mod invalid_transaction_error; +pub use self::invalid_transaction_error::InvalidTransactionError; +pub mod ledger_state; +pub use self::ledger_state::LedgerState; +pub mod ledger_state_mixin; +pub use self::ledger_state_mixin::LedgerStateMixin; +pub mod ledger_state_selector; +pub use self::ledger_state_selector::LedgerStateSelector; +pub mod metadata_bool_array_value; +pub use self::metadata_bool_array_value::MetadataBoolArrayValue; +pub mod metadata_bool_value; +pub use self::metadata_bool_value::MetadataBoolValue; +pub mod metadata_decimal_array_value; +pub use self::metadata_decimal_array_value::MetadataDecimalArrayValue; +pub mod metadata_decimal_value; +pub use self::metadata_decimal_value::MetadataDecimalValue; +pub mod metadata_global_address_array_value; +pub use self::metadata_global_address_array_value::MetadataGlobalAddressArrayValue; +pub mod metadata_global_address_value; +pub use self::metadata_global_address_value::MetadataGlobalAddressValue; +pub mod metadata_i32_array_value; +pub use self::metadata_i32_array_value::MetadataI32ArrayValue; +pub mod metadata_i32_value; +pub use self::metadata_i32_value::MetadataI32Value; +pub mod metadata_i64_array_value; +pub use self::metadata_i64_array_value::MetadataI64ArrayValue; +pub mod metadata_i64_value; +pub use self::metadata_i64_value::MetadataI64Value; +pub mod metadata_instant_array_value; +pub use self::metadata_instant_array_value::MetadataInstantArrayValue; +pub mod metadata_instant_value; +pub use self::metadata_instant_value::MetadataInstantValue; +pub mod metadata_non_fungible_global_id_array_value; +pub use self::metadata_non_fungible_global_id_array_value::MetadataNonFungibleGlobalIdArrayValue; +pub mod metadata_non_fungible_global_id_array_value_all_of_values; +pub use self::metadata_non_fungible_global_id_array_value_all_of_values::MetadataNonFungibleGlobalIdArrayValueAllOfValues; +pub mod metadata_non_fungible_global_id_value; +pub use self::metadata_non_fungible_global_id_value::MetadataNonFungibleGlobalIdValue; +pub mod metadata_non_fungible_local_id_array_value; +pub use self::metadata_non_fungible_local_id_array_value::MetadataNonFungibleLocalIdArrayValue; +pub mod metadata_non_fungible_local_id_value; +pub use self::metadata_non_fungible_local_id_value::MetadataNonFungibleLocalIdValue; +pub mod metadata_origin_array_value; +pub use self::metadata_origin_array_value::MetadataOriginArrayValue; +pub mod metadata_origin_value; +pub use self::metadata_origin_value::MetadataOriginValue; +pub mod metadata_public_key_array_value; +pub use self::metadata_public_key_array_value::MetadataPublicKeyArrayValue; +pub mod metadata_public_key_hash_array_value; +pub use self::metadata_public_key_hash_array_value::MetadataPublicKeyHashArrayValue; +pub mod metadata_public_key_hash_value; +pub use self::metadata_public_key_hash_value::MetadataPublicKeyHashValue; +pub mod metadata_public_key_value; +pub use self::metadata_public_key_value::MetadataPublicKeyValue; +pub mod metadata_string_array_value; +pub use self::metadata_string_array_value::MetadataStringArrayValue; +pub mod metadata_string_value; +pub use self::metadata_string_value::MetadataStringValue; +pub mod metadata_typed_value; +pub use self::metadata_typed_value::MetadataTypedValue; +pub mod metadata_u32_array_value; +pub use self::metadata_u32_array_value::MetadataU32ArrayValue; +pub mod metadata_u32_value; +pub use self::metadata_u32_value::MetadataU32Value; +pub mod metadata_u64_array_value; +pub use self::metadata_u64_array_value::MetadataU64ArrayValue; +pub mod metadata_u64_value; +pub use self::metadata_u64_value::MetadataU64Value; +pub mod metadata_u8_array_value; +pub use self::metadata_u8_array_value::MetadataU8ArrayValue; +pub mod metadata_u8_value; +pub use self::metadata_u8_value::MetadataU8Value; +pub mod metadata_url_array_value; +pub use self::metadata_url_array_value::MetadataUrlArrayValue; +pub mod metadata_url_value; +pub use self::metadata_url_value::MetadataUrlValue; +pub mod metadata_value_type; +pub use self::metadata_value_type::MetadataValueType; +pub mod network_configuration_response; +pub use self::network_configuration_response::NetworkConfigurationResponse; +pub mod network_configuration_response_well_known_addresses; +pub use self::network_configuration_response_well_known_addresses::NetworkConfigurationResponseWellKnownAddresses; +pub mod non_fungible_id_type; +pub use self::non_fungible_id_type::NonFungibleIdType; +pub mod non_fungible_ids_collection; +pub use self::non_fungible_ids_collection::NonFungibleIdsCollection; +pub mod non_fungible_resources_collection; +pub use self::non_fungible_resources_collection::NonFungibleResourcesCollection; +pub mod non_fungible_resources_collection_item; +pub use self::non_fungible_resources_collection_item::NonFungibleResourcesCollectionItem; +pub mod non_fungible_resources_collection_item_globally_aggregated; +pub use self::non_fungible_resources_collection_item_globally_aggregated::NonFungibleResourcesCollectionItemGloballyAggregated; +pub mod non_fungible_resources_collection_item_vault_aggregated; +pub use self::non_fungible_resources_collection_item_vault_aggregated::NonFungibleResourcesCollectionItemVaultAggregated; +pub mod non_fungible_resources_collection_item_vault_aggregated_vault; +pub use self::non_fungible_resources_collection_item_vault_aggregated_vault::NonFungibleResourcesCollectionItemVaultAggregatedVault; +pub mod non_fungible_resources_collection_item_vault_aggregated_vault_item; +pub use self::non_fungible_resources_collection_item_vault_aggregated_vault_item::NonFungibleResourcesCollectionItemVaultAggregatedVaultItem; +pub mod not_synced_up_error; +pub use self::not_synced_up_error::NotSyncedUpError; +pub mod object_module_id; +pub use self::object_module_id::ObjectModuleId; +pub mod optional_non_fungible_ids_collection; +pub use self::optional_non_fungible_ids_collection::OptionalNonFungibleIdsCollection; +pub mod package_vm_type; +pub use self::package_vm_type::PackageVmType; +pub mod programmatic_scrypto_sbor_value; +pub use self::programmatic_scrypto_sbor_value::ProgrammaticScryptoSborValue; +pub mod programmatic_scrypto_sbor_value_array; +pub use self::programmatic_scrypto_sbor_value_array::ProgrammaticScryptoSborValueArray; +pub mod programmatic_scrypto_sbor_value_bool; +pub use self::programmatic_scrypto_sbor_value_bool::ProgrammaticScryptoSborValueBool; +pub mod programmatic_scrypto_sbor_value_bytes; +pub use self::programmatic_scrypto_sbor_value_bytes::ProgrammaticScryptoSborValueBytes; +pub mod programmatic_scrypto_sbor_value_decimal; +pub use self::programmatic_scrypto_sbor_value_decimal::ProgrammaticScryptoSborValueDecimal; +pub mod programmatic_scrypto_sbor_value_enum; +pub use self::programmatic_scrypto_sbor_value_enum::ProgrammaticScryptoSborValueEnum; +pub mod programmatic_scrypto_sbor_value_i128; +pub use self::programmatic_scrypto_sbor_value_i128::ProgrammaticScryptoSborValueI128; +pub mod programmatic_scrypto_sbor_value_i16; +pub use self::programmatic_scrypto_sbor_value_i16::ProgrammaticScryptoSborValueI16; +pub mod programmatic_scrypto_sbor_value_i32; +pub use self::programmatic_scrypto_sbor_value_i32::ProgrammaticScryptoSborValueI32; +pub mod programmatic_scrypto_sbor_value_i64; +pub use self::programmatic_scrypto_sbor_value_i64::ProgrammaticScryptoSborValueI64; +pub mod programmatic_scrypto_sbor_value_i8; +pub use self::programmatic_scrypto_sbor_value_i8::ProgrammaticScryptoSborValueI8; +pub mod programmatic_scrypto_sbor_value_kind; +pub use self::programmatic_scrypto_sbor_value_kind::ProgrammaticScryptoSborValueKind; +pub mod programmatic_scrypto_sbor_value_map; +pub use self::programmatic_scrypto_sbor_value_map::ProgrammaticScryptoSborValueMap; +pub mod programmatic_scrypto_sbor_value_map_entry; +pub use self::programmatic_scrypto_sbor_value_map_entry::ProgrammaticScryptoSborValueMapEntry; +pub mod programmatic_scrypto_sbor_value_non_fungible_local_id; +pub use self::programmatic_scrypto_sbor_value_non_fungible_local_id::ProgrammaticScryptoSborValueNonFungibleLocalId; +pub mod programmatic_scrypto_sbor_value_own; +pub use self::programmatic_scrypto_sbor_value_own::ProgrammaticScryptoSborValueOwn; +pub mod programmatic_scrypto_sbor_value_precise_decimal; +pub use self::programmatic_scrypto_sbor_value_precise_decimal::ProgrammaticScryptoSborValuePreciseDecimal; +pub mod programmatic_scrypto_sbor_value_reference; +pub use self::programmatic_scrypto_sbor_value_reference::ProgrammaticScryptoSborValueReference; +pub mod programmatic_scrypto_sbor_value_string; +pub use self::programmatic_scrypto_sbor_value_string::ProgrammaticScryptoSborValueString; +pub mod programmatic_scrypto_sbor_value_tuple; +pub use self::programmatic_scrypto_sbor_value_tuple::ProgrammaticScryptoSborValueTuple; +pub mod programmatic_scrypto_sbor_value_u128; +pub use self::programmatic_scrypto_sbor_value_u128::ProgrammaticScryptoSborValueU128; +pub mod programmatic_scrypto_sbor_value_u16; +pub use self::programmatic_scrypto_sbor_value_u16::ProgrammaticScryptoSborValueU16; +pub mod programmatic_scrypto_sbor_value_u32; +pub use self::programmatic_scrypto_sbor_value_u32::ProgrammaticScryptoSborValueU32; +pub mod programmatic_scrypto_sbor_value_u64; +pub use self::programmatic_scrypto_sbor_value_u64::ProgrammaticScryptoSborValueU64; +pub mod programmatic_scrypto_sbor_value_u8; +pub use self::programmatic_scrypto_sbor_value_u8::ProgrammaticScryptoSborValueU8; +pub mod public_key; +pub use self::public_key::PublicKey; +pub mod public_key_ecdsa_secp256k1; +pub use self::public_key_ecdsa_secp256k1::PublicKeyEcdsaSecp256k1; +pub mod public_key_eddsa_ed25519; +pub use self::public_key_eddsa_ed25519::PublicKeyEddsaEd25519; +pub mod public_key_hash; +pub use self::public_key_hash::PublicKeyHash; +pub mod public_key_hash_ecdsa_secp256k1; +pub use self::public_key_hash_ecdsa_secp256k1::PublicKeyHashEcdsaSecp256k1; +pub mod public_key_hash_eddsa_ed25519; +pub use self::public_key_hash_eddsa_ed25519::PublicKeyHashEddsaEd25519; +pub mod public_key_hash_type; +pub use self::public_key_hash_type::PublicKeyHashType; +pub mod public_key_type; +pub use self::public_key_type::PublicKeyType; +pub mod resource_aggregation_level; +pub use self::resource_aggregation_level::ResourceAggregationLevel; +pub mod result_set_cursor_mixin; +pub use self::result_set_cursor_mixin::ResultSetCursorMixin; +pub mod role_assignment_resolution; +pub use self::role_assignment_resolution::RoleAssignmentResolution; +pub mod role_key; +pub use self::role_key::RoleKey; +pub mod scrypto_sbor_value; +pub use self::scrypto_sbor_value::ScryptoSborValue; +pub mod state_entity_details_opt_ins; +pub use self::state_entity_details_opt_ins::StateEntityDetailsOptIns; +pub mod state_entity_details_request; +pub use self::state_entity_details_request::StateEntityDetailsRequest; +pub mod state_entity_details_response; +pub use self::state_entity_details_response::StateEntityDetailsResponse; +pub mod state_entity_details_response_component_details; +pub use self::state_entity_details_response_component_details::StateEntityDetailsResponseComponentDetails; +pub mod state_entity_details_response_fungible_resource_details; +pub use self::state_entity_details_response_fungible_resource_details::StateEntityDetailsResponseFungibleResourceDetails; +pub mod state_entity_details_response_fungible_vault_details; +pub use self::state_entity_details_response_fungible_vault_details::StateEntityDetailsResponseFungibleVaultDetails; +pub mod state_entity_details_response_item; +pub use self::state_entity_details_response_item::StateEntityDetailsResponseItem; +pub mod state_entity_details_response_item_ancestor_identities; +pub use self::state_entity_details_response_item_ancestor_identities::StateEntityDetailsResponseItemAncestorIdentities; +pub mod state_entity_details_response_item_details; +pub use self::state_entity_details_response_item_details::StateEntityDetailsResponseItemDetails; +pub mod state_entity_details_response_item_details_type; +pub use self::state_entity_details_response_item_details_type::StateEntityDetailsResponseItemDetailsType; +pub mod state_entity_details_response_non_fungible_resource_details; +pub use self::state_entity_details_response_non_fungible_resource_details::StateEntityDetailsResponseNonFungibleResourceDetails; +pub mod state_entity_details_response_non_fungible_vault_details; +pub use self::state_entity_details_response_non_fungible_vault_details::StateEntityDetailsResponseNonFungibleVaultDetails; +pub mod state_entity_details_response_package_details; +pub use self::state_entity_details_response_package_details::StateEntityDetailsResponsePackageDetails; +pub mod state_entity_details_response_package_details_blueprint_collection; +pub use self::state_entity_details_response_package_details_blueprint_collection::StateEntityDetailsResponsePackageDetailsBlueprintCollection; +pub mod state_entity_details_response_package_details_blueprint_item; +pub use self::state_entity_details_response_package_details_blueprint_item::StateEntityDetailsResponsePackageDetailsBlueprintItem; +pub mod state_entity_details_response_package_details_schema_collection; +pub use self::state_entity_details_response_package_details_schema_collection::StateEntityDetailsResponsePackageDetailsSchemaCollection; +pub mod state_entity_details_response_package_details_schema_item; +pub use self::state_entity_details_response_package_details_schema_item::StateEntityDetailsResponsePackageDetailsSchemaItem; +pub mod state_entity_fungible_resource_vaults_page_request; +pub use self::state_entity_fungible_resource_vaults_page_request::StateEntityFungibleResourceVaultsPageRequest; +pub mod state_entity_fungible_resource_vaults_page_response; +pub use self::state_entity_fungible_resource_vaults_page_response::StateEntityFungibleResourceVaultsPageResponse; +pub mod state_entity_fungibles_page_request; +pub use self::state_entity_fungibles_page_request::StateEntityFungiblesPageRequest; +pub mod state_entity_fungibles_page_request_opt_ins; +pub use self::state_entity_fungibles_page_request_opt_ins::StateEntityFungiblesPageRequestOptIns; +pub mod state_entity_fungibles_page_response; +pub use self::state_entity_fungibles_page_response::StateEntityFungiblesPageResponse; +pub mod state_entity_metadata_page_request; +pub use self::state_entity_metadata_page_request::StateEntityMetadataPageRequest; +pub mod state_entity_metadata_page_response; +pub use self::state_entity_metadata_page_response::StateEntityMetadataPageResponse; +pub mod state_entity_non_fungible_ids_page_request; +pub use self::state_entity_non_fungible_ids_page_request::StateEntityNonFungibleIdsPageRequest; +pub mod state_entity_non_fungible_ids_page_response; +pub use self::state_entity_non_fungible_ids_page_response::StateEntityNonFungibleIdsPageResponse; +pub mod state_entity_non_fungible_resource_vaults_page_opt_ins; +pub use self::state_entity_non_fungible_resource_vaults_page_opt_ins::StateEntityNonFungibleResourceVaultsPageOptIns; +pub mod state_entity_non_fungible_resource_vaults_page_request; +pub use self::state_entity_non_fungible_resource_vaults_page_request::StateEntityNonFungibleResourceVaultsPageRequest; +pub mod state_entity_non_fungible_resource_vaults_page_response; +pub use self::state_entity_non_fungible_resource_vaults_page_response::StateEntityNonFungibleResourceVaultsPageResponse; +pub mod state_entity_non_fungibles_page_request; +pub use self::state_entity_non_fungibles_page_request::StateEntityNonFungiblesPageRequest; +pub mod state_entity_non_fungibles_page_request_opt_ins; +pub use self::state_entity_non_fungibles_page_request_opt_ins::StateEntityNonFungiblesPageRequestOptIns; +pub mod state_entity_non_fungibles_page_response; +pub use self::state_entity_non_fungibles_page_response::StateEntityNonFungiblesPageResponse; +pub mod state_key_value_store_data_request; +pub use self::state_key_value_store_data_request::StateKeyValueStoreDataRequest; +pub mod state_key_value_store_data_request_key_item; +pub use self::state_key_value_store_data_request_key_item::StateKeyValueStoreDataRequestKeyItem; +pub mod state_key_value_store_data_response; +pub use self::state_key_value_store_data_response::StateKeyValueStoreDataResponse; +pub mod state_key_value_store_data_response_item; +pub use self::state_key_value_store_data_response_item::StateKeyValueStoreDataResponseItem; +pub mod state_non_fungible_data_request; +pub use self::state_non_fungible_data_request::StateNonFungibleDataRequest; +pub mod state_non_fungible_data_response; +pub use self::state_non_fungible_data_response::StateNonFungibleDataResponse; +pub mod state_non_fungible_details_response_item; +pub use self::state_non_fungible_details_response_item::StateNonFungibleDetailsResponseItem; +pub mod state_non_fungible_ids_request; +pub use self::state_non_fungible_ids_request::StateNonFungibleIdsRequest; +pub mod state_non_fungible_ids_response; +pub use self::state_non_fungible_ids_response::StateNonFungibleIdsResponse; +pub mod state_non_fungible_location_request; +pub use self::state_non_fungible_location_request::StateNonFungibleLocationRequest; +pub mod state_non_fungible_location_response; +pub use self::state_non_fungible_location_response::StateNonFungibleLocationResponse; +pub mod state_non_fungible_location_response_item; +pub use self::state_non_fungible_location_response_item::StateNonFungibleLocationResponseItem; +pub mod state_validators_list_request; +pub use self::state_validators_list_request::StateValidatorsListRequest; +pub mod state_validators_list_response; +pub use self::state_validators_list_response::StateValidatorsListResponse; +pub mod stream_transactions_request; +pub use self::stream_transactions_request::StreamTransactionsRequest; +pub mod stream_transactions_request_event_filter_item; +pub use self::stream_transactions_request_event_filter_item::StreamTransactionsRequestEventFilterItem; +pub mod stream_transactions_response; +pub use self::stream_transactions_response::StreamTransactionsResponse; +pub mod transaction_balance_changes; +pub use self::transaction_balance_changes::TransactionBalanceChanges; +pub mod transaction_committed_details_request; +pub use self::transaction_committed_details_request::TransactionCommittedDetailsRequest; +pub mod transaction_committed_details_response; +pub use self::transaction_committed_details_response::TransactionCommittedDetailsResponse; +pub mod transaction_construction_response; +pub use self::transaction_construction_response::TransactionConstructionResponse; +pub mod transaction_details_opt_ins; +pub use self::transaction_details_opt_ins::TransactionDetailsOptIns; +pub mod transaction_fungible_balance_changes; +pub use self::transaction_fungible_balance_changes::TransactionFungibleBalanceChanges; +pub mod transaction_fungible_fee_balance_change_type; +pub use self::transaction_fungible_fee_balance_change_type::TransactionFungibleFeeBalanceChangeType; +pub mod transaction_fungible_fee_balance_changes; +pub use self::transaction_fungible_fee_balance_changes::TransactionFungibleFeeBalanceChanges; +pub mod transaction_intent_status; +pub use self::transaction_intent_status::TransactionIntentStatus; +pub mod transaction_non_fungible_balance_changes; +pub use self::transaction_non_fungible_balance_changes::TransactionNonFungibleBalanceChanges; +pub mod transaction_not_found_error; +pub use self::transaction_not_found_error::TransactionNotFoundError; +pub mod transaction_payload_gateway_handling_status; +pub use self::transaction_payload_gateway_handling_status::TransactionPayloadGatewayHandlingStatus; +pub mod transaction_payload_status; +pub use self::transaction_payload_status::TransactionPayloadStatus; +pub mod transaction_preview_request; +pub use self::transaction_preview_request::TransactionPreviewRequest; +pub mod transaction_preview_request_flags; +pub use self::transaction_preview_request_flags::TransactionPreviewRequestFlags; +pub mod transaction_preview_response; +pub use self::transaction_preview_response::TransactionPreviewResponse; +pub mod transaction_preview_response_logs_inner; +pub use self::transaction_preview_response_logs_inner::TransactionPreviewResponseLogsInner; +pub mod transaction_receipt; +pub use self::transaction_receipt::{Entity, StateUpdates, TransactionReceipt}; +pub mod transaction_status; +pub use self::transaction_status::TransactionStatus; +pub mod transaction_status_request; +pub use self::transaction_status_request::TransactionStatusRequest; +pub mod transaction_status_response; +pub use self::transaction_status_response::TransactionStatusResponse; +pub mod transaction_status_response_known_payload_item; +pub use self::transaction_status_response_known_payload_item::TransactionStatusResponseKnownPayloadItem; +pub mod transaction_submit_request; +pub use self::transaction_submit_request::TransactionSubmitRequest; +pub mod transaction_submit_response; +pub use self::transaction_submit_response::TransactionSubmitResponse; +pub mod validation_errors_at_path; +pub use self::validation_errors_at_path::ValidationErrorsAtPath; +pub mod validator_collection; +pub use self::validator_collection::ValidatorCollection; +pub mod validator_collection_item; +pub use self::validator_collection_item::ValidatorCollectionItem; +pub mod validator_collection_item_active_in_epoch; +pub use self::validator_collection_item_active_in_epoch::ValidatorCollectionItemActiveInEpoch; +pub mod validator_collection_item_effective_fee_factor; +pub use self::validator_collection_item_effective_fee_factor::ValidatorCollectionItemEffectiveFeeFactor; +pub mod validator_collection_item_effective_fee_factor_current; +pub use self::validator_collection_item_effective_fee_factor_current::ValidatorCollectionItemEffectiveFeeFactorCurrent; +pub mod validator_collection_item_effective_fee_factor_pending; +pub use self::validator_collection_item_effective_fee_factor_pending::ValidatorCollectionItemEffectiveFeeFactorPending; +pub mod validator_uptime_collection; +pub use self::validator_uptime_collection::ValidatorUptimeCollection; +pub mod validator_uptime_collection_item; +pub use self::validator_uptime_collection_item::ValidatorUptimeCollectionItem; +pub mod validator_vault_item; +pub use self::validator_vault_item::ValidatorVaultItem; +pub mod validators_uptime_request; +pub use self::validators_uptime_request::ValidatorsUptimeRequest; +pub mod validators_uptime_response; +pub use self::validators_uptime_response::ValidatorsUptimeResponse; diff --git a/libraries/gateway-client/src/models/network_configuration_response.rs b/libraries/gateway-client/src/models/network_configuration_response.rs new file mode 100644 index 00000000..3e646c61 --- /dev/null +++ b/libraries/gateway-client/src/models/network_configuration_response.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NetworkConfigurationResponse { + #[serde(rename = "network_id")] + pub network_id: i32, + + #[serde(rename = "network_name")] + pub network_name: String, + #[serde(rename = "well_known_addresses")] + pub well_known_addresses: + Box, +} + +impl NetworkConfigurationResponse { + pub fn new( + network_id: i32, + network_name: String, + well_known_addresses: crate::models::NetworkConfigurationResponseWellKnownAddresses, + ) -> NetworkConfigurationResponse { + NetworkConfigurationResponse { + network_id, + network_name, + well_known_addresses: Box::new(well_known_addresses), + } + } +} diff --git a/libraries/gateway-client/src/models/network_configuration_response_well_known_addresses.rs b/libraries/gateway-client/src/models/network_configuration_response_well_known_addresses.rs new file mode 100644 index 00000000..7e59d87a --- /dev/null +++ b/libraries/gateway-client/src/models/network_configuration_response_well_known_addresses.rs @@ -0,0 +1,140 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NetworkConfigurationResponseWellKnownAddresses { + #[serde(rename = "xrd")] + pub xrd: String, + + #[serde(rename = "secp256k1_signature_virtual_badge")] + pub secp256k1_signature_virtual_badge: String, + + #[serde(rename = "ed25519_signature_virtual_badge")] + pub ed25519_signature_virtual_badge: String, + + #[serde(rename = "package_of_direct_caller_virtual_badge")] + pub package_of_direct_caller_virtual_badge: String, + + #[serde(rename = "global_caller_virtual_badge")] + pub global_caller_virtual_badge: String, + + #[serde(rename = "system_transaction_badge")] + pub system_transaction_badge: String, + + #[serde(rename = "package_owner_badge")] + pub package_owner_badge: String, + + #[serde(rename = "validator_owner_badge")] + pub validator_owner_badge: String, + + #[serde(rename = "account_owner_badge")] + pub account_owner_badge: String, + + #[serde(rename = "identity_owner_badge")] + pub identity_owner_badge: String, + + #[serde(rename = "package_package")] + pub package_package: String, + + #[serde(rename = "resource_package")] + pub resource_package: String, + + #[serde(rename = "account_package")] + pub account_package: String, + + #[serde(rename = "identity_package")] + pub identity_package: String, + + #[serde(rename = "consensus_manager_package")] + pub consensus_manager_package: String, + + #[serde(rename = "access_controller_package")] + pub access_controller_package: String, + + #[serde(rename = "transaction_processor_package")] + pub transaction_processor_package: String, + + #[serde(rename = "metadata_module_package")] + pub metadata_module_package: String, + + #[serde(rename = "royalty_module_package")] + pub royalty_module_package: String, + + #[serde(rename = "access_rules_package")] + pub access_rules_package: String, + + #[serde(rename = "genesis_helper_package")] + pub genesis_helper_package: String, + + #[serde(rename = "faucet_package")] + pub faucet_package: String, + + #[serde(rename = "consensus_manager")] + pub consensus_manager: String, + + #[serde(rename = "genesis_helper")] + pub genesis_helper: String, + + #[serde(rename = "faucet")] + pub faucet: String, + + #[serde(rename = "pool_package")] + pub pool_package: String, +} + +impl NetworkConfigurationResponseWellKnownAddresses { + pub fn new( + xrd: String, + secp256k1_signature_virtual_badge: String, + ed25519_signature_virtual_badge: String, + package_of_direct_caller_virtual_badge: String, + global_caller_virtual_badge: String, + system_transaction_badge: String, + package_owner_badge: String, + validator_owner_badge: String, + account_owner_badge: String, + identity_owner_badge: String, + package_package: String, + resource_package: String, + account_package: String, + identity_package: String, + consensus_manager_package: String, + access_controller_package: String, + transaction_processor_package: String, + metadata_module_package: String, + royalty_module_package: String, + access_rules_package: String, + genesis_helper_package: String, + faucet_package: String, + consensus_manager: String, + genesis_helper: String, + faucet: String, + pool_package: String, + ) -> NetworkConfigurationResponseWellKnownAddresses { + NetworkConfigurationResponseWellKnownAddresses { + xrd, + secp256k1_signature_virtual_badge, + ed25519_signature_virtual_badge, + package_of_direct_caller_virtual_badge, + global_caller_virtual_badge, + system_transaction_badge, + package_owner_badge, + validator_owner_badge, + account_owner_badge, + identity_owner_badge, + package_package, + resource_package, + account_package, + identity_package, + consensus_manager_package, + access_controller_package, + transaction_processor_package, + metadata_module_package, + royalty_module_package, + access_rules_package, + genesis_helper_package, + faucet_package, + consensus_manager, + genesis_helper, + faucet, + pool_package, + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_id_type.rs b/libraries/gateway-client/src/models/non_fungible_id_type.rs new file mode 100644 index 00000000..ca9bd66e --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_id_type.rs @@ -0,0 +1,39 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum NonFungibleIdType { + #[serde(rename = "String")] + String, + #[serde(rename = "Integer")] + Integer, + #[serde(rename = "Bytes")] + Bytes, + #[serde(rename = "Ruid")] + Ruid, +} + +impl ToString for NonFungibleIdType { + fn to_string(&self) -> String { + match self { + Self::String => String::from("String"), + Self::Integer => String::from("Integer"), + Self::Bytes => String::from("Bytes"), + Self::Ruid => String::from("Ruid"), + } + } +} + +impl Default for NonFungibleIdType { + fn default() -> NonFungibleIdType { + Self::String + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_ids_collection.rs b/libraries/gateway-client/src/models/non_fungible_ids_collection.rs new file mode 100644 index 00000000..6a4730b0 --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_ids_collection.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleIdsCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl NonFungibleIdsCollection { + pub fn new(items: Vec) -> NonFungibleIdsCollection { + NonFungibleIdsCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection.rs new file mode 100644 index 00000000..60e0460f --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleResourcesCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl NonFungibleResourcesCollection { + pub fn new( + items: Vec, + ) -> NonFungibleResourcesCollection { + NonFungibleResourcesCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection_item.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection_item.rs new file mode 100644 index 00000000..9139f899 --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection_item.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum NonFungibleResourcesCollectionItem {} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection_item_globally_aggregated.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_globally_aggregated.rs new file mode 100644 index 00000000..6f552ec8 --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_globally_aggregated.rs @@ -0,0 +1,36 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleResourcesCollectionItemGloballyAggregated { + #[serde(rename = "aggregation_level")] + pub aggregation_level: crate::models::ResourceAggregationLevel, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, + + #[serde(rename = "amount")] + pub amount: i64, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl NonFungibleResourcesCollectionItemGloballyAggregated { + pub fn new( + aggregation_level: crate::models::ResourceAggregationLevel, + resource_address: String, + amount: i64, + last_updated_at_state_version: i64, + ) -> NonFungibleResourcesCollectionItemGloballyAggregated { + NonFungibleResourcesCollectionItemGloballyAggregated { + aggregation_level, + resource_address, + explicit_metadata: None, + amount, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated.rs new file mode 100644 index 00000000..93b95973 --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleResourcesCollectionItemVaultAggregated { + #[serde(rename = "aggregation_level")] + pub aggregation_level: crate::models::ResourceAggregationLevel, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, + #[serde(rename = "vaults")] + pub vaults: Box< + crate::models::NonFungibleResourcesCollectionItemVaultAggregatedVault, + >, +} + +impl NonFungibleResourcesCollectionItemVaultAggregated { + pub fn new( + aggregation_level: crate::models::ResourceAggregationLevel, + resource_address: String, + vaults: crate::models::NonFungibleResourcesCollectionItemVaultAggregatedVault, + ) -> NonFungibleResourcesCollectionItemVaultAggregated { + NonFungibleResourcesCollectionItemVaultAggregated { + aggregation_level, + resource_address, + explicit_metadata: None, + vaults: Box::new(vaults), + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault.rs new file mode 100644 index 00000000..913b84f1 --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleResourcesCollectionItemVaultAggregatedVault { + + #[serde(rename = "total_count", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub total_count: Option>, + + #[serde(rename = "next_cursor", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl NonFungibleResourcesCollectionItemVaultAggregatedVault { + pub fn new( + items: Vec, + ) -> NonFungibleResourcesCollectionItemVaultAggregatedVault { + NonFungibleResourcesCollectionItemVaultAggregatedVault { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault_item.rs b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault_item.rs new file mode 100644 index 00000000..be0c743e --- /dev/null +++ b/libraries/gateway-client/src/models/non_fungible_resources_collection_item_vault_aggregated_vault_item.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NonFungibleResourcesCollectionItemVaultAggregatedVaultItem { + #[serde(rename = "total_count")] + pub total_count: i64, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items", skip_serializing_if = "Option::is_none")] + pub items: Option>, + + #[serde(rename = "vault_address")] + pub vault_address: String, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl NonFungibleResourcesCollectionItemVaultAggregatedVaultItem { + pub fn new( + total_count: i64, + vault_address: String, + last_updated_at_state_version: i64, + ) -> NonFungibleResourcesCollectionItemVaultAggregatedVaultItem { + NonFungibleResourcesCollectionItemVaultAggregatedVaultItem { + total_count, + next_cursor: None, + items: None, + vault_address, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/not_synced_up_error.rs b/libraries/gateway-client/src/models/not_synced_up_error.rs new file mode 100644 index 00000000..93e5d5bf --- /dev/null +++ b/libraries/gateway-client/src/models/not_synced_up_error.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NotSyncedUpError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "request_type")] + pub request_type: String, + + #[serde(rename = "current_sync_delay_seconds")] + pub current_sync_delay_seconds: i64, + + #[serde(rename = "max_allowed_sync_delay_seconds")] + pub max_allowed_sync_delay_seconds: i64, +} + +impl NotSyncedUpError { + pub fn new( + r#type: String, + request_type: String, + current_sync_delay_seconds: i64, + max_allowed_sync_delay_seconds: i64, + ) -> NotSyncedUpError { + NotSyncedUpError { + r#type, + request_type, + current_sync_delay_seconds, + max_allowed_sync_delay_seconds, + } + } +} diff --git a/libraries/gateway-client/src/models/object_module_id.rs b/libraries/gateway-client/src/models/object_module_id.rs new file mode 100644 index 00000000..d940c433 --- /dev/null +++ b/libraries/gateway-client/src/models/object_module_id.rs @@ -0,0 +1,39 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum ObjectModuleId { + #[serde(rename = "Main")] + Main, + #[serde(rename = "Metadata")] + Metadata, + #[serde(rename = "Royalty")] + Royalty, + #[serde(rename = "RoleAssignment")] + RoleAssignment, +} + +impl ToString for ObjectModuleId { + fn to_string(&self) -> String { + match self { + Self::Main => String::from("Main"), + Self::Metadata => String::from("Metadata"), + Self::Royalty => String::from("Royalty"), + Self::RoleAssignment => String::from("RoleAssignment"), + } + } +} + +impl Default for ObjectModuleId { + fn default() -> ObjectModuleId { + Self::Main + } +} diff --git a/libraries/gateway-client/src/models/optional_non_fungible_ids_collection.rs b/libraries/gateway-client/src/models/optional_non_fungible_ids_collection.rs new file mode 100644 index 00000000..36906743 --- /dev/null +++ b/libraries/gateway-client/src/models/optional_non_fungible_ids_collection.rs @@ -0,0 +1,36 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct OptionalNonFungibleIdsCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items", skip_serializing_if = "Option::is_none")] + pub items: Option>, +} + +impl Default for OptionalNonFungibleIdsCollection { + fn default() -> Self { + Self::new() + } +} + +impl OptionalNonFungibleIdsCollection { + pub fn new() -> OptionalNonFungibleIdsCollection { + OptionalNonFungibleIdsCollection { + total_count: None, + next_cursor: None, + items: None, + } + } +} diff --git a/libraries/gateway-client/src/models/package_vm_type.rs b/libraries/gateway-client/src/models/package_vm_type.rs new file mode 100644 index 00000000..bb990329 --- /dev/null +++ b/libraries/gateway-client/src/models/package_vm_type.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum PackageVmType { + #[serde(rename = "Native")] + Native, + #[serde(rename = "ScryptoV1")] + ScryptoV1, +} + +impl ToString for PackageVmType { + fn to_string(&self) -> String { + match self { + Self::Native => String::from("Native"), + Self::ScryptoV1 => String::from("ScryptoV1"), + } + } +} + +impl Default for PackageVmType { + fn default() -> PackageVmType { + Self::Native + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value.rs new file mode 100644 index 00000000..260cf8bc --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum ProgrammaticScryptoSborValue {} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_array.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_array.rs new file mode 100644 index 00000000..a42b3e7e --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_array.rs @@ -0,0 +1,47 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueArray { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "element_kind")] + pub element_kind: crate::models::ProgrammaticScryptoSborValueKind, + #[serde( + rename = "element_type_name", + skip_serializing_if = "Option::is_none" + )] + pub element_type_name: Option, + #[serde(rename = "elements")] + pub elements: Vec, +} + +impl ProgrammaticScryptoSborValueArray { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + element_kind: crate::models::ProgrammaticScryptoSborValueKind, + elements: Vec, + ) -> ProgrammaticScryptoSborValueArray { + ProgrammaticScryptoSborValueArray { + kind, + type_name: None, + field_name: None, + element_kind, + element_type_name: None, + elements, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bool.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bool.rs new file mode 100644 index 00000000..e8c9adf6 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bool.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueBool { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: bool, +} + +impl ProgrammaticScryptoSborValueBool { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: bool, + ) -> ProgrammaticScryptoSborValueBool { + ProgrammaticScryptoSborValueBool { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bytes.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bytes.rs new file mode 100644 index 00000000..1afc7c36 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_bytes.rs @@ -0,0 +1,48 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueBytes { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "element_kind")] + pub element_kind: crate::models::ProgrammaticScryptoSborValueKind, + #[serde( + rename = "element_type_name", + skip_serializing_if = "Option::is_none" + )] + pub element_type_name: Option, + + #[serde(rename = "hex")] + pub hex: String, +} + +impl ProgrammaticScryptoSborValueBytes { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + element_kind: crate::models::ProgrammaticScryptoSborValueKind, + hex: String, + ) -> ProgrammaticScryptoSborValueBytes { + ProgrammaticScryptoSborValueBytes { + kind, + type_name: None, + field_name: None, + element_kind, + element_type_name: None, + hex, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_decimal.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_decimal.rs new file mode 100644 index 00000000..a813f189 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_decimal.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueDecimal { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueDecimal { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueDecimal { + ProgrammaticScryptoSborValueDecimal { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_enum.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_enum.rs new file mode 100644 index 00000000..1fa9a290 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_enum.rs @@ -0,0 +1,44 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueEnum { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "variant_id")] + pub variant_id: i32, + #[serde(rename = "variant_name", skip_serializing_if = "Option::is_none")] + pub variant_name: Option, + #[serde(rename = "fields")] + pub fields: Vec, +} + +impl ProgrammaticScryptoSborValueEnum { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + variant_id: i32, + fields: Vec, + ) -> ProgrammaticScryptoSborValueEnum { + ProgrammaticScryptoSborValueEnum { + kind, + type_name: None, + field_name: None, + variant_id, + variant_name: None, + fields, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i128.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i128.rs new file mode 100644 index 00000000..8e29f78f --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i128.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueI128 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueI128 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueI128 { + ProgrammaticScryptoSborValueI128 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i16.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i16.rs new file mode 100644 index 00000000..0f75087b --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i16.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueI16 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueI16 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueI16 { + ProgrammaticScryptoSborValueI16 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i32.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i32.rs new file mode 100644 index 00000000..0865863e --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i32.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueI32 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueI32 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueI32 { + ProgrammaticScryptoSborValueI32 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i64.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i64.rs new file mode 100644 index 00000000..2e7c934f --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i64.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueI64 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueI64 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueI64 { + ProgrammaticScryptoSborValueI64 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i8.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i8.rs new file mode 100644 index 00000000..fa56cc58 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_i8.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueI8 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueI8 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueI8 { + ProgrammaticScryptoSborValueI8 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_kind.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_kind.rs new file mode 100644 index 00000000..4d19b7e0 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_kind.rs @@ -0,0 +1,93 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum ProgrammaticScryptoSborValueKind { + #[serde(rename = "Bool")] + Bool, + #[serde(rename = "I8")] + I8, + #[serde(rename = "I16")] + I16, + #[serde(rename = "I32")] + I32, + #[serde(rename = "I64")] + I64, + #[serde(rename = "I128")] + I128, + #[serde(rename = "U8")] + U8, + #[serde(rename = "U16")] + U16, + #[serde(rename = "U32")] + U32, + #[serde(rename = "U64")] + U64, + #[serde(rename = "U128")] + U128, + #[serde(rename = "String")] + String, + #[serde(rename = "Enum")] + Enum, + #[serde(rename = "Array")] + Array, + #[serde(rename = "Bytes")] + Bytes, + #[serde(rename = "Map")] + Map, + #[serde(rename = "Tuple")] + Tuple, + #[serde(rename = "Reference")] + Reference, + #[serde(rename = "Own")] + Own, + #[serde(rename = "Decimal")] + Decimal, + #[serde(rename = "PreciseDecimal")] + PreciseDecimal, + #[serde(rename = "NonFungibleLocalId")] + NonFungibleLocalId, +} + +impl ToString for ProgrammaticScryptoSborValueKind { + fn to_string(&self) -> String { + match self { + Self::Bool => String::from("Bool"), + Self::I8 => String::from("I8"), + Self::I16 => String::from("I16"), + Self::I32 => String::from("I32"), + Self::I64 => String::from("I64"), + Self::I128 => String::from("I128"), + Self::U8 => String::from("U8"), + Self::U16 => String::from("U16"), + Self::U32 => String::from("U32"), + Self::U64 => String::from("U64"), + Self::U128 => String::from("U128"), + Self::String => String::from("String"), + Self::Enum => String::from("Enum"), + Self::Array => String::from("Array"), + Self::Bytes => String::from("Bytes"), + Self::Map => String::from("Map"), + Self::Tuple => String::from("Tuple"), + Self::Reference => String::from("Reference"), + Self::Own => String::from("Own"), + Self::Decimal => String::from("Decimal"), + Self::PreciseDecimal => String::from("PreciseDecimal"), + Self::NonFungibleLocalId => String::from("NonFungibleLocalId"), + } + } +} + +impl Default for ProgrammaticScryptoSborValueKind { + fn default() -> ProgrammaticScryptoSborValueKind { + Self::Bool + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map.rs new file mode 100644 index 00000000..2da55594 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map.rs @@ -0,0 +1,54 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueMap { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "key_kind")] + pub key_kind: crate::models::ProgrammaticScryptoSborValueKind, + #[serde(rename = "key_type_name", skip_serializing_if = "Option::is_none")] + pub key_type_name: Option, + #[serde(rename = "value_kind")] + pub value_kind: crate::models::ProgrammaticScryptoSborValueKind, + #[serde( + rename = "value_type_name", + skip_serializing_if = "Option::is_none" + )] + pub value_type_name: Option, + #[serde(rename = "entries")] + pub entries: Vec, +} + +impl ProgrammaticScryptoSborValueMap { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + key_kind: crate::models::ProgrammaticScryptoSborValueKind, + value_kind: crate::models::ProgrammaticScryptoSborValueKind, + entries: Vec, + ) -> ProgrammaticScryptoSborValueMap { + ProgrammaticScryptoSborValueMap { + kind, + type_name: None, + field_name: None, + key_kind, + key_type_name: None, + value_kind, + value_type_name: None, + entries, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map_entry.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map_entry.rs new file mode 100644 index 00000000..b37dfaa3 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_map_entry.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueMapEntry { + #[serde(rename = "key")] + pub key: Box, + #[serde(rename = "value")] + pub value: Box, +} + +impl ProgrammaticScryptoSborValueMapEntry { + pub fn new( + key: crate::models::ProgrammaticScryptoSborValue, + value: crate::models::ProgrammaticScryptoSborValue, + ) -> ProgrammaticScryptoSborValueMapEntry { + ProgrammaticScryptoSborValueMapEntry { + key: Box::new(key), + value: Box::new(value), + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_non_fungible_local_id.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_non_fungible_local_id.rs new file mode 100644 index 00000000..50daa711 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_non_fungible_local_id.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueNonFungibleLocalId { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueNonFungibleLocalId { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueNonFungibleLocalId { + ProgrammaticScryptoSborValueNonFungibleLocalId { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_own.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_own.rs new file mode 100644 index 00000000..3a944eb7 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_own.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueOwn { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueOwn { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueOwn { + ProgrammaticScryptoSborValueOwn { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_precise_decimal.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_precise_decimal.rs new file mode 100644 index 00000000..9823e998 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_precise_decimal.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValuePreciseDecimal { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValuePreciseDecimal { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValuePreciseDecimal { + ProgrammaticScryptoSborValuePreciseDecimal { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_reference.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_reference.rs new file mode 100644 index 00000000..44078bc5 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_reference.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueReference { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueReference { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueReference { + ProgrammaticScryptoSborValueReference { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_string.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_string.rs new file mode 100644 index 00000000..277848ef --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_string.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueString { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueString { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueString { + ProgrammaticScryptoSborValueString { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_tuple.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_tuple.rs new file mode 100644 index 00000000..8c154c07 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_tuple.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueTuple { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "fields")] + pub fields: Vec, +} + +impl ProgrammaticScryptoSborValueTuple { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + fields: Vec, + ) -> ProgrammaticScryptoSborValueTuple { + ProgrammaticScryptoSborValueTuple { + kind, + type_name: None, + field_name: None, + fields, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u128.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u128.rs new file mode 100644 index 00000000..ad67cdca --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u128.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueU128 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueU128 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueU128 { + ProgrammaticScryptoSborValueU128 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u16.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u16.rs new file mode 100644 index 00000000..42a4d685 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u16.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueU16 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueU16 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueU16 { + ProgrammaticScryptoSborValueU16 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u32.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u32.rs new file mode 100644 index 00000000..81dec0d6 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u32.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueU32 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueU32 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueU32 { + ProgrammaticScryptoSborValueU32 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u64.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u64.rs new file mode 100644 index 00000000..52c1a2a6 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u64.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueU64 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueU64 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueU64 { + ProgrammaticScryptoSborValueU64 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u8.rs b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u8.rs new file mode 100644 index 00000000..77821ba8 --- /dev/null +++ b/libraries/gateway-client/src/models/programmatic_scrypto_sbor_value_u8.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ProgrammaticScryptoSborValueU8 { + #[serde(rename = "kind")] + pub kind: crate::models::ProgrammaticScryptoSborValueKind, + + #[serde( + rename = "type_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub type_name: Option>, + + #[serde( + rename = "field_name", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub field_name: Option>, + #[serde(rename = "value")] + pub value: String, +} + +impl ProgrammaticScryptoSborValueU8 { + pub fn new( + kind: crate::models::ProgrammaticScryptoSborValueKind, + value: String, + ) -> ProgrammaticScryptoSborValueU8 { + ProgrammaticScryptoSborValueU8 { + kind, + type_name: None, + field_name: None, + value, + } + } +} diff --git a/libraries/gateway-client/src/models/public_key.rs b/libraries/gateway-client/src/models/public_key.rs new file mode 100644 index 00000000..6a95950d --- /dev/null +++ b/libraries/gateway-client/src/models/public_key.rs @@ -0,0 +1,15 @@ +#[serde_with::serde_as] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "key_type")] +pub enum PublicKey { + EcdsaSecp256k1 { + #[serde_as(as = "serde_with::hex::Hex")] + #[serde(rename = "key_hex")] + key: [u8; 33], + }, + EddsaEd25519 { + #[serde_as(as = "serde_with::hex::Hex")] + #[serde(rename = "key_hex")] + key: [u8; 32], + }, +} diff --git a/libraries/gateway-client/src/models/public_key_ecdsa_secp256k1.rs b/libraries/gateway-client/src/models/public_key_ecdsa_secp256k1.rs new file mode 100644 index 00000000..f3fee956 --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_ecdsa_secp256k1.rs @@ -0,0 +1,17 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PublicKeyEcdsaSecp256k1 { + #[serde(rename = "key_type")] + pub key_type: crate::models::PublicKeyType, + + #[serde(rename = "key_hex")] + pub key_hex: String, +} + +impl PublicKeyEcdsaSecp256k1 { + pub fn new( + key_type: crate::models::PublicKeyType, + key_hex: String, + ) -> PublicKeyEcdsaSecp256k1 { + PublicKeyEcdsaSecp256k1 { key_type, key_hex } + } +} diff --git a/libraries/gateway-client/src/models/public_key_eddsa_ed25519.rs b/libraries/gateway-client/src/models/public_key_eddsa_ed25519.rs new file mode 100644 index 00000000..57c534d7 --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_eddsa_ed25519.rs @@ -0,0 +1,17 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PublicKeyEddsaEd25519 { + #[serde(rename = "key_type")] + pub key_type: crate::models::PublicKeyType, + + #[serde(rename = "key_hex")] + pub key_hex: String, +} + +impl PublicKeyEddsaEd25519 { + pub fn new( + key_type: crate::models::PublicKeyType, + key_hex: String, + ) -> PublicKeyEddsaEd25519 { + PublicKeyEddsaEd25519 { key_type, key_hex } + } +} diff --git a/libraries/gateway-client/src/models/public_key_hash.rs b/libraries/gateway-client/src/models/public_key_hash.rs new file mode 100644 index 00000000..4d6417df --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_hash.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum PublicKeyHash {} diff --git a/libraries/gateway-client/src/models/public_key_hash_ecdsa_secp256k1.rs b/libraries/gateway-client/src/models/public_key_hash_ecdsa_secp256k1.rs new file mode 100644 index 00000000..6c354791 --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_hash_ecdsa_secp256k1.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PublicKeyHashEcdsaSecp256k1 { + #[serde(rename = "key_hash_type")] + pub key_hash_type: crate::models::PublicKeyHashType, + + #[serde(rename = "hash_hex")] + pub hash_hex: String, +} + +impl PublicKeyHashEcdsaSecp256k1 { + pub fn new( + key_hash_type: crate::models::PublicKeyHashType, + hash_hex: String, + ) -> PublicKeyHashEcdsaSecp256k1 { + PublicKeyHashEcdsaSecp256k1 { + key_hash_type, + hash_hex, + } + } +} diff --git a/libraries/gateway-client/src/models/public_key_hash_eddsa_ed25519.rs b/libraries/gateway-client/src/models/public_key_hash_eddsa_ed25519.rs new file mode 100644 index 00000000..ebd37009 --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_hash_eddsa_ed25519.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PublicKeyHashEddsaEd25519 { + #[serde(rename = "key_hash_type")] + pub key_hash_type: crate::models::PublicKeyHashType, + + #[serde(rename = "hash_hex")] + pub hash_hex: String, +} + +impl PublicKeyHashEddsaEd25519 { + pub fn new( + key_hash_type: crate::models::PublicKeyHashType, + hash_hex: String, + ) -> PublicKeyHashEddsaEd25519 { + PublicKeyHashEddsaEd25519 { + key_hash_type, + hash_hex, + } + } +} diff --git a/libraries/gateway-client/src/models/public_key_hash_type.rs b/libraries/gateway-client/src/models/public_key_hash_type.rs new file mode 100644 index 00000000..d492e527 --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_hash_type.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum PublicKeyHashType { + #[serde(rename = "EcdsaSecp256k1")] + EcdsaSecp256k1, + #[serde(rename = "EddsaEd25519")] + EddsaEd25519, +} + +impl ToString for PublicKeyHashType { + fn to_string(&self) -> String { + match self { + Self::EcdsaSecp256k1 => String::from("EcdsaSecp256k1"), + Self::EddsaEd25519 => String::from("EddsaEd25519"), + } + } +} + +impl Default for PublicKeyHashType { + fn default() -> PublicKeyHashType { + Self::EcdsaSecp256k1 + } +} diff --git a/libraries/gateway-client/src/models/public_key_type.rs b/libraries/gateway-client/src/models/public_key_type.rs new file mode 100644 index 00000000..e3af59cb --- /dev/null +++ b/libraries/gateway-client/src/models/public_key_type.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum PublicKeyType { + #[serde(rename = "EcdsaSecp256k1")] + EcdsaSecp256k1, + #[serde(rename = "EddsaEd25519")] + EddsaEd25519, +} + +impl ToString for PublicKeyType { + fn to_string(&self) -> String { + match self { + Self::EcdsaSecp256k1 => String::from("EcdsaSecp256k1"), + Self::EddsaEd25519 => String::from("EddsaEd25519"), + } + } +} + +impl Default for PublicKeyType { + fn default() -> PublicKeyType { + Self::EcdsaSecp256k1 + } +} diff --git a/libraries/gateway-client/src/models/resource_aggregation_level.rs b/libraries/gateway-client/src/models/resource_aggregation_level.rs new file mode 100644 index 00000000..184784df --- /dev/null +++ b/libraries/gateway-client/src/models/resource_aggregation_level.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum ResourceAggregationLevel { + #[serde(rename = "Global")] + Global, + #[serde(rename = "Vault")] + Vault, +} + +impl ToString for ResourceAggregationLevel { + fn to_string(&self) -> String { + match self { + Self::Global => String::from("Global"), + Self::Vault => String::from("Vault"), + } + } +} + +impl Default for ResourceAggregationLevel { + fn default() -> ResourceAggregationLevel { + Self::Global + } +} diff --git a/libraries/gateway-client/src/models/result_set_cursor_mixin.rs b/libraries/gateway-client/src/models/result_set_cursor_mixin.rs new file mode 100644 index 00000000..fefbad69 --- /dev/null +++ b/libraries/gateway-client/src/models/result_set_cursor_mixin.rs @@ -0,0 +1,33 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ResultSetCursorMixin { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, +} + +impl Default for ResultSetCursorMixin { + fn default() -> Self { + Self::new() + } +} + +impl ResultSetCursorMixin { + pub fn new() -> ResultSetCursorMixin { + ResultSetCursorMixin { + total_count: None, + next_cursor: None, + } + } +} diff --git a/libraries/gateway-client/src/models/role_assignment_resolution.rs b/libraries/gateway-client/src/models/role_assignment_resolution.rs new file mode 100644 index 00000000..18292fb2 --- /dev/null +++ b/libraries/gateway-client/src/models/role_assignment_resolution.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum RoleAssignmentResolution { + #[serde(rename = "Explicit")] + Explicit, + #[serde(rename = "Owner")] + Owner, +} + +impl ToString for RoleAssignmentResolution { + fn to_string(&self) -> String { + match self { + Self::Explicit => String::from("Explicit"), + Self::Owner => String::from("Owner"), + } + } +} + +impl Default for RoleAssignmentResolution { + fn default() -> RoleAssignmentResolution { + Self::Explicit + } +} diff --git a/libraries/gateway-client/src/models/role_key.rs b/libraries/gateway-client/src/models/role_key.rs new file mode 100644 index 00000000..3a856b32 --- /dev/null +++ b/libraries/gateway-client/src/models/role_key.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct RoleKey { + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "module")] + pub module: crate::models::ObjectModuleId, +} + +impl RoleKey { + pub fn new(name: String, module: crate::models::ObjectModuleId) -> RoleKey { + RoleKey { name, module } + } +} diff --git a/libraries/gateway-client/src/models/scrypto_sbor_value.rs b/libraries/gateway-client/src/models/scrypto_sbor_value.rs new file mode 100644 index 00000000..13a7c80c --- /dev/null +++ b/libraries/gateway-client/src/models/scrypto_sbor_value.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ScryptoSborValue { + #[serde(rename = "raw_hex")] + pub raw_hex: String, + #[serde(rename = "programmatic_json")] + pub programmatic_json: Box, +} + +impl ScryptoSborValue { + pub fn new( + raw_hex: String, + programmatic_json: crate::models::ProgrammaticScryptoSborValue, + ) -> ScryptoSborValue { + ScryptoSborValue { + raw_hex, + programmatic_json: Box::new(programmatic_json), + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_opt_ins.rs b/libraries/gateway-client/src/models/state_entity_details_opt_ins.rs new file mode 100644 index 00000000..26c4ad27 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_opt_ins.rs @@ -0,0 +1,50 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsOptIns { + #[serde( + rename = "ancestor_identities", + skip_serializing_if = "Option::is_none" + )] + pub ancestor_identities: Option, + + #[serde( + rename = "component_royalty_vault_balance", + skip_serializing_if = "Option::is_none" + )] + pub component_royalty_vault_balance: Option, + + #[serde( + rename = "package_royalty_vault_balance", + skip_serializing_if = "Option::is_none" + )] + pub package_royalty_vault_balance: Option, + + #[serde( + rename = "non_fungible_include_nfids", + skip_serializing_if = "Option::is_none" + )] + pub non_fungible_include_nfids: Option, + + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, +} + +impl Default for StateEntityDetailsOptIns { + fn default() -> Self { + Self::new() + } +} + +impl StateEntityDetailsOptIns { + pub fn new() -> StateEntityDetailsOptIns { + StateEntityDetailsOptIns { + ancestor_identities: None, + component_royalty_vault_balance: None, + package_royalty_vault_balance: None, + non_fungible_include_nfids: None, + explicit_metadata: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_request.rs b/libraries/gateway-client/src/models/state_entity_details_request.rs new file mode 100644 index 00000000..28d6568d --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_request.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: Option>, + + #[serde(rename = "addresses")] + pub addresses: Vec, + #[serde( + rename = "aggregation_level", + skip_serializing_if = "Option::is_none" + )] + pub aggregation_level: Option, +} + +impl StateEntityDetailsRequest { + pub fn new(addresses: Vec) -> StateEntityDetailsRequest { + StateEntityDetailsRequest { + at_ledger_state: None, + opt_ins: None, + addresses, + aggregation_level: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response.rs b/libraries/gateway-client/src/models/state_entity_details_response.rs new file mode 100644 index 00000000..87da1fc5 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "items")] + pub items: Vec, +} + +impl StateEntityDetailsResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + ) -> StateEntityDetailsResponse { + StateEntityDetailsResponse { + ledger_state: Box::new(ledger_state), + items, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_component_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_component_details.rs new file mode 100644 index 00000000..260973b7 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_component_details.rs @@ -0,0 +1,48 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseComponentDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + + #[serde( + rename = "package_address", + skip_serializing_if = "Option::is_none" + )] + pub package_address: Option, + #[serde(rename = "blueprint_name")] + pub blueprint_name: String, + #[serde(rename = "blueprint_version")] + pub blueprint_version: String, + + #[serde(rename = "state", skip_serializing_if = "Option::is_none")] + pub state: Option, + #[serde( + rename = "role_assignments", + skip_serializing_if = "Option::is_none" + )] + pub role_assignments: + Option>, + + #[serde( + rename = "royalty_vault_balance", + skip_serializing_if = "Option::is_none" + )] + pub royalty_vault_balance: Option, +} + +impl StateEntityDetailsResponseComponentDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + blueprint_name: String, + blueprint_version: String, + ) -> StateEntityDetailsResponseComponentDetails { + StateEntityDetailsResponseComponentDetails { + r#type, + package_address: None, + blueprint_name, + blueprint_version, + state: None, + role_assignments: None, + royalty_vault_balance: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_fungible_resource_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_fungible_resource_details.rs new file mode 100644 index 00000000..a236386f --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_fungible_resource_details.rs @@ -0,0 +1,38 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseFungibleResourceDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + #[serde(rename = "role_assignments")] + pub role_assignments: Box, + #[serde(rename = "divisibility")] + pub divisibility: i32, + + #[serde(rename = "total_supply")] + pub total_supply: String, + + #[serde(rename = "total_minted")] + pub total_minted: String, + + #[serde(rename = "total_burned")] + pub total_burned: String, +} + +impl StateEntityDetailsResponseFungibleResourceDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + role_assignments: crate::models::ComponentEntityRoleAssignments, + divisibility: i32, + total_supply: String, + total_minted: String, + total_burned: String, + ) -> StateEntityDetailsResponseFungibleResourceDetails { + StateEntityDetailsResponseFungibleResourceDetails { + r#type, + role_assignments: Box::new(role_assignments), + divisibility, + total_supply, + total_minted, + total_burned, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_fungible_vault_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_fungible_vault_details.rs new file mode 100644 index 00000000..b6a5793e --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_fungible_vault_details.rs @@ -0,0 +1,26 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseFungibleVaultDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "balance")] + pub balance: Box< + crate::models::FungibleResourcesCollectionItemVaultAggregatedVaultItem, + >, +} + +impl StateEntityDetailsResponseFungibleVaultDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + resource_address: String, + balance: crate::models::FungibleResourcesCollectionItemVaultAggregatedVaultItem, + ) -> StateEntityDetailsResponseFungibleVaultDetails { + StateEntityDetailsResponseFungibleVaultDetails { + r#type, + resource_address, + balance: Box::new(balance), + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_item.rs b/libraries/gateway-client/src/models/state_entity_details_response_item.rs new file mode 100644 index 00000000..c74fb398 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_item.rs @@ -0,0 +1,51 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseItem { + #[serde(rename = "address")] + pub address: String, + #[serde( + rename = "fungible_resources", + skip_serializing_if = "Option::is_none" + )] + pub fungible_resources: + Option>, + #[serde( + rename = "non_fungible_resources", + skip_serializing_if = "Option::is_none" + )] + pub non_fungible_resources: + Option>, + #[serde( + rename = "ancestor_identities", + skip_serializing_if = "Option::is_none" + )] + pub ancestor_identities: Option< + Box, + >, + #[serde(rename = "metadata")] + pub metadata: Box, + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, + #[serde(rename = "details", skip_serializing_if = "Option::is_none")] + pub details: + Option>, +} + +impl StateEntityDetailsResponseItem { + pub fn new( + address: String, + metadata: crate::models::EntityMetadataCollection, + ) -> StateEntityDetailsResponseItem { + StateEntityDetailsResponseItem { + address, + fungible_resources: None, + non_fungible_resources: None, + ancestor_identities: None, + metadata: Box::new(metadata), + explicit_metadata: None, + details: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_item_ancestor_identities.rs b/libraries/gateway-client/src/models/state_entity_details_response_item_ancestor_identities.rs new file mode 100644 index 00000000..37a9ae4a --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_item_ancestor_identities.rs @@ -0,0 +1,33 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseItemAncestorIdentities { + #[serde( + rename = "parent_address", + skip_serializing_if = "Option::is_none" + )] + pub parent_address: Option, + + #[serde(rename = "owner_address", skip_serializing_if = "Option::is_none")] + pub owner_address: Option, + + #[serde( + rename = "global_address", + skip_serializing_if = "Option::is_none" + )] + pub global_address: Option, +} + +impl Default for StateEntityDetailsResponseItemAncestorIdentities { + fn default() -> Self { + Self::new() + } +} + +impl StateEntityDetailsResponseItemAncestorIdentities { + pub fn new() -> StateEntityDetailsResponseItemAncestorIdentities { + StateEntityDetailsResponseItemAncestorIdentities { + parent_address: None, + owner_address: None, + global_address: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_item_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_item_details.rs new file mode 100644 index 00000000..c00e665a --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_item_details.rs @@ -0,0 +1,3 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "")] +pub enum StateEntityDetailsResponseItemDetails {} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_item_details_type.rs b/libraries/gateway-client/src/models/state_entity_details_response_item_details_type.rs new file mode 100644 index 00000000..92bcbb96 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_item_details_type.rs @@ -0,0 +1,45 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum StateEntityDetailsResponseItemDetailsType { + #[serde(rename = "FungibleResource")] + FungibleResource, + #[serde(rename = "NonFungibleResource")] + NonFungibleResource, + #[serde(rename = "FungibleVault")] + FungibleVault, + #[serde(rename = "NonFungibleVault")] + NonFungibleVault, + #[serde(rename = "Package")] + Package, + #[serde(rename = "Component")] + Component, +} + +impl ToString for StateEntityDetailsResponseItemDetailsType { + fn to_string(&self) -> String { + match self { + Self::FungibleResource => String::from("FungibleResource"), + Self::NonFungibleResource => String::from("NonFungibleResource"), + Self::FungibleVault => String::from("FungibleVault"), + Self::NonFungibleVault => String::from("NonFungibleVault"), + Self::Package => String::from("Package"), + Self::Component => String::from("Component"), + } + } +} + +impl Default for StateEntityDetailsResponseItemDetailsType { + fn default() -> StateEntityDetailsResponseItemDetailsType { + Self::FungibleResource + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_resource_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_resource_details.rs new file mode 100644 index 00000000..0ab65bec --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_resource_details.rs @@ -0,0 +1,38 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseNonFungibleResourceDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + #[serde(rename = "role_assignments")] + pub role_assignments: Box, + #[serde(rename = "non_fungible_id_type")] + pub non_fungible_id_type: crate::models::NonFungibleIdType, + + #[serde(rename = "total_supply")] + pub total_supply: String, + + #[serde(rename = "total_minted")] + pub total_minted: String, + + #[serde(rename = "total_burned")] + pub total_burned: String, +} + +impl StateEntityDetailsResponseNonFungibleResourceDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + role_assignments: crate::models::ComponentEntityRoleAssignments, + non_fungible_id_type: crate::models::NonFungibleIdType, + total_supply: String, + total_minted: String, + total_burned: String, + ) -> StateEntityDetailsResponseNonFungibleResourceDetails { + StateEntityDetailsResponseNonFungibleResourceDetails { + r#type, + role_assignments: Box::new(role_assignments), + non_fungible_id_type, + total_supply, + total_minted, + total_burned, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_vault_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_vault_details.rs new file mode 100644 index 00000000..df8edc2f --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_non_fungible_vault_details.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponseNonFungibleVaultDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "balance")] + pub balance: Box, +} + +impl StateEntityDetailsResponseNonFungibleVaultDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + resource_address: String, + balance: crate::models::NonFungibleResourcesCollectionItemVaultAggregatedVaultItem, + ) -> StateEntityDetailsResponseNonFungibleVaultDetails { + StateEntityDetailsResponseNonFungibleVaultDetails { + r#type, + resource_address, + balance: Box::new(balance), + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_package_details.rs b/libraries/gateway-client/src/models/state_entity_details_response_package_details.rs new file mode 100644 index 00000000..28de3148 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_package_details.rs @@ -0,0 +1,39 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponsePackageDetails { + #[serde(rename = "type")] + pub r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + #[serde(rename = "vm_type")] + pub vm_type: crate::models::PackageVmType, + + #[serde(rename = "code_hash_hex")] + pub code_hash_hex: String, + + #[serde(rename = "code_hex")] + pub code_hex: String, + + #[serde(rename = "royalty_vault_balance", skip_serializing_if = "Option::is_none")] + pub royalty_vault_balance: Option, + #[serde(rename = "blueprints", skip_serializing_if = "Option::is_none")] + pub blueprints: Option>, + #[serde(rename = "schemas", skip_serializing_if = "Option::is_none")] + pub schemas: Option>, +} + +impl StateEntityDetailsResponsePackageDetails { + pub fn new( + r#type: crate::models::StateEntityDetailsResponseItemDetailsType, + vm_type: crate::models::PackageVmType, + code_hash_hex: String, + code_hex: String, + ) -> StateEntityDetailsResponsePackageDetails { + StateEntityDetailsResponsePackageDetails { + r#type, + vm_type, + code_hash_hex, + code_hex, + royalty_vault_balance: None, + blueprints: None, + schemas: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_collection.rs b/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_collection.rs new file mode 100644 index 00000000..34a12cfc --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_collection.rs @@ -0,0 +1,34 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponsePackageDetailsBlueprintCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec< + crate::models::StateEntityDetailsResponsePackageDetailsBlueprintItem, + >, +} + +impl StateEntityDetailsResponsePackageDetailsBlueprintCollection { + pub fn new( + items: Vec, + ) -> StateEntityDetailsResponsePackageDetailsBlueprintCollection { + StateEntityDetailsResponsePackageDetailsBlueprintCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_item.rs b/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_item.rs new file mode 100644 index 00000000..edc13682 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_package_details_blueprint_item.rs @@ -0,0 +1,57 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponsePackageDetailsBlueprintItem { + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "version")] + pub version: String, + + #[serde(rename = "definition")] + pub definition: serde_json::Value, + #[serde( + rename = "dependant_entities", + skip_serializing_if = "Option::is_none" + )] + pub dependant_entities: Option>, + + #[serde(rename = "auth_template", skip_serializing_if = "Option::is_none")] + pub auth_template: Option, + #[serde( + rename = "auth_template_is_locked", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub auth_template_is_locked: Option>, + + #[serde( + rename = "royalty_config", + skip_serializing_if = "Option::is_none" + )] + pub royalty_config: Option, + #[serde( + rename = "royalty_config_is_locked", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub royalty_config_is_locked: Option>, +} + +impl StateEntityDetailsResponsePackageDetailsBlueprintItem { + pub fn new( + name: String, + version: String, + definition: serde_json::Value, + ) -> StateEntityDetailsResponsePackageDetailsBlueprintItem { + StateEntityDetailsResponsePackageDetailsBlueprintItem { + name, + version, + definition, + dependant_entities: None, + auth_template: None, + auth_template_is_locked: None, + royalty_config: None, + royalty_config_is_locked: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_collection.rs b/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_collection.rs new file mode 100644 index 00000000..a4005e8d --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_collection.rs @@ -0,0 +1,35 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponsePackageDetailsSchemaCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: + Vec, +} + +impl StateEntityDetailsResponsePackageDetailsSchemaCollection { + pub fn new( + items: Vec< + crate::models::StateEntityDetailsResponsePackageDetailsSchemaItem, + >, + ) -> StateEntityDetailsResponsePackageDetailsSchemaCollection { + StateEntityDetailsResponsePackageDetailsSchemaCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_item.rs b/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_item.rs new file mode 100644 index 00000000..c46e3012 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_details_response_package_details_schema_item.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityDetailsResponsePackageDetailsSchemaItem { + #[serde(rename = "schema_hash_hex")] + pub schema_hash_hex: String, + + #[serde(rename = "schema_hex")] + pub schema_hex: String, +} + +impl StateEntityDetailsResponsePackageDetailsSchemaItem { + pub fn new( + schema_hash_hex: String, + schema_hex: String, + ) -> StateEntityDetailsResponsePackageDetailsSchemaItem { + StateEntityDetailsResponsePackageDetailsSchemaItem { + schema_hash_hex, + schema_hex, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_request.rs b/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_request.rs new file mode 100644 index 00000000..357f5463 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_request.rs @@ -0,0 +1,48 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityFungibleResourceVaultsPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateEntityFungibleResourceVaultsPageRequest { + pub fn new( + address: String, + resource_address: String, + ) -> StateEntityFungibleResourceVaultsPageRequest { + StateEntityFungibleResourceVaultsPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_response.rs b/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_response.rs new file mode 100644 index 00000000..ac5f6219 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_fungible_resource_vaults_page_response.rs @@ -0,0 +1,49 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityFungibleResourceVaultsPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec< + crate::models::FungibleResourcesCollectionItemVaultAggregatedVaultItem, + >, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateEntityFungibleResourceVaultsPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + resource_address: String, + ) -> StateEntityFungibleResourceVaultsPageResponse { + StateEntityFungibleResourceVaultsPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_fungibles_page_request.rs b/libraries/gateway-client/src/models/state_entity_fungibles_page_request.rs new file mode 100644 index 00000000..9c7a8496 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_fungibles_page_request.rs @@ -0,0 +1,51 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityFungiblesPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, + #[serde( + rename = "aggregation_level", + skip_serializing_if = "Option::is_none" + )] + pub aggregation_level: Option, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: + Option>, +} + +impl StateEntityFungiblesPageRequest { + pub fn new(address: String) -> StateEntityFungiblesPageRequest { + StateEntityFungiblesPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + aggregation_level: None, + opt_ins: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_fungibles_page_request_opt_ins.rs b/libraries/gateway-client/src/models/state_entity_fungibles_page_request_opt_ins.rs new file mode 100644 index 00000000..adfaa2fd --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_fungibles_page_request_opt_ins.rs @@ -0,0 +1,22 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityFungiblesPageRequestOptIns { + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, +} + +impl Default for StateEntityFungiblesPageRequestOptIns { + fn default() -> Self { + Self::new() + } +} + +impl StateEntityFungiblesPageRequestOptIns { + pub fn new() -> StateEntityFungiblesPageRequestOptIns { + StateEntityFungiblesPageRequestOptIns { + explicit_metadata: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_fungibles_page_response.rs b/libraries/gateway-client/src/models/state_entity_fungibles_page_response.rs new file mode 100644 index 00000000..dd85a64e --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_fungibles_page_response.rs @@ -0,0 +1,42 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityFungiblesPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, + + #[serde(rename = "address")] + pub address: String, +} + +impl StateEntityFungiblesPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + ) -> StateEntityFungiblesPageResponse { + StateEntityFungiblesPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_metadata_page_request.rs b/libraries/gateway-client/src/models/state_entity_metadata_page_request.rs new file mode 100644 index 00000000..9e25a347 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_metadata_page_request.rs @@ -0,0 +1,41 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityMetadataPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, +} + +impl StateEntityMetadataPageRequest { + pub fn new(address: String) -> StateEntityMetadataPageRequest { + StateEntityMetadataPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_metadata_page_response.rs b/libraries/gateway-client/src/models/state_entity_metadata_page_response.rs new file mode 100644 index 00000000..cfb1a31d --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_metadata_page_response.rs @@ -0,0 +1,42 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityMetadataPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, + + #[serde(rename = "address")] + pub address: String, +} + +impl StateEntityMetadataPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + ) -> StateEntityMetadataPageResponse { + StateEntityMetadataPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_request.rs b/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_request.rs new file mode 100644 index 00000000..56bc430f --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_request.rs @@ -0,0 +1,53 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungibleIdsPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "vault_address")] + pub vault_address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateEntityNonFungibleIdsPageRequest { + pub fn new( + address: String, + vault_address: String, + resource_address: String, + ) -> StateEntityNonFungibleIdsPageRequest { + StateEntityNonFungibleIdsPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + vault_address, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_response.rs b/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_response.rs new file mode 100644 index 00000000..09b4731c --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungible_ids_page_response.rs @@ -0,0 +1,47 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungibleIdsPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateEntityNonFungibleIdsPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + resource_address: String, + ) -> StateEntityNonFungibleIdsPageResponse { + StateEntityNonFungibleIdsPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_opt_ins.rs b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_opt_ins.rs new file mode 100644 index 00000000..18fe96bc --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_opt_ins.rs @@ -0,0 +1,22 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungibleResourceVaultsPageOptIns { + #[serde( + rename = "non_fungible_include_nfids", + skip_serializing_if = "Option::is_none" + )] + pub non_fungible_include_nfids: Option, +} + +impl Default for StateEntityNonFungibleResourceVaultsPageOptIns { + fn default() -> Self { + Self::new() + } +} + +impl StateEntityNonFungibleResourceVaultsPageOptIns { + pub fn new() -> StateEntityNonFungibleResourceVaultsPageOptIns { + StateEntityNonFungibleResourceVaultsPageOptIns { + non_fungible_include_nfids: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_request.rs b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_request.rs new file mode 100644 index 00000000..aff096bc --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_request.rs @@ -0,0 +1,53 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungibleResourceVaultsPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: Option< + Box, + >, +} + +impl StateEntityNonFungibleResourceVaultsPageRequest { + pub fn new( + address: String, + resource_address: String, + ) -> StateEntityNonFungibleResourceVaultsPageRequest { + StateEntityNonFungibleResourceVaultsPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + resource_address, + opt_ins: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_response.rs b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_response.rs new file mode 100644 index 00000000..5587a241 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungible_resource_vaults_page_response.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungibleResourceVaultsPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde(rename = "total_count", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub total_count: Option>, + + #[serde(rename = "next_cursor", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, + + #[serde(rename = "address")] + pub address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateEntityNonFungibleResourceVaultsPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + resource_address: String, + ) -> StateEntityNonFungibleResourceVaultsPageResponse { + StateEntityNonFungibleResourceVaultsPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request.rs b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request.rs new file mode 100644 index 00000000..0a39eee7 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request.rs @@ -0,0 +1,51 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungiblesPageRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "address")] + pub address: String, + #[serde( + rename = "aggregation_level", + skip_serializing_if = "Option::is_none" + )] + pub aggregation_level: Option, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: + Option>, +} + +impl StateEntityNonFungiblesPageRequest { + pub fn new(address: String) -> StateEntityNonFungiblesPageRequest { + StateEntityNonFungiblesPageRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + address, + aggregation_level: None, + opt_ins: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request_opt_ins.rs b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request_opt_ins.rs new file mode 100644 index 00000000..b47440f1 --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_request_opt_ins.rs @@ -0,0 +1,29 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungiblesPageRequestOptIns { + #[serde( + rename = "non_fungible_include_nfids", + skip_serializing_if = "Option::is_none" + )] + pub non_fungible_include_nfids: Option, + + #[serde( + rename = "explicit_metadata", + skip_serializing_if = "Option::is_none" + )] + pub explicit_metadata: Option>, +} + +impl Default for StateEntityNonFungiblesPageRequestOptIns { + fn default() -> Self { + Self::new() + } +} + +impl StateEntityNonFungiblesPageRequestOptIns { + pub fn new() -> StateEntityNonFungiblesPageRequestOptIns { + StateEntityNonFungiblesPageRequestOptIns { + non_fungible_include_nfids: None, + explicit_metadata: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_entity_non_fungibles_page_response.rs b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_response.rs new file mode 100644 index 00000000..e1d2f71f --- /dev/null +++ b/libraries/gateway-client/src/models/state_entity_non_fungibles_page_response.rs @@ -0,0 +1,42 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateEntityNonFungiblesPageResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, + + #[serde(rename = "address")] + pub address: String, +} + +impl StateEntityNonFungiblesPageResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + address: String, + ) -> StateEntityNonFungiblesPageResponse { + StateEntityNonFungiblesPageResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_key_value_store_data_request.rs b/libraries/gateway-client/src/models/state_key_value_store_data_request.rs new file mode 100644 index 00000000..e91977c0 --- /dev/null +++ b/libraries/gateway-client/src/models/state_key_value_store_data_request.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateKeyValueStoreDataRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde(rename = "key_value_store_address")] + pub key_value_store_address: String, + + #[serde(rename = "keys")] + pub keys: Vec, +} + +impl StateKeyValueStoreDataRequest { + pub fn new( + key_value_store_address: String, + keys: Vec, + ) -> StateKeyValueStoreDataRequest { + StateKeyValueStoreDataRequest { + at_ledger_state: None, + key_value_store_address, + keys, + } + } +} diff --git a/libraries/gateway-client/src/models/state_key_value_store_data_request_key_item.rs b/libraries/gateway-client/src/models/state_key_value_store_data_request_key_item.rs new file mode 100644 index 00000000..e124af3a --- /dev/null +++ b/libraries/gateway-client/src/models/state_key_value_store_data_request_key_item.rs @@ -0,0 +1,22 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateKeyValueStoreDataRequestKeyItem { + #[serde(rename = "key_hex", skip_serializing_if = "Option::is_none")] + pub key_hex: Option, + #[serde(rename = "key_json", skip_serializing_if = "Option::is_none")] + pub key_json: Option>, +} + +impl Default for StateKeyValueStoreDataRequestKeyItem { + fn default() -> Self { + Self::new() + } +} + +impl StateKeyValueStoreDataRequestKeyItem { + pub fn new() -> StateKeyValueStoreDataRequestKeyItem { + StateKeyValueStoreDataRequestKeyItem { + key_hex: None, + key_json: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_key_value_store_data_response.rs b/libraries/gateway-client/src/models/state_key_value_store_data_response.rs new file mode 100644 index 00000000..06b9fbce --- /dev/null +++ b/libraries/gateway-client/src/models/state_key_value_store_data_response.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateKeyValueStoreDataResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde(rename = "key_value_store_address")] + pub key_value_store_address: String, + #[serde(rename = "entries")] + pub entries: Vec, +} + +impl StateKeyValueStoreDataResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + key_value_store_address: String, + entries: Vec, + ) -> StateKeyValueStoreDataResponse { + StateKeyValueStoreDataResponse { + ledger_state: Box::new(ledger_state), + key_value_store_address, + entries, + } + } +} diff --git a/libraries/gateway-client/src/models/state_key_value_store_data_response_item.rs b/libraries/gateway-client/src/models/state_key_value_store_data_response_item.rs new file mode 100644 index 00000000..0dc38f11 --- /dev/null +++ b/libraries/gateway-client/src/models/state_key_value_store_data_response_item.rs @@ -0,0 +1,28 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateKeyValueStoreDataResponseItem { + #[serde(rename = "key")] + pub key: Box, + #[serde(rename = "value")] + pub value: Box, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, + #[serde(rename = "is_locked")] + pub is_locked: bool, +} + +impl StateKeyValueStoreDataResponseItem { + pub fn new( + key: crate::models::ScryptoSborValue, + value: crate::models::ScryptoSborValue, + last_updated_at_state_version: i64, + is_locked: bool, + ) -> StateKeyValueStoreDataResponseItem { + StateKeyValueStoreDataResponseItem { + key: Box::new(key), + value: Box::new(value), + last_updated_at_state_version, + is_locked, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_data_request.rs b/libraries/gateway-client/src/models/state_non_fungible_data_request.rs new file mode 100644 index 00000000..970d7a16 --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_data_request.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleDataRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "non_fungible_ids")] + pub non_fungible_ids: Vec, +} + +impl StateNonFungibleDataRequest { + pub fn new( + resource_address: String, + non_fungible_ids: Vec, + ) -> StateNonFungibleDataRequest { + StateNonFungibleDataRequest { + at_ledger_state: None, + resource_address, + non_fungible_ids, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_data_response.rs b/libraries/gateway-client/src/models/state_non_fungible_data_response.rs new file mode 100644 index 00000000..2718ee7f --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_data_response.rs @@ -0,0 +1,31 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleDataResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "non_fungible_id_type")] + pub non_fungible_id_type: crate::models::NonFungibleIdType, + #[serde(rename = "non_fungible_ids")] + pub non_fungible_ids: + Vec, +} + +impl StateNonFungibleDataResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + resource_address: String, + non_fungible_id_type: crate::models::NonFungibleIdType, + non_fungible_ids: Vec< + crate::models::StateNonFungibleDetailsResponseItem, + >, + ) -> StateNonFungibleDataResponse { + StateNonFungibleDataResponse { + ledger_state: Box::new(ledger_state), + resource_address, + non_fungible_id_type, + non_fungible_ids, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_details_response_item.rs b/libraries/gateway-client/src/models/state_non_fungible_details_response_item.rs new file mode 100644 index 00000000..55d9955f --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_details_response_item.rs @@ -0,0 +1,28 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleDetailsResponseItem { + #[serde(rename = "is_burned")] + pub is_burned: bool, + + #[serde(rename = "non_fungible_id")] + pub non_fungible_id: String, + #[serde(rename = "data", skip_serializing_if = "Option::is_none")] + pub data: Option>, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl StateNonFungibleDetailsResponseItem { + pub fn new( + is_burned: bool, + non_fungible_id: String, + last_updated_at_state_version: i64, + ) -> StateNonFungibleDetailsResponseItem { + StateNonFungibleDetailsResponseItem { + is_burned, + non_fungible_id, + data: None, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_ids_request.rs b/libraries/gateway-client/src/models/state_non_fungible_ids_request.rs new file mode 100644 index 00000000..4eb6e9bd --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_ids_request.rs @@ -0,0 +1,41 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleIdsRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "resource_address")] + pub resource_address: String, +} + +impl StateNonFungibleIdsRequest { + pub fn new(resource_address: String) -> StateNonFungibleIdsRequest { + StateNonFungibleIdsRequest { + at_ledger_state: None, + cursor: None, + limit_per_page: None, + resource_address, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_ids_response.rs b/libraries/gateway-client/src/models/state_non_fungible_ids_response.rs new file mode 100644 index 00000000..6a246c14 --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_ids_response.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleIdsResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "non_fungible_ids")] + pub non_fungible_ids: Box, +} + +impl StateNonFungibleIdsResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + resource_address: String, + non_fungible_ids: crate::models::NonFungibleIdsCollection, + ) -> StateNonFungibleIdsResponse { + StateNonFungibleIdsResponse { + ledger_state: Box::new(ledger_state), + resource_address, + non_fungible_ids: Box::new(non_fungible_ids), + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_location_request.rs b/libraries/gateway-client/src/models/state_non_fungible_location_request.rs new file mode 100644 index 00000000..2b40a13b --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_location_request.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleLocationRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "non_fungible_ids")] + pub non_fungible_ids: Vec, +} + +impl StateNonFungibleLocationRequest { + pub fn new( + resource_address: String, + non_fungible_ids: Vec, + ) -> StateNonFungibleLocationRequest { + StateNonFungibleLocationRequest { + at_ledger_state: None, + resource_address, + non_fungible_ids, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_location_response.rs b/libraries/gateway-client/src/models/state_non_fungible_location_response.rs new file mode 100644 index 00000000..ce985042 --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_location_response.rs @@ -0,0 +1,27 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleLocationResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "non_fungible_ids")] + pub non_fungible_ids: + Vec, +} + +impl StateNonFungibleLocationResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + resource_address: String, + non_fungible_ids: Vec< + crate::models::StateNonFungibleLocationResponseItem, + >, + ) -> StateNonFungibleLocationResponse { + StateNonFungibleLocationResponse { + ledger_state: Box::new(ledger_state), + resource_address, + non_fungible_ids, + } + } +} diff --git a/libraries/gateway-client/src/models/state_non_fungible_location_response_item.rs b/libraries/gateway-client/src/models/state_non_fungible_location_response_item.rs new file mode 100644 index 00000000..041ea836 --- /dev/null +++ b/libraries/gateway-client/src/models/state_non_fungible_location_response_item.rs @@ -0,0 +1,31 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateNonFungibleLocationResponseItem { + #[serde(rename = "non_fungible_id")] + pub non_fungible_id: String, + + #[serde( + rename = "owning_vault_address", + skip_serializing_if = "Option::is_none" + )] + pub owning_vault_address: Option, + #[serde(rename = "is_burned")] + pub is_burned: bool, + + #[serde(rename = "last_updated_at_state_version")] + pub last_updated_at_state_version: i64, +} + +impl StateNonFungibleLocationResponseItem { + pub fn new( + non_fungible_id: String, + is_burned: bool, + last_updated_at_state_version: i64, + ) -> StateNonFungibleLocationResponseItem { + StateNonFungibleLocationResponseItem { + non_fungible_id, + owning_vault_address: None, + is_burned, + last_updated_at_state_version, + } + } +} diff --git a/libraries/gateway-client/src/models/state_validators_list_request.rs b/libraries/gateway-client/src/models/state_validators_list_request.rs new file mode 100644 index 00000000..ec58b9c5 --- /dev/null +++ b/libraries/gateway-client/src/models/state_validators_list_request.rs @@ -0,0 +1,34 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateValidatorsListRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, +} + +impl Default for StateValidatorsListRequest { + fn default() -> Self { + Self::new() + } +} + +impl StateValidatorsListRequest { + pub fn new() -> StateValidatorsListRequest { + StateValidatorsListRequest { + at_ledger_state: None, + cursor: None, + } + } +} diff --git a/libraries/gateway-client/src/models/state_validators_list_response.rs b/libraries/gateway-client/src/models/state_validators_list_response.rs new file mode 100644 index 00000000..a0c45506 --- /dev/null +++ b/libraries/gateway-client/src/models/state_validators_list_response.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StateValidatorsListResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "validators")] + pub validators: Box, +} + +impl StateValidatorsListResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + validators: crate::models::ValidatorCollection, + ) -> StateValidatorsListResponse { + StateValidatorsListResponse { + ledger_state: Box::new(ledger_state), + validators: Box::new(validators), + } + } +} diff --git a/libraries/gateway-client/src/models/stream_transactions_request.rs b/libraries/gateway-client/src/models/stream_transactions_request.rs new file mode 100644 index 00000000..05388dcd --- /dev/null +++ b/libraries/gateway-client/src/models/stream_transactions_request.rs @@ -0,0 +1,143 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StreamTransactionsRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + #[serde( + rename = "from_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub from_ledger_state: + Option>>, + + #[serde( + rename = "cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub cursor: Option>, + + #[serde( + rename = "limit_per_page", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub limit_per_page: Option>, + + #[serde(rename = "kind_filter", skip_serializing_if = "Option::is_none")] + pub kind_filter: Option, + #[serde( + rename = "manifest_accounts_withdrawn_from_filter", + skip_serializing_if = "Option::is_none" + )] + pub manifest_accounts_withdrawn_from_filter: Option>, + #[serde( + rename = "manifest_accounts_deposited_into_filter", + skip_serializing_if = "Option::is_none" + )] + pub manifest_accounts_deposited_into_filter: Option>, + #[serde( + rename = "manifest_resources_filter", + skip_serializing_if = "Option::is_none" + )] + pub manifest_resources_filter: Option>, + #[serde( + rename = "affected_global_entities_filter", + skip_serializing_if = "Option::is_none" + )] + pub affected_global_entities_filter: Option>, + #[serde(rename = "events_filter", skip_serializing_if = "Option::is_none")] + pub events_filter: + Option>, + + #[serde(rename = "order", skip_serializing_if = "Option::is_none")] + pub order: Option, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: Option>, +} + +impl Default for StreamTransactionsRequest { + fn default() -> Self { + Self::new() + } +} + +impl StreamTransactionsRequest { + pub fn new() -> StreamTransactionsRequest { + StreamTransactionsRequest { + at_ledger_state: None, + from_ledger_state: None, + cursor: None, + limit_per_page: None, + kind_filter: None, + manifest_accounts_withdrawn_from_filter: None, + manifest_accounts_deposited_into_filter: None, + manifest_resources_filter: None, + affected_global_entities_filter: None, + events_filter: None, + order: None, + opt_ins: None, + } + } +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum KindFilter { + #[serde(rename = "User")] + User, + #[serde(rename = "EpochChange")] + EpochChange, + #[serde(rename = "All")] + All, +} + +impl Default for KindFilter { + fn default() -> KindFilter { + Self::User + } +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum Order { + #[serde(rename = "Asc")] + Asc, + #[serde(rename = "Desc")] + Desc, +} + +impl Default for Order { + fn default() -> Order { + Self::Asc + } +} diff --git a/libraries/gateway-client/src/models/stream_transactions_request_event_filter_item.rs b/libraries/gateway-client/src/models/stream_transactions_request_event_filter_item.rs new file mode 100644 index 00000000..a75122e7 --- /dev/null +++ b/libraries/gateway-client/src/models/stream_transactions_request_event_filter_item.rs @@ -0,0 +1,52 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StreamTransactionsRequestEventFilterItem { + #[serde(rename = "event")] + pub event: Event, + + #[serde( + rename = "emitter_address", + skip_serializing_if = "Option::is_none" + )] + pub emitter_address: Option, + + #[serde( + rename = "resource_address", + skip_serializing_if = "Option::is_none" + )] + pub resource_address: Option, +} + +impl StreamTransactionsRequestEventFilterItem { + pub fn new(event: Event) -> StreamTransactionsRequestEventFilterItem { + StreamTransactionsRequestEventFilterItem { + event, + emitter_address: None, + resource_address: None, + } + } +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum Event { + #[serde(rename = "Deposit")] + Deposit, + #[serde(rename = "Withdrawal")] + Withdrawal, +} + +impl Default for Event { + fn default() -> Event { + Self::Deposit + } +} diff --git a/libraries/gateway-client/src/models/stream_transactions_response.rs b/libraries/gateway-client/src/models/stream_transactions_response.rs new file mode 100644 index 00000000..c2eba096 --- /dev/null +++ b/libraries/gateway-client/src/models/stream_transactions_response.rs @@ -0,0 +1,38 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct StreamTransactionsResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + + #[serde(rename = "items")] + pub items: Vec, +} + +impl StreamTransactionsResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + items: Vec, + ) -> StreamTransactionsResponse { + StreamTransactionsResponse { + ledger_state: Box::new(ledger_state), + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_balance_changes.rs b/libraries/gateway-client/src/models/transaction_balance_changes.rs new file mode 100644 index 00000000..af57b2e2 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_balance_changes.rs @@ -0,0 +1,34 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionBalanceChanges { + #[serde(rename = "fungible_fee_balance_changes")] + pub fungible_fee_balance_changes: + Vec, + + #[serde(rename = "fungible_balance_changes")] + pub fungible_balance_changes: + Vec, + + #[serde(rename = "non_fungible_balance_changes")] + pub non_fungible_balance_changes: + Vec, +} + +impl TransactionBalanceChanges { + pub fn new( + fungible_fee_balance_changes: Vec< + crate::models::TransactionFungibleFeeBalanceChanges, + >, + fungible_balance_changes: Vec< + crate::models::TransactionFungibleBalanceChanges, + >, + non_fungible_balance_changes: Vec< + crate::models::TransactionNonFungibleBalanceChanges, + >, + ) -> TransactionBalanceChanges { + TransactionBalanceChanges { + fungible_fee_balance_changes, + fungible_balance_changes, + non_fungible_balance_changes, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_committed_details_request.rs b/libraries/gateway-client/src/models/transaction_committed_details_request.rs new file mode 100644 index 00000000..8586c9c3 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_committed_details_request.rs @@ -0,0 +1,26 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionCommittedDetailsRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + + #[serde(rename = "intent_hash")] + pub intent_hash: String, + #[serde(rename = "opt_ins", skip_serializing_if = "Option::is_none")] + pub opt_ins: Option>, +} + +impl TransactionCommittedDetailsRequest { + pub fn new(intent_hash: String) -> TransactionCommittedDetailsRequest { + TransactionCommittedDetailsRequest { + at_ledger_state: None, + intent_hash, + opt_ins: None, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_committed_details_response.rs b/libraries/gateway-client/src/models/transaction_committed_details_response.rs new file mode 100644 index 00000000..1ae08770 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_committed_details_response.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionCommittedDetailsResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "transaction")] + pub transaction: Box, +} + +impl TransactionCommittedDetailsResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + transaction: crate::models::CommittedTransactionInfo, + ) -> TransactionCommittedDetailsResponse { + TransactionCommittedDetailsResponse { + ledger_state: Box::new(ledger_state), + transaction: Box::new(transaction), + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_construction_response.rs b/libraries/gateway-client/src/models/transaction_construction_response.rs new file mode 100644 index 00000000..e82addc4 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_construction_response.rs @@ -0,0 +1,15 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionConstructionResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, +} + +impl TransactionConstructionResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + ) -> TransactionConstructionResponse { + TransactionConstructionResponse { + ledger_state: Box::new(ledger_state), + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_details_opt_ins.rs b/libraries/gateway-client/src/models/transaction_details_opt_ins.rs new file mode 100644 index 00000000..579c7400 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_details_opt_ins.rs @@ -0,0 +1,82 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionDetailsOptIns { + #[serde(rename = "raw_hex", skip_serializing_if = "Option::is_none")] + pub raw_hex: Option, + + #[serde( + rename = "receipt_state_changes", + skip_serializing_if = "Option::is_none" + )] + pub receipt_state_changes: Option, + + #[serde( + rename = "receipt_fee_summary", + skip_serializing_if = "Option::is_none" + )] + pub receipt_fee_summary: Option, + + #[serde( + rename = "receipt_fee_source", + skip_serializing_if = "Option::is_none" + )] + pub receipt_fee_source: Option, + + #[serde( + rename = "receipt_fee_destination", + skip_serializing_if = "Option::is_none" + )] + pub receipt_fee_destination: Option, + + #[serde( + rename = "receipt_costing_parameters", + skip_serializing_if = "Option::is_none" + )] + pub receipt_costing_parameters: Option, + + #[serde( + rename = "receipt_events", + skip_serializing_if = "Option::is_none" + )] + pub receipt_events: Option, + + #[serde( + rename = "receipt_output", + skip_serializing_if = "Option::is_none" + )] + pub receipt_output: Option, + + #[serde( + rename = "affected_global_entities", + skip_serializing_if = "Option::is_none" + )] + pub affected_global_entities: Option, + + #[serde( + rename = "balance_changes", + skip_serializing_if = "Option::is_none" + )] + pub balance_changes: Option, +} + +impl Default for TransactionDetailsOptIns { + fn default() -> Self { + Self::new() + } +} + +impl TransactionDetailsOptIns { + pub fn new() -> TransactionDetailsOptIns { + TransactionDetailsOptIns { + raw_hex: None, + receipt_state_changes: None, + receipt_fee_summary: None, + receipt_fee_source: None, + receipt_fee_destination: None, + receipt_costing_parameters: None, + receipt_events: None, + receipt_output: None, + affected_global_entities: None, + balance_changes: None, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_fungible_balance_changes.rs b/libraries/gateway-client/src/models/transaction_fungible_balance_changes.rs new file mode 100644 index 00000000..f8dcf2ce --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_fungible_balance_changes.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionFungibleBalanceChanges { + #[serde(rename = "entity_address")] + pub entity_address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "balance_change")] + pub balance_change: String, +} + +impl TransactionFungibleBalanceChanges { + pub fn new( + entity_address: String, + resource_address: String, + balance_change: String, + ) -> TransactionFungibleBalanceChanges { + TransactionFungibleBalanceChanges { + entity_address, + resource_address, + balance_change, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_fungible_fee_balance_change_type.rs b/libraries/gateway-client/src/models/transaction_fungible_fee_balance_change_type.rs new file mode 100644 index 00000000..a22f71e1 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_fungible_fee_balance_change_type.rs @@ -0,0 +1,39 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum TransactionFungibleFeeBalanceChangeType { + #[serde(rename = "FeePayment")] + FeePayment, + #[serde(rename = "FeeDistributed")] + FeeDistributed, + #[serde(rename = "TipDistributed")] + TipDistributed, + #[serde(rename = "RoyaltyDistributed")] + RoyaltyDistributed, +} + +impl ToString for TransactionFungibleFeeBalanceChangeType { + fn to_string(&self) -> String { + match self { + Self::FeePayment => String::from("FeePayment"), + Self::FeeDistributed => String::from("FeeDistributed"), + Self::TipDistributed => String::from("TipDistributed"), + Self::RoyaltyDistributed => String::from("RoyaltyDistributed"), + } + } +} + +impl Default for TransactionFungibleFeeBalanceChangeType { + fn default() -> TransactionFungibleFeeBalanceChangeType { + Self::FeePayment + } +} diff --git a/libraries/gateway-client/src/models/transaction_fungible_fee_balance_changes.rs b/libraries/gateway-client/src/models/transaction_fungible_fee_balance_changes.rs new file mode 100644 index 00000000..add6b6e2 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_fungible_fee_balance_changes.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionFungibleFeeBalanceChanges { + #[serde(rename = "type")] + pub r#type: crate::models::TransactionFungibleFeeBalanceChangeType, + + #[serde(rename = "entity_address")] + pub entity_address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, + + #[serde(rename = "balance_change")] + pub balance_change: String, +} + +impl TransactionFungibleFeeBalanceChanges { + pub fn new( + r#type: crate::models::TransactionFungibleFeeBalanceChangeType, + entity_address: String, + resource_address: String, + balance_change: String, + ) -> TransactionFungibleFeeBalanceChanges { + TransactionFungibleFeeBalanceChanges { + r#type, + entity_address, + resource_address, + balance_change, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_intent_status.rs b/libraries/gateway-client/src/models/transaction_intent_status.rs new file mode 100644 index 00000000..b839d827 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_intent_status.rs @@ -0,0 +1,52 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum TransactionIntentStatus { + #[serde(rename = "Unknown")] + Unknown, + #[serde(rename = "CommittedSuccess")] + CommittedSuccess, + #[serde(rename = "CommittedFailure")] + CommittedFailure, + #[serde(rename = "CommitPendingOutcomeUnknown")] + CommitPendingOutcomeUnknown, + #[serde(rename = "PermanentlyRejected")] + PermanentlyRejected, + #[serde(rename = "LikelyButNotCertainRejection")] + LikelyButNotCertainRejection, + #[serde(rename = "Pending")] + Pending, +} + +impl ToString for TransactionIntentStatus { + fn to_string(&self) -> String { + match self { + Self::Unknown => String::from("Unknown"), + Self::CommittedSuccess => String::from("CommittedSuccess"), + Self::CommittedFailure => String::from("CommittedFailure"), + Self::CommitPendingOutcomeUnknown => { + String::from("CommitPendingOutcomeUnknown") + } + Self::PermanentlyRejected => String::from("PermanentlyRejected"), + Self::LikelyButNotCertainRejection => { + String::from("LikelyButNotCertainRejection") + } + Self::Pending => String::from("Pending"), + } + } +} + +impl Default for TransactionIntentStatus { + fn default() -> TransactionIntentStatus { + Self::Unknown + } +} diff --git a/libraries/gateway-client/src/models/transaction_non_fungible_balance_changes.rs b/libraries/gateway-client/src/models/transaction_non_fungible_balance_changes.rs new file mode 100644 index 00000000..c676edcf --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_non_fungible_balance_changes.rs @@ -0,0 +1,28 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionNonFungibleBalanceChanges { + #[serde(rename = "entity_address")] + pub entity_address: String, + + #[serde(rename = "resource_address")] + pub resource_address: String, + #[serde(rename = "added")] + pub added: Vec, + #[serde(rename = "removed")] + pub removed: Vec, +} + +impl TransactionNonFungibleBalanceChanges { + pub fn new( + entity_address: String, + resource_address: String, + added: Vec, + removed: Vec, + ) -> TransactionNonFungibleBalanceChanges { + TransactionNonFungibleBalanceChanges { + entity_address, + resource_address, + added, + removed, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_not_found_error.rs b/libraries/gateway-client/src/models/transaction_not_found_error.rs new file mode 100644 index 00000000..1fd2a634 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_not_found_error.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionNotFoundError { + #[serde(rename = "type")] + pub r#type: String, + + #[serde(rename = "intent_hash")] + pub intent_hash: String, +} + +impl TransactionNotFoundError { + pub fn new( + r#type: String, + intent_hash: String, + ) -> TransactionNotFoundError { + TransactionNotFoundError { + r#type, + intent_hash, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_payload_gateway_handling_status.rs b/libraries/gateway-client/src/models/transaction_payload_gateway_handling_status.rs new file mode 100644 index 00000000..af0573bc --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_payload_gateway_handling_status.rs @@ -0,0 +1,33 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum TransactionPayloadGatewayHandlingStatus { + #[serde(rename = "HandlingSubmission")] + HandlingSubmission, + #[serde(rename = "Concluded")] + Concluded, +} + +impl ToString for TransactionPayloadGatewayHandlingStatus { + fn to_string(&self) -> String { + match self { + Self::HandlingSubmission => String::from("HandlingSubmission"), + Self::Concluded => String::from("Concluded"), + } + } +} + +impl Default for TransactionPayloadGatewayHandlingStatus { + fn default() -> TransactionPayloadGatewayHandlingStatus { + Self::HandlingSubmission + } +} diff --git a/libraries/gateway-client/src/models/transaction_payload_status.rs b/libraries/gateway-client/src/models/transaction_payload_status.rs new file mode 100644 index 00000000..56454832 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_payload_status.rs @@ -0,0 +1,50 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum TransactionPayloadStatus { + #[serde(rename = "Unknown")] + Unknown, + #[serde(rename = "CommittedSuccess")] + CommittedSuccess, + #[serde(rename = "CommittedFailure")] + CommittedFailure, + #[serde(rename = "CommitPendingOutcomeUnknown")] + CommitPendingOutcomeUnknown, + #[serde(rename = "PermanentlyRejected")] + PermanentlyRejected, + #[serde(rename = "TemporarilyRejected")] + TemporarilyRejected, + #[serde(rename = "Pending")] + Pending, +} + +impl ToString for TransactionPayloadStatus { + fn to_string(&self) -> String { + match self { + Self::Unknown => String::from("Unknown"), + Self::CommittedSuccess => String::from("CommittedSuccess"), + Self::CommittedFailure => String::from("CommittedFailure"), + Self::CommitPendingOutcomeUnknown => { + String::from("CommitPendingOutcomeUnknown") + } + Self::PermanentlyRejected => String::from("PermanentlyRejected"), + Self::TemporarilyRejected => String::from("TemporarilyRejected"), + Self::Pending => String::from("Pending"), + } + } +} + +impl Default for TransactionPayloadStatus { + fn default() -> TransactionPayloadStatus { + Self::Unknown + } +} diff --git a/libraries/gateway-client/src/models/transaction_preview_request.rs b/libraries/gateway-client/src/models/transaction_preview_request.rs new file mode 100644 index 00000000..19bd8995 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_preview_request.rs @@ -0,0 +1,61 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionPreviewRequest { + #[serde(rename = "manifest")] + pub manifest: String, + + #[serde(rename = "blobs_hex", skip_serializing_if = "Option::is_none")] + pub blobs_hex: Option>, + + #[serde(rename = "start_epoch_inclusive")] + pub start_epoch_inclusive: i64, + + #[serde(rename = "end_epoch_exclusive")] + pub end_epoch_exclusive: i64, + #[serde( + rename = "notary_public_key", + skip_serializing_if = "Option::is_none" + )] + pub notary_public_key: Option>, + + #[serde( + rename = "notary_is_signatory", + skip_serializing_if = "Option::is_none" + )] + pub notary_is_signatory: Option, + + #[serde(rename = "tip_percentage")] + pub tip_percentage: i32, + + #[serde(rename = "nonce")] + pub nonce: i64, + + #[serde(rename = "signer_public_keys")] + pub signer_public_keys: Vec, + #[serde(rename = "flags")] + pub flags: Box, +} + +impl TransactionPreviewRequest { + pub fn new( + manifest: String, + start_epoch_inclusive: i64, + end_epoch_exclusive: i64, + tip_percentage: i32, + nonce: i64, + signer_public_keys: Vec, + flags: crate::models::TransactionPreviewRequestFlags, + ) -> TransactionPreviewRequest { + TransactionPreviewRequest { + manifest, + blobs_hex: None, + start_epoch_inclusive, + end_epoch_exclusive, + notary_public_key: None, + notary_is_signatory: None, + tip_percentage, + nonce, + signer_public_keys, + flags: Box::new(flags), + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_preview_request_flags.rs b/libraries/gateway-client/src/models/transaction_preview_request_flags.rs new file mode 100644 index 00000000..81a281f4 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_preview_request_flags.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionPreviewRequestFlags { + #[serde(rename = "use_free_credit")] + pub use_free_credit: bool, + #[serde(rename = "assume_all_signature_proofs")] + pub assume_all_signature_proofs: bool, + #[serde(rename = "skip_epoch_check")] + pub skip_epoch_check: bool, +} + +impl TransactionPreviewRequestFlags { + pub fn new( + use_free_credit: bool, + assume_all_signature_proofs: bool, + skip_epoch_check: bool, + ) -> TransactionPreviewRequestFlags { + TransactionPreviewRequestFlags { + use_free_credit, + assume_all_signature_proofs, + skip_epoch_check, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_preview_response.rs b/libraries/gateway-client/src/models/transaction_preview_response.rs new file mode 100644 index 00000000..7952307c --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_preview_response.rs @@ -0,0 +1,29 @@ +#[serde_with::serde_as] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionPreviewResponse { + #[serde(rename = "encoded_receipt")] + #[serde_as(as = "serde_with::hex::Hex")] + pub encoded_receipt: Vec, + #[serde(rename = "receipt")] + pub receipt: serde_json::Value, + #[serde(rename = "resource_changes")] + pub resource_changes: Vec, + #[serde(rename = "logs")] + pub logs: Vec, +} + +impl TransactionPreviewResponse { + pub fn new( + encoded_receipt: Vec, + receipt: serde_json::Value, + resource_changes: Vec, + logs: Vec, + ) -> TransactionPreviewResponse { + TransactionPreviewResponse { + encoded_receipt, + receipt, + resource_changes, + logs, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_preview_response_logs_inner.rs b/libraries/gateway-client/src/models/transaction_preview_response_logs_inner.rs new file mode 100644 index 00000000..d3423dfe --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_preview_response_logs_inner.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionPreviewResponseLogsInner { + #[serde(rename = "level")] + pub level: String, + #[serde(rename = "message")] + pub message: String, +} + +impl TransactionPreviewResponseLogsInner { + pub fn new( + level: String, + message: String, + ) -> TransactionPreviewResponseLogsInner { + TransactionPreviewResponseLogsInner { level, message } + } +} diff --git a/libraries/gateway-client/src/models/transaction_receipt.rs b/libraries/gateway-client/src/models/transaction_receipt.rs new file mode 100644 index 00000000..2767cf96 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_receipt.rs @@ -0,0 +1,74 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionReceipt { + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + + #[serde(rename = "fee_summary", skip_serializing_if = "Option::is_none")] + pub fee_summary: Option, + #[serde( + rename = "costing_parameters", + skip_serializing_if = "Option::is_none" + )] + pub costing_parameters: Option, + + #[serde( + rename = "fee_destination", + skip_serializing_if = "Option::is_none" + )] + pub fee_destination: Option, + + #[serde(rename = "fee_source", skip_serializing_if = "Option::is_none")] + pub fee_source: Option, + #[serde(rename = "state_updates", skip_serializing_if = "Option::is_none")] + pub state_updates: Option, + #[serde(rename = "next_epoch", skip_serializing_if = "Option::is_none")] + pub next_epoch: Option, + #[serde(rename = "output", skip_serializing_if = "Option::is_none")] + pub output: Option, + + #[serde(rename = "events", skip_serializing_if = "Option::is_none")] + pub events: Option>, + + #[serde( + rename = "error_message", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub error_message: Option>, +} + +impl Default for TransactionReceipt { + fn default() -> Self { + Self::new() + } +} + +impl TransactionReceipt { + pub fn new() -> TransactionReceipt { + TransactionReceipt { + status: None, + fee_summary: None, + costing_parameters: None, + fee_destination: None, + fee_source: None, + state_updates: None, + next_epoch: None, + output: None, + events: None, + error_message: None, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct StateUpdates { + pub new_global_entities: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct Entity { + pub is_global: bool, + pub entity_type: String, + pub entity_address: String, +} diff --git a/libraries/gateway-client/src/models/transaction_status.rs b/libraries/gateway-client/src/models/transaction_status.rs new file mode 100644 index 00000000..5ab066e0 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_status.rs @@ -0,0 +1,42 @@ +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub enum TransactionStatus { + #[serde(rename = "Unknown")] + Unknown, + #[serde(rename = "CommittedSuccess")] + CommittedSuccess, + #[serde(rename = "CommittedFailure")] + CommittedFailure, + #[serde(rename = "Pending")] + Pending, + #[serde(rename = "Rejected")] + Rejected, +} + +impl ToString for TransactionStatus { + fn to_string(&self) -> String { + match self { + Self::Unknown => String::from("Unknown"), + Self::CommittedSuccess => String::from("CommittedSuccess"), + Self::CommittedFailure => String::from("CommittedFailure"), + Self::Pending => String::from("Pending"), + Self::Rejected => String::from("Rejected"), + } + } +} + +impl Default for TransactionStatus { + fn default() -> TransactionStatus { + Self::Unknown + } +} diff --git a/libraries/gateway-client/src/models/transaction_status_request.rs b/libraries/gateway-client/src/models/transaction_status_request.rs new file mode 100644 index 00000000..965c32fb --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_status_request.rs @@ -0,0 +1,11 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionStatusRequest { + #[serde(rename = "intent_hash")] + pub intent_hash: String, +} + +impl TransactionStatusRequest { + pub fn new(intent_hash: String) -> TransactionStatusRequest { + TransactionStatusRequest { intent_hash } + } +} diff --git a/libraries/gateway-client/src/models/transaction_status_response.rs b/libraries/gateway-client/src/models/transaction_status_response.rs new file mode 100644 index 00000000..c012907a --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_status_response.rs @@ -0,0 +1,53 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionStatusResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "status")] + pub status: crate::models::TransactionStatus, + #[serde(rename = "intent_status")] + pub intent_status: crate::models::TransactionIntentStatus, + + #[serde(rename = "intent_status_description")] + pub intent_status_description: String, + #[serde(rename = "known_payloads")] + pub known_payloads: + Vec, + + #[serde( + rename = "committed_state_version", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub committed_state_version: Option>, + + #[serde( + rename = "error_message", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub error_message: Option>, +} + +impl TransactionStatusResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + status: crate::models::TransactionStatus, + intent_status: crate::models::TransactionIntentStatus, + intent_status_description: String, + known_payloads: Vec< + crate::models::TransactionStatusResponseKnownPayloadItem, + >, + ) -> TransactionStatusResponse { + TransactionStatusResponse { + ledger_state: Box::new(ledger_state), + status, + intent_status, + intent_status_description, + known_payloads, + committed_state_version: None, + error_message: None, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_status_response_known_payload_item.rs b/libraries/gateway-client/src/models/transaction_status_response_known_payload_item.rs new file mode 100644 index 00000000..85ab71d2 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_status_response_known_payload_item.rs @@ -0,0 +1,75 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionStatusResponseKnownPayloadItem { + #[serde(rename = "payload_hash")] + pub payload_hash: String, + #[serde(rename = "status")] + pub status: crate::models::TransactionStatus, + #[serde( + rename = "payload_status", + skip_serializing_if = "Option::is_none" + )] + pub payload_status: Option, + + #[serde( + rename = "payload_status_description", + skip_serializing_if = "Option::is_none" + )] + pub payload_status_description: Option, + + #[serde( + rename = "error_message", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub error_message: Option>, + + #[serde( + rename = "latest_error_message", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub latest_error_message: Option>, + #[serde( + rename = "handling_status", + skip_serializing_if = "Option::is_none" + )] + pub handling_status: + Option, + + #[serde( + rename = "handling_status_reason", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub handling_status_reason: Option>, + + #[serde( + rename = "submission_error", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub submission_error: Option>, +} + +impl TransactionStatusResponseKnownPayloadItem { + pub fn new( + payload_hash: String, + status: crate::models::TransactionStatus, + ) -> TransactionStatusResponseKnownPayloadItem { + TransactionStatusResponseKnownPayloadItem { + payload_hash, + status, + payload_status: None, + payload_status_description: None, + error_message: None, + latest_error_message: None, + handling_status: None, + handling_status_reason: None, + submission_error: None, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_submit_request.rs b/libraries/gateway-client/src/models/transaction_submit_request.rs new file mode 100644 index 00000000..fc49cba8 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_submit_request.rs @@ -0,0 +1,15 @@ +#[serde_with::serde_as] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionSubmitRequest { + #[serde(rename = "notarized_transaction_hex")] + #[serde_as(as = "serde_with::hex::Hex")] + pub notarized_transaction: Vec, +} + +impl TransactionSubmitRequest { + pub fn new(notarized_transaction: Vec) -> TransactionSubmitRequest { + TransactionSubmitRequest { + notarized_transaction, + } + } +} diff --git a/libraries/gateway-client/src/models/transaction_submit_response.rs b/libraries/gateway-client/src/models/transaction_submit_response.rs new file mode 100644 index 00000000..f96345b7 --- /dev/null +++ b/libraries/gateway-client/src/models/transaction_submit_response.rs @@ -0,0 +1,11 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TransactionSubmitResponse { + #[serde(rename = "duplicate")] + pub duplicate: bool, +} + +impl TransactionSubmitResponse { + pub fn new(duplicate: bool) -> TransactionSubmitResponse { + TransactionSubmitResponse { duplicate } + } +} diff --git a/libraries/gateway-client/src/models/validation_errors_at_path.rs b/libraries/gateway-client/src/models/validation_errors_at_path.rs new file mode 100644 index 00000000..735d8f5b --- /dev/null +++ b/libraries/gateway-client/src/models/validation_errors_at_path.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidationErrorsAtPath { + #[serde(rename = "path")] + pub path: String, + #[serde(rename = "errors")] + pub errors: Vec, +} + +impl ValidationErrorsAtPath { + pub fn new(path: String, errors: Vec) -> ValidationErrorsAtPath { + ValidationErrorsAtPath { path, errors } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection.rs b/libraries/gateway-client/src/models/validator_collection.rs new file mode 100644 index 00000000..0ed841e4 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollection { + #[serde( + rename = "total_count", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub total_count: Option>, + + #[serde( + rename = "next_cursor", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub next_cursor: Option>, + #[serde(rename = "items")] + pub items: Vec, +} + +impl ValidatorCollection { + pub fn new( + items: Vec, + ) -> ValidatorCollection { + ValidatorCollection { + total_count: None, + next_cursor: None, + items, + } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection_item.rs b/libraries/gateway-client/src/models/validator_collection_item.rs new file mode 100644 index 00000000..2a916a77 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection_item.rs @@ -0,0 +1,57 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollectionItem { + #[serde(rename = "address")] + pub address: String, + #[serde(rename = "stake_vault")] + pub stake_vault: Box, + #[serde(rename = "pending_xrd_withdraw_vault")] + pub pending_xrd_withdraw_vault: Box, + #[serde(rename = "locked_owner_stake_unit_vault")] + pub locked_owner_stake_unit_vault: Box, + #[serde(rename = "pending_owner_stake_unit_unlock_vault")] + pub pending_owner_stake_unit_unlock_vault: + Box, + + #[serde(rename = "state", deserialize_with = "Option::deserialize")] + pub state: Option, + #[serde( + rename = "active_in_epoch", + skip_serializing_if = "Option::is_none" + )] + pub active_in_epoch: + Option>, + #[serde(rename = "metadata")] + pub metadata: Box, + #[serde(rename = "effective_fee_factor")] + pub effective_fee_factor: + Box, +} + +impl ValidatorCollectionItem { + pub fn new( + address: String, + stake_vault: crate::models::ValidatorVaultItem, + pending_xrd_withdraw_vault: crate::models::ValidatorVaultItem, + locked_owner_stake_unit_vault: crate::models::ValidatorVaultItem, + pending_owner_stake_unit_unlock_vault: crate::models::ValidatorVaultItem, + state: Option, + metadata: crate::models::EntityMetadataCollection, + effective_fee_factor: crate::models::ValidatorCollectionItemEffectiveFeeFactor, + ) -> ValidatorCollectionItem { + ValidatorCollectionItem { + address, + stake_vault: Box::new(stake_vault), + pending_xrd_withdraw_vault: Box::new(pending_xrd_withdraw_vault), + locked_owner_stake_unit_vault: Box::new( + locked_owner_stake_unit_vault, + ), + pending_owner_stake_unit_unlock_vault: Box::new( + pending_owner_stake_unit_unlock_vault, + ), + state, + active_in_epoch: None, + metadata: Box::new(metadata), + effective_fee_factor: Box::new(effective_fee_factor), + } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection_item_active_in_epoch.rs b/libraries/gateway-client/src/models/validator_collection_item_active_in_epoch.rs new file mode 100644 index 00000000..2a72f879 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection_item_active_in_epoch.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollectionItemActiveInEpoch { + #[serde(rename = "stake")] + pub stake: String, + #[serde(rename = "stake_percentage")] + pub stake_percentage: f64, + #[serde(rename = "key")] + pub key: Box, +} + +impl ValidatorCollectionItemActiveInEpoch { + pub fn new( + stake: String, + stake_percentage: f64, + key: crate::models::PublicKey, + ) -> ValidatorCollectionItemActiveInEpoch { + ValidatorCollectionItemActiveInEpoch { + stake, + stake_percentage, + key: Box::new(key), + } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor.rs b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor.rs new file mode 100644 index 00000000..16eacb0c --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollectionItemEffectiveFeeFactor { + #[serde(rename = "current")] + pub current: + Box, + #[serde( + rename = "pending", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub pending: Option< + Option< + Box< + crate::models::ValidatorCollectionItemEffectiveFeeFactorPending, + >, + >, + >, +} + +impl ValidatorCollectionItemEffectiveFeeFactor { + pub fn new( + current: crate::models::ValidatorCollectionItemEffectiveFeeFactorCurrent, + ) -> ValidatorCollectionItemEffectiveFeeFactor { + ValidatorCollectionItemEffectiveFeeFactor { + current: Box::new(current), + pending: None, + } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_current.rs b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_current.rs new file mode 100644 index 00000000..c1df6e6a --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_current.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollectionItemEffectiveFeeFactorCurrent { + #[serde(rename = "fee_factor")] + pub fee_factor: String, +} + +impl ValidatorCollectionItemEffectiveFeeFactorCurrent { + pub fn new( + fee_factor: String, + ) -> ValidatorCollectionItemEffectiveFeeFactorCurrent { + ValidatorCollectionItemEffectiveFeeFactorCurrent { fee_factor } + } +} diff --git a/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_pending.rs b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_pending.rs new file mode 100644 index 00000000..29952739 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_collection_item_effective_fee_factor_pending.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorCollectionItemEffectiveFeeFactorPending { + #[serde(rename = "fee_factor")] + pub fee_factor: String, + #[serde(rename = "effective_at_epoch")] + pub effective_at_epoch: i64, +} + +impl ValidatorCollectionItemEffectiveFeeFactorPending { + pub fn new( + fee_factor: String, + effective_at_epoch: i64, + ) -> ValidatorCollectionItemEffectiveFeeFactorPending { + ValidatorCollectionItemEffectiveFeeFactorPending { + fee_factor, + effective_at_epoch, + } + } +} diff --git a/libraries/gateway-client/src/models/validator_uptime_collection.rs b/libraries/gateway-client/src/models/validator_uptime_collection.rs new file mode 100644 index 00000000..15388c13 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_uptime_collection.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorUptimeCollection { + #[serde(rename = "items")] + pub items: Vec, +} + +impl ValidatorUptimeCollection { + pub fn new( + items: Vec, + ) -> ValidatorUptimeCollection { + ValidatorUptimeCollection { items } + } +} diff --git a/libraries/gateway-client/src/models/validator_uptime_collection_item.rs b/libraries/gateway-client/src/models/validator_uptime_collection_item.rs new file mode 100644 index 00000000..bed9a665 --- /dev/null +++ b/libraries/gateway-client/src/models/validator_uptime_collection_item.rs @@ -0,0 +1,38 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorUptimeCollectionItem { + #[serde(rename = "address")] + pub address: String, + + #[serde( + rename = "proposals_made", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub proposals_made: Option>, + + #[serde( + rename = "proposals_missed", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub proposals_missed: Option>, + + #[serde(rename = "epochs_active_in")] + pub epochs_active_in: i64, +} + +impl ValidatorUptimeCollectionItem { + pub fn new( + address: String, + epochs_active_in: i64, + ) -> ValidatorUptimeCollectionItem { + ValidatorUptimeCollectionItem { + address, + proposals_made: None, + proposals_missed: None, + epochs_active_in, + } + } +} diff --git a/libraries/gateway-client/src/models/validator_vault_item.rs b/libraries/gateway-client/src/models/validator_vault_item.rs new file mode 100644 index 00000000..b43c2fbd --- /dev/null +++ b/libraries/gateway-client/src/models/validator_vault_item.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorVaultItem { + #[serde(rename = "balance")] + pub balance: String, + #[serde(rename = "last_changed_at_state_version")] + pub last_changed_at_state_version: i64, + + #[serde(rename = "address")] + pub address: String, +} + +impl ValidatorVaultItem { + pub fn new( + balance: String, + last_changed_at_state_version: i64, + address: String, + ) -> ValidatorVaultItem { + ValidatorVaultItem { + balance, + last_changed_at_state_version, + address, + } + } +} diff --git a/libraries/gateway-client/src/models/validators_uptime_request.rs b/libraries/gateway-client/src/models/validators_uptime_request.rs new file mode 100644 index 00000000..291adcc3 --- /dev/null +++ b/libraries/gateway-client/src/models/validators_uptime_request.rs @@ -0,0 +1,40 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorsUptimeRequest { + #[serde( + rename = "at_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub at_ledger_state: + Option>>, + #[serde( + rename = "from_ledger_state", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub from_ledger_state: + Option>>, + #[serde( + rename = "validator_addresses", + skip_serializing_if = "Option::is_none" + )] + pub validator_addresses: Option>, +} + +impl Default for ValidatorsUptimeRequest { + fn default() -> Self { + Self::new() + } +} + +impl ValidatorsUptimeRequest { + pub fn new() -> ValidatorsUptimeRequest { + ValidatorsUptimeRequest { + at_ledger_state: None, + from_ledger_state: None, + validator_addresses: None, + } + } +} diff --git a/libraries/gateway-client/src/models/validators_uptime_response.rs b/libraries/gateway-client/src/models/validators_uptime_response.rs new file mode 100644 index 00000000..f8539b84 --- /dev/null +++ b/libraries/gateway-client/src/models/validators_uptime_response.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ValidatorsUptimeResponse { + #[serde(rename = "ledger_state")] + pub ledger_state: Box, + #[serde(rename = "validators")] + pub validators: Box, +} + +impl ValidatorsUptimeResponse { + pub fn new( + ledger_state: crate::models::LedgerState, + validators: crate::models::ValidatorUptimeCollection, + ) -> ValidatorsUptimeResponse { + ValidatorsUptimeResponse { + ledger_state: Box::new(ledger_state), + validators: Box::new(validators), + } + } +} diff --git a/libraries/package-loader/Cargo.toml b/libraries/package-loader/Cargo.toml new file mode 100644 index 00000000..5c278065 --- /dev/null +++ b/libraries/package-loader/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "package-loader" +description = "The implementaton of a package builder and loader for efficient runtime package loading." +version.workspace = true +edition.workspace = true +build = "build.rs" + +[dependencies] +scrypto-unit = { workspace = true } +radix-engine-common = { workspace = true } +radix-engine-queries = { workspace = true } + +lazy_static = { verison = "1.4.0", optional = true } +getrandom = { version = "0.2.12", features = ["js"] } + +[build-dependencies] +walkdir = { version = "2.3.3", optional = true } +wasm-opt = { version = "0.116.0", optional = true } +cargo_toml = { version = "0.18.0", optional = true } + +radix-engine = { workspace = true, optional = true } +radix-engine-interface = { workspace = true, optional = true } + +[features] +default = [] +build-time-blueprints = [ + "dep:lazy_static", + "dep:walkdir", + "dep:cargo_toml", + "dep:radix-engine", + "dep:radix-engine-interface", + "dep:wasm-opt", +] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/libraries/package-loader/build.rs b/libraries/package-loader/build.rs new file mode 100644 index 00000000..1b6f4645 --- /dev/null +++ b/libraries/package-loader/build.rs @@ -0,0 +1,192 @@ +fn main() -> Result<(), Error> { + build_blueprints()?; + Ok(()) +} + +#[cfg(not(feature = "build-time-blueprints"))] +fn build_blueprints() -> Result<(), Error> { + Ok(()) +} + +#[cfg(feature = "build-time-blueprints")] +fn build_blueprints() -> Result<(), Error> { + use std::env::*; + use std::fs::*; + use std::path::*; + use std::process::*; + use std::*; + + use cargo_toml::Manifest; + use radix_engine_interface::prelude::*; + + // All of the blueprints are in the `packages` subdirectory of the project. + // So, we get the path to it so that we can start finding the blueprints + // here. + let root_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(2) + .ok_or(Error::FailedToFindAncestor { + path: PathBuf::from(env!("CARGO_MANIFEST_DIR")), + ancestor: 2, + })? + .to_owned(); + + let packages_path = root_path.join("packages"); + let target_path = root_path.join("target"); + let builds_target_path = target_path.join("package-loader-target"); + if !builds_target_path.exists() { + create_dir(&builds_target_path)?; + } + + println!("cargo:rerun-if-changed={}", packages_path.display()); + + // Getting the name of all of the blueprints found in the packages directory + let package_names = read_dir(packages_path)? + .filter_map(Result::ok) + .filter_map(|entry| { + if entry.file_type().is_ok_and(|ty| ty.is_dir()) { + Some(entry.path()) + } else { + None + } + }) + .map(|path| { + Manifest::from_path(path.join("Cargo.toml")) + .map(|manifest| manifest.package.map(|package| package.name)) + }) + .filter_map(Result::ok) + .flatten() + .collect::>(); + + // Build 1: Building each of the packages with the package definition. + let status = Command::new("cargo") + .args([ + "build", + "--target", + "wasm32-unknown-unknown", + "--release", + "--target-dir", + builds_target_path.as_path().display().to_string().as_str(), + "--features", + "scrypto/log-info", + ]) + .args(package_names.iter().flat_map(|package_name| { + ["--package".to_owned(), package_name.to_owned()] + })) + .status()?; + if !status.success() { + return Err(Error::CompilationOfPackageFailed); + } + + // Read the package definition of the various packages - assume code to be + // an empty byte array for now. + let mut packages = package_names + .iter() + .map(|package_name| { + let wasm_path = builds_target_path + .join("wasm32-unknown-unknown") + .join("release") + .join(format!("{}.wasm", package_name.replace('-', "_"))); + + let package_definition = + radix_engine::utils::extract_definition(&read(wasm_path)?)?; + + Ok::<_, Error>(( + package_name.clone(), + (Vec::::new(), package_definition), + )) + }) + .collect::, _>>()?; + + // Build 2: Build without the package definition. + let status = Command::new("cargo") + .args([ + "build", + "--target", + "wasm32-unknown-unknown", + "--release", + "--target-dir", + builds_target_path.as_path().display().to_string().as_str(), + "--features", + "scrypto/no-schema", + "--features", + "scrypto/log-info", + ]) + .args(package_names.iter().flat_map(|package_name| { + ["--package".to_owned(), package_name.to_owned()] + })) + .status()?; + if !status.success() { + return Err(Error::CompilationOfPackageFailed); + } + + for package_name in package_names.iter() { + let wasm_path = builds_target_path + .join("wasm32-unknown-unknown") + .join("release") + .join(format!("{}.wasm", package_name.replace('-', "_"))); + + // Optimize the WASM using wasm-opt for size + wasm_opt::OptimizationOptions::new_optimize_for_size_aggressively() + .add_pass(wasm_opt::Pass::StripDebug) + .add_pass(wasm_opt::Pass::StripDwarf) + .add_pass(wasm_opt::Pass::StripProducers) + .run(&wasm_path, &wasm_path)?; + + let wasm = read(wasm_path)?; + + packages.get_mut(package_name.as_str()).unwrap().0 = wasm; + } + + let out_dir = + PathBuf::from(var("OUT_DIR").expect("out dir must be defined!")); + let compilation_path = out_dir.join("compiled_packages.bin"); + + let encoded_packages = scrypto_encode(&packages).unwrap(); + write(compilation_path, encoded_packages).unwrap(); + + Ok(()) +} + +#[derive(Debug)] +pub enum Error { + FailedToFindAncestor { + path: std::path::PathBuf, + ancestor: usize, + }, + IoError(std::io::Error), + #[cfg(feature = "build-time-blueprints")] + ManifestError(cargo_toml::Error), + CompilationOfPackageFailed, + #[cfg(feature = "build-time-blueprints")] + ExtractSchemaError(radix_engine::utils::ExtractSchemaError), + #[cfg(feature = "build-time-blueprints")] + OptimizationError(wasm_opt::OptimizationError), +} + +impl From for Error { + fn from(value: std::io::Error) -> Self { + Self::IoError(value) + } +} + +#[cfg(feature = "build-time-blueprints")] +impl From for Error { + fn from(value: cargo_toml::Error) -> Self { + Self::ManifestError(value) + } +} + +#[cfg(feature = "build-time-blueprints")] +impl From for Error { + fn from(value: radix_engine::utils::ExtractSchemaError) -> Self { + Self::ExtractSchemaError(value) + } +} + +#[cfg(feature = "build-time-blueprints")] +impl From for Error { + fn from(value: wasm_opt::OptimizationError) -> Self { + Self::OptimizationError(value) + } +} diff --git a/libraries/package-loader/src/lib.rs b/libraries/package-loader/src/lib.rs new file mode 100644 index 00000000..8f2aa962 --- /dev/null +++ b/libraries/package-loader/src/lib.rs @@ -0,0 +1,51 @@ +#[cfg(feature = "build-time-blueprints")] +#[allow(unused, clippy::module_inception)] +mod package_loader { + use radix_engine_common::prelude::*; + use radix_engine_queries::typed_substate_layout::*; + + const PACKAGES_BINARY: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/compiled_packages.bin")); + + lazy_static::lazy_static! { + static ref PACKAGES: HashMap, PackageDefinition)> = { + scrypto_decode(PACKAGES_BINARY).unwrap() + }; + } + + pub struct PackageLoader; + impl PackageLoader { + pub fn get(name: &str) -> (Vec, PackageDefinition) { + if let Some(rtn) = PACKAGES.get(name) { + rtn.clone() + } else { + panic!("Package \"{}\" not found. Are you sure that this package is: a) in the blueprints folder, b) that this is the same as the package name in the Cargo.toml file?", name) + } + } + } +} + +#[cfg(not(feature = "build-time-blueprints"))] +#[allow(unused, clippy::module_inception)] +mod package_loader { + use radix_engine_common::prelude::*; + use radix_engine_queries::typed_substate_layout::*; + use std::path::PathBuf; + + pub struct PackageLoader; + impl PackageLoader { + pub fn get(name: &str) -> (Vec, PackageDefinition) { + let package_dir = PathBuf::from_str(env!("CARGO_MANIFEST_DIR")) + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .join("packages") + .join(name); + scrypto_unit::Compile::compile(package_dir) + } + } +} + +pub use package_loader::PackageLoader; diff --git a/libraries/ports-interface/Cargo.toml b/libraries/ports-interface/Cargo.toml new file mode 100644 index 00000000..960ab48e --- /dev/null +++ b/libraries/ports-interface/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "ports-interface" +version.workspace = true +edition.workspace = true +description = "Defines the interface of the various adapters." + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +transaction = { workspace = true, optional = true } +radix-engine-common = { workspace = true } +radix-engine-derive = { workspace = true } +radix-engine-interface = { workspace = true } + +common = { path = "../common" } +scrypto-interface = { path = "../scrypto-interface" } + +[features] +default = [ + "trait", + "scrypto-stubs", + "scrypto-test-stubs", + "manifest-builder-stubs", +] +trait = [] +scrypto-stubs = [] +scrypto-test-stubs = [] +manifest-builder-stubs = ["dep:transaction"] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/libraries/ports-interface/src/lib.rs b/libraries/ports-interface/src/lib.rs new file mode 100644 index 00000000..cabab69c --- /dev/null +++ b/libraries/ports-interface/src/lib.rs @@ -0,0 +1,4 @@ +mod oracle; +mod pool; + +pub mod prelude; diff --git a/libraries/ports-interface/src/oracle.rs b/libraries/ports-interface/src/oracle.rs new file mode 100644 index 00000000..85478525 --- /dev/null +++ b/libraries/ports-interface/src/oracle.rs @@ -0,0 +1,42 @@ +//! Defines the interface that oracles must implement to be callable from +//! project ignition. This interface can be implemented by the oracles +//! or their adapters. + +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + OracleAdapter impl [ + #[cfg(feature = "trait")] + Trait, + #[cfg(feature = "scrypto-stubs")] + ScryptoStub, + #[cfg(feature = "scrypto-test-stubs")] + ScryptoTestStub, + #[cfg(feature = "manifest-builder-stubs")] + ManifestBuilderStub + ] { + /// Gets the price of one asset in terms of another. + /// + /// Returns the price of the provided base and quote assets. This is the + /// amount of the quote required to buy one of the base, so the units + /// are actually reversed from the standard Base/Quote representation. + /// + /// # Arguments + /// + /// `base`: [`ResourceAddress`] - The address of the base asset. + /// `quote`: [`ResourceAddress`] - The address of the quote asset. + /// + /// # Returns + /// + /// [`Decimal`] - The price of the asset. If the caller desires a + /// [`Price`] object then its their responsibility to construct it. + /// [`Instant`] - The instant when the price was updated, used in + /// staleness calculations. + fn get_price( + &self, + base: ResourceAddress, + quote: ResourceAddress, + ) -> (Decimal, Instant); + } +} diff --git a/libraries/ports-interface/src/pool.rs b/libraries/ports-interface/src/pool.rs new file mode 100644 index 00000000..5bb7dd90 --- /dev/null +++ b/libraries/ports-interface/src/pool.rs @@ -0,0 +1,80 @@ +//! Defines the interface of the adapters used to communicate with pools. + +use common::prelude::*; +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + PoolAdapter impl [ + #[cfg(feature = "trait")] + Trait, + #[cfg(feature = "scrypto-stubs")] + ScryptoStub, + #[cfg(feature = "scrypto-test-stubs")] + ScryptoTestStub, + ] { + /// Opens a liquidity position in the pool. + /// + /// This method opens a liquidity position, or adds liquidity, to a + /// two-resource liquidity pool and returns the pool units, change, and + /// other resources returned to it that are neither change nor pool + /// units. + /// + /// There is no assumption on what kind of pool units are returned. They + /// can be the pool units from the native pools, custom pool units, or + /// even NFTs. + fn open_liquidity_position( + &mut self, + pool_address: ComponentAddress, + #[manifest_type = "(ManifestBucket, ManifestBucket)"] + buckets: (Bucket, Bucket), + ) -> OpenLiquidityPositionOutput; + + /// Closes a liquidity position on the passed pool. + /// + /// This method closes a liquidity position, or removes liquidity, from + /// the pool returning the share of the user in the pool as well as the + /// estimated fees. + fn close_liquidity_position( + &mut self, + pool_address: ComponentAddress, + #[manifest_type = "ManifestBucket"] + pool_units: Bucket, + adapter_specific_information: AnyValue + ) -> CloseLiquidityPositionOutput; + + /// Returns the price of the pair of assets in the pool. + fn price(&mut self, pool_address: ComponentAddress) -> Price; + + /// The addresses of the pool's resources. + fn resource_addresses( + &mut self, + pool_address: ComponentAddress + ) -> (ResourceAddress, ResourceAddress); + } +} + +#[derive(Debug, ScryptoSbor)] +pub struct OpenLiquidityPositionOutput { + /// The pool units obtained as part of the contribution to the pool. + pub pool_units: Bucket, + /// Any change the pool has returned back indexed by the resource address. + pub change: IndexMap, + /// Any additional tokens that the pool has returned back. + pub others: Vec, + /// Any adapter specific information that the adapter wishes to pass back + /// to the protocol and to be given back at a later time when the position + /// is being closed + pub adapter_specific_information: AnyValue, +} + +#[derive(Debug, ScryptoSbor)] +pub struct CloseLiquidityPositionOutput { + /// Resources obtained from closing the liquidity position, indexed by the + /// resource address. + pub resources: IndexMap, + /// Any additional tokens that the pool has returned back. + pub others: Vec, + /// The amount of trading fees earned on the position. + pub fees: IndexMap, +} diff --git a/libraries/ports-interface/src/prelude.rs b/libraries/ports-interface/src/prelude.rs new file mode 100644 index 00000000..e4308388 --- /dev/null +++ b/libraries/ports-interface/src/prelude.rs @@ -0,0 +1,2 @@ +pub use crate::oracle::*; +pub use crate::pool::*; diff --git a/libraries/scrypto-interface/Cargo.toml b/libraries/scrypto-interface/Cargo.toml new file mode 100644 index 00000000..1a4a20b7 --- /dev/null +++ b/libraries/scrypto-interface/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "scrypto-interface" +description = "A library that provides a set of macros for writing and using Scrypto interfaces" +version.workspace = true +edition.workspace = true + +[dependencies] +heck = { version = "0.4.1" } +proc-macro2 = { version = "1.0.76" } +quote = { version = "1.0.35" } +syn = { version = "2.0.48", features = ["full", "extra-traits"] } + +[lib] +proc-macro = true + +[lints] +workspace = true \ No newline at end of file diff --git a/libraries/scrypto-interface/README.md b/libraries/scrypto-interface/README.md new file mode 100644 index 00000000..fd93596f --- /dev/null +++ b/libraries/scrypto-interface/README.md @@ -0,0 +1,366 @@ +
+ +

scrypto-interface

+ +

+ A library facilitating interfacing with Scrypto blueprints and generation of high-level typed abstractions +

+ +

+ License + Tests Workflow +

+
+ +## Features + +There are two main features provided in this crate: + +- A `define_interface!` function-like procedural macro that is used to define the interface of blueprints. It then generates a trait describing the interface, Scrypto, Scrypto Test, and Manifest Builder bindings based on the defined interface. +- A `blueprint_with_traits` attribute procedural macro that allows writing blueprints with a single main `impl` block and zero or more `impl`s of traits for the blueprint. + +## `define_interface!` + +This is a procedural macro used to define the interface of blueprints and generate stubs based on the defined interface. + +This macro defines a high-level trait-like DSL for defining the interface of blueprints and defining what this macro should and should not generate. This macro currently can generate the following four stubs based on the provided blueprint interface: + +- Trait: A trait of the blueprint interface including all of the methods and functions. +- Scrypto Stubs: Stubs that provide higher-level type-checked stubs for interactions with the blueprint from Scrypto. +- Scrypto Test Stubs: Stubs that provide higher-level type-checked stubs for interactions with the blueprint from the Scrypto Test framework. +- Manifest Builder Stubs: Extends the manifest builder with methods for interacting with the blueprint and components of the blueprint through the manifest builder. + +This macro can be configured to generate either all of the above stubs or just a subset of them, this can be useful in situations and cases where the crates required for the full stubs are not available in a particular setting and thus should not be generated. + +### Example + +```rust +define_interface! { + // The name of the blueprint + Radiswap { + // All of the methods and functions that the blueprint has. + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} +``` + +### Usage + +This section provides a guide on how to use this macro and the different settings and arguments that can be passed. + +#### Changing the Struct Name + +The name of the generated `struct` can be changed by adding an `as $Ident` after the blueprint name. This is useful in cases where the blueprint is named one thing but we would like for the generated stubs to use a different name completely. + +```rust +define_interface! { + // The name of the blueprint + Radiswap as Dex { + // All of the methods and functions that the blueprint has. + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} +``` + +#### Controlling What Is Generated + +As mentioned previously, this macro allows the user to specify what they wish to have generated and defaults to generating all that it can if nothing is specified explicitly. + +The user can control what they wish to have generated by passing an +`impl [$($expr),*]` after the struct name. The possible values that can be +there are: + +- `Trait` +- `ScryptoStub` +- `ScryptoTestStub` +- `ManifestBuilderStub` + +As an example, if we wish to only generate the scrypto test and the manifest builder stubs for a particular blueprint then we would invoke this macro as follows: + +```rust +define_interface! { + // The name of the blueprint - in this example, providing a struct + // name (the `as Dex` is the struct name) is optional, just shown to + // make it clear where the `impl` goes; after the blueprint and struct + // names. + Radiswap as Dex impl [ScryptoTestStub, ManifestBuilderStub] { + // All of the methods and functions that the blueprint has. + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} +``` + +#### Specifying the Manifest Types + +In some interfaces, the types to use in Scrypto and the manifest will be different, this distinction is especially important when this macro will generate the manifest builder stubs. As an example, `Bucket` is not a valid type in the context of the manifest builder, `ManifestBucket` is. + +This macro allows you to specify the type that should be used for the manifest builder by adding a `#[manifest_type = "$ty"]` on top of the argument you wish to have their type changed. + +For the Radiswap example above, we can control the types to use for the manifest builder as follows: + +```rust +define_interface! { + // The name of the blueprint - in this example, providing a struct + // name (the `as Dex` is the struct name) is optional, just shown to + // make it clear where the `impl` goes; after the blueprint and struct + // names. + Radiswap as Dex impl [ScryptoTestStub, ManifestBuilderStub] { + // All of the methods and functions that the blueprint has. + fn swap( + &mut self, + #[manifest_type = "ManifestBucket"] + bucket1: Bucket, + ) -> (Bucket, Option); + } +} +``` + +### Generated + +#### Trait + +The generated trait will have the name `$struct_name InterfaceTrait` and will have the methods and functions of the blueprint in the exact way that they were specified in the macro invocation with no difference at all. This trait will not use any of the defined `manifest_type`s as those are meant for `ManifestBuilderStub`s generated by this macro. + +This generated trait can be useful in a number of settings. An example of that would be the development of a number of adapter blueprints that must adhere to particular interface. This adherence to said interface can be checked at compile-time by defining the interface through this macro and then implementing the generated trait on the blueprint with the aid of the `blueprint_with_traits` macro. As an example: + +```rust +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + DexPairAdapter impl [Trait] { + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} + +#[blueprint_with_traits] +mod adapter1 { + struct Adapter1; + + impl Adapter1 { + /* Some functions and methods */ + } + + // This trait has been generated by the `define_interface` trait above. + // The postfix added to the name is described in this sub-section. + impl DexPairAdapterInterfaceTrait for Adapter1 { + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option) { + todo!("Write an implementation here") + } + } +} + +#[blueprint_with_traits] +mod adapter1 { + struct Adapter2; + + impl Adapter2 { + /* Some functions and methods */ + } + + // This trait has been generated by the `define_interface` trait above. + // The postfix added to the name is described in this sub-section. + impl DexPairAdapterInterfaceTrait for Adapter2 { + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option) { + todo!("Write an implementation here") + } + } +} +``` + +The adherence of the adapters to the `DexPairAdapterInterfaceTrait` trait is checked at compile-time so there is no chance of implementing the interface in an incorrect way or in a way that is not expected by the clients that will be calling into the adapters. + +#### Scrypto Stubs + +Scrypto stubs are generated from the provided interface to facilitate and provide a typed-abstraction for invoking blueprints and components that implement this interface. The generated struct has the name `$struct_name` with a postfix of `InterfaceScryptoStub`. + +The generated `struct` has all of the interface functions and methods implemented on it. The methods are implemented as is, with no changes to the arguments and the returns. Functions have an additional argument at the end named `blueprint_package_address` which is the `PackageAddress` of the package that the blueprint belongs to. + +The generated `struct` is transparent in SBOR, meaning that it can be used as an argument or a return type and will be treated as a `ComponentAddress` in encoding and decoding. Thus, no manual casting needs to be done manually by the user inside of the body of functions. + +This is especially used in areas where the `external_blueprint` and `external_component` are not suitable, specifically in cases when the package address or component address of said external entity is not known at compile-time but the only thing that is known is the interface of it. This could perhaps be due to the difference of addresses between networks or due to the component or package being instantiated or published later on. + +The following is an example of this in action: + +```rust +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + DexPairAdapter impl [ScryptoStub] { + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} + + +#[blueprint_with_traits] +mod client { + struct Client; + + impl Client { + fn call_dex( + &mut self, + // A `DexPairAdapterInterfaceScryptoStub` can be decoded from a + // `ComponentAddress` passed in the manifest. + dex_adapter: DexPairAdapterInterfaceScryptoStub, + bucket: Bucket + ) { + // The methods are available and can be called. Everything is + // typed and type checked. + let (bucket, change) = dex_adapter.swap(bucket); + + todo!("Continue the implementation!"); + } + } +} +``` + +#### Scrypto Test Stubs + +In a similar fashion to Scrypto stubs, this macro generated stubs to be used for the Scrypto Test framework. These stubs are meant to provide a typed abstraction over the blueprint removing the need to perform manual encoding and decoding and adding compile-time enforced type checks on interactions with the blueprint or components of the blueprint. The generated struct has the name `$struct_name` with a postfix of `InterfaceScryptoTestStub`. + +The generated methods and functions have the same name as defined in the macro invocation. All functions have an additional argument named `blueprint_package_address` which is the `PackageAddress` of the package that the blueprint belongs to, and all functions and methods end with an argument called `env` which is a generic argument of any type that has a `::radix_engine_interface::prelude::ClientApi` implementation. This is practically going to be the scrypto test environment. The return types are changed as well such that the functions return a `Result` instead of `T` where `T` is their original return type. + +The stubs generated by this macro can be useful in cases when tests involve blueprints external to the current project with no source code provided and just a WASM and an RPD. Thus, no scrypto-test stubs are provided with them from the `blueprint` macro. + +The following is an example of this macro in action: + +```rust +use scrypto::prelude::*; +use scrypto_test::prelude::*; +use scrypto_interface::*; + +define_interface! { + Radiswap impl [ScryptoTestStub] { + fn swap( + &mut self, + bucket1: Bucket, + ) -> (Bucket, Option); + } +} + + +#[test] +fn some_test() { + // Arrange + let env = &mut TestEnvironment::new(); + let mut pool: RadiswapInterfaceScryptoTestStub = todo!(); + + // Act + let bucket: Bucket = todo!(); + let rtn = pool.swap(bucket, env); + + // Assert + assert!(rtn.is_ok()) +} +``` + +#### Manifest Builder Stubs + +Each invocation of this macro extends the manifest builder adding methods to it that are specific to the blueprint at hand. Similar to the other stubs this also provides typed-abstractions for invocations of the blueprint in manifest builder making it much easier to invoke the blueprint or components of the blueprint from the manifest through the manifest builder. This generates an extension trait of the name `$struct_name` and a postfix of `InterfaceManifestBuilderExtensionTrait`. Since this is an extension trait, this means that the methods that it provides should be available directly on the `ManifestBuilder` type as soon as the trait is imported since this macro also generates an implementation of this extension trait. + +Out of all of the generations performed by this macro, this one perhaps does the most amount of changes to the functions and methods passed in the macro invocation. Specifically: + +- The methods on the `ManifestBuilder` are provided as the snake case name of the struct followed by the name of the method. As an example, for the `Radiswap` interface used so far in this doc, the generated method would be called `radiswap_swap` (`$struct_name _ $method_name`). +- A `PackageAddress` argument is added to the beginning for all functions and ` ComponentAddress` argument is added to the beginning of all methods. +- The types are replaced by the types specified in the `manifest_type`, if any types were specified there. + +The following is an example of this in action: + +```rust +use scrypto::prelude::*; +use scrypto_interface::*; +use transaction::builder::*; + +define_interface! { + Radiswap impl [ManifestBuilderStub] { + fn swap( + &mut self, + #[manifest_type = "ManifestBucket"] + bucket1: Bucket, + ) -> (Bucket, Option); + } +} + +#[test] +fn some_test() { + let account: ComponentAddress = todo!(); + let radiswap: ComponentAddress = todo!(); + let manifest = ManifestBuilder::new() + .withdraw_from_account(account, XRD, dec!(100)) + .take_all_from_worktop(XRD, "bucket") + .with_bucket("bucket", |builder, bucket| { + // This method is now available on the manifest builder and can + // be invoked directly. + builder.radiswap_swap(radiswap, bucket) + }) + .try_deposit_entire_worktop_or_abort(account, None); +} +``` + +## `#[blueprint_with_traits]` + +A procedural blueprint macro with the added support for traits allowing for compile-time checking of interfaces. + +This macro performs some logic and then delegates the remaining logic to scrypto's blueprint macro, thus the logic of this macro should not diverge from the main blueprint macro. + +This macro starts by finding all of the trait implementations inside the module and removing them from there. It then copies the implementation of the trait to the `impl` block of the blueprint. Then, a `const _: ()` block is used to house a trait implementation for a private type. + +This means that: + +- A blueprint can contain trait implementations. These implementations do not have a fixed place and can occur in any order and will be handled as expected by this macro. +- Functions and methods implemented through traits will be made public and can not be changed. +- Functions and methods implemented through traits will be implemented in the main impl block of the blueprint and will be considered as a normal public function or method. + +This macro can be used just like the regular `blueprint` macro from Scrypto. In fact, this macro just performs some post-processing and delegates the rest to the regular `blueprint` macro. + +### Example + +```rust +use scrypto::prelude::*; +use scrypto_interface::*; + +#[blueprint_with_traits] +mod blueprint { + pub struct MyBlueprint; + + impl MyBlueprint { + pub fn instantiate() -> Global { + todo!() + } + } + + // This is now permitted, these methods and functions will be + // implemented on the blueprint itself. + impl MyTrait for MyBlueprint { + pub fn my_method(&mut self) -> u32 { + todo!() + } + } +} + +pub trait MyTrait { + fn my_method(&mut self) -> u32; +} +``` diff --git a/libraries/scrypto-interface/src/decl_macros.rs b/libraries/scrypto-interface/src/decl_macros.rs new file mode 100644 index 00000000..3e48f30d --- /dev/null +++ b/libraries/scrypto-interface/src/decl_macros.rs @@ -0,0 +1,55 @@ +macro_rules! impl_enum_parse { + ( + $(#[$meta: meta])* + $vis: vis enum $ident: ident { + $( + $variant: ident + ),* $(,)? + } + ) => { + $(#[$meta])* + $vis enum $ident { + $( + $variant + ),* + } + + const _: () = { + impl ::core::convert::TryFrom<::syn::Ident> for $ident { + type Error = ::syn::Error; + + fn try_from(ident: ::syn::Ident) -> ::syn::Result<$ident> { + match ident.to_string().as_str() { + $( + stringify!($variant) => Ok(Self::$variant), + )* + _ => Err(::syn::Error::new( + ident.span(), + format!("\"{}\" is not a valid \"{}\". Valid values are: {:?}", ident, stringify!($ident), $ident::STRINGS) + )) + } + } + } + + impl $ident { + pub const STRINGS: &'static [&'static str] = &[ + $( + stringify!($variant) + ),* + ]; + + pub const ALL: &'static [$ident] = &[ + $( + Self::$variant + ),* + ]; + } + + impl ::syn::parse::Parse for $ident { + fn parse(input: ParseStream) -> Result { + <$ident>::try_from(Ident::parse(input)?) + } + } + }; + }; +} diff --git a/libraries/scrypto-interface/src/handlers.rs b/libraries/scrypto-interface/src/handlers.rs new file mode 100644 index 00000000..cefee704 --- /dev/null +++ b/libraries/scrypto-interface/src/handlers.rs @@ -0,0 +1,875 @@ +use std::collections::*; + +use heck::ToSnakeCase; +use proc_macro2::TokenStream as TokenStream2; +use quote::*; +use syn::spanned::*; +use syn::*; + +use crate::types::{Signature, *}; + +pub fn handle_define_interface( + input: TokenStream2, +) -> syn::Result { + let define_interface = parse2::(input)?; + + let generate = define_interface + .generate + .as_ref() + .map(|(_, _, generate)| generate.iter().cloned().collect()) + .unwrap_or( + Generate::ALL + .iter() + .map(|generate| GenerationItem { + attributes: Default::default(), + generate: *generate, + }) + .collect::>(), + ); + + let mut generated = vec![]; + for GenerationItem { + attributes, + generate, + } in generate + { + match generate { + Generate::Trait => { + generated.push(generate_trait(&define_interface, &attributes)) + } + Generate::ScryptoStub => generated + .push(generate_scrypto_stub(&define_interface, &attributes)), + Generate::ScryptoTestStub => generated.push( + generate_scrypto_test_stub(&define_interface, &attributes), + ), + Generate::ManifestBuilderStub => generated.push( + generate_manifest_builder_stub(&define_interface, &attributes)?, + ), + }; + } + + Ok(quote!( + #(#generated)* + )) +} + +fn generate_trait( + input: &DefineInterfaceInput, + attributes: &[Attribute], +) -> TokenStream2 { + let struct_ident = input.struct_ident(); + let trait_ident = format_ident!("{}InterfaceTrait", struct_ident); + + let signatures = input + .signatures + .iter() + .map( + |Signature { + attrs, + token_fn, + ident, + arguments, + rtn, + semi_colon, + .. + }| { + quote! { + #(#attrs)* + #[allow(clippy::too_many_arguments)] + #token_fn #ident ( #arguments ) #rtn #semi_colon + } + }, + ) + .collect::>(); + + quote!( + #(#attributes)* + pub trait #trait_ident { + #(#signatures)* + } + ) +} + +fn generate_scrypto_stub( + input: &DefineInterfaceInput, + attributes: &[Attribute], +) -> TokenStream2 { + let struct_ident = input.struct_ident(); + let struct_ident = format_ident!("{}InterfaceScryptoStub", struct_ident); + let blueprint_ident = &input.blueprint_ident; + + let try_from_impl = [ + "ComponentAddress", + "ResourceAddress", + "PackageAddress", + "InternalAddress", + "GlobalAddress", + ] + .iter() + .map(|ty| -> syn::Type { + let ty_ident = Ident::new(ty, blueprint_ident.span()); + parse_quote!(::radix_engine_interface::prelude::#ty_ident) + }) + .map(|ty| { + quote! { + #[allow(clippy::too_many_arguments)] + impl TryFrom<#struct_ident> for #ty + { + type Error = < + #ty as TryFrom<::radix_engine_interface::prelude::NodeId> + >::Error; + + fn try_from( + value: #struct_ident + ) -> Result + { + <#ty>::try_from( + *value.0.as_node_id() + ) + } + } + } + }) + .collect::>(); + + let functions = input + .signatures + .iter() + .map( + |Signature { + attrs, + token_fn, + ident, + arguments, + rtn, + .. + }| { + let arg_idents = arguments.arg_idents(); + + let mut arguments = arguments.clone(); + if arguments.is_function() { + arguments.add_argument_to_end( + Ident::new("blueprint_package_address", ident.span()), + parse_quote!(::radix_engine_interface::prelude::PackageAddress) + ); + } + + let inner = if arguments.is_function() { + quote! { + let rtn = ::scrypto::prelude::ScryptoVmV1Api::blueprint_call( + blueprint_package_address, + stringify!(#blueprint_ident), + stringify!(#ident), + ::radix_engine_interface::scrypto_args!(#(#arg_idents),*) + ); + ::radix_engine_interface::prelude::scrypto_decode(&rtn).unwrap() + } + } else { + quote! { + let rtn = ::scrypto::prelude::ScryptoVmV1Api::object_call( + &self.0.0, + stringify!(#ident), + ::radix_engine_interface::scrypto_args!(#(#arg_idents),*) + ); + ::radix_engine_interface::prelude::scrypto_decode(&rtn).unwrap() + } + }; + + quote! { + #(#attrs)* + #[allow(clippy::too_many_arguments)] + pub #token_fn #ident ( #arguments ) #rtn { + #inner + } + } + }, + ) + .collect::>(); + + quote! { + #[derive( + ::radix_engine_interface::prelude::ScryptoSbor, + ::radix_engine_interface::prelude::ManifestSbor, + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash + )] + #(#attributes)* + #[sbor(transparent)] + pub struct #struct_ident ( + ::radix_engine_interface::prelude::Reference + ); + + #(#attributes)* + #[allow(clippy::too_many_arguments)] + const _: () = { + impl From for #struct_ident + where + T: ::core::convert::Into<::radix_engine_interface::prelude::NodeId> + { + fn from(value: T) -> Self { + Self(::radix_engine_interface::prelude::Reference(value.into())) + } + } + + #(#try_from_impl)* + + #[allow(clippy::too_many_arguments)] + impl #struct_ident { + #(#functions)* + + pub fn blueprint_id( + package_address: ::radix_engine_interface::prelude::PackageAddress + ) -> ::radix_engine_interface::prelude::BlueprintId { + ::radix_engine_interface::prelude::BlueprintId { + package_address, + blueprint_name: stringify!(#blueprint_ident).to_string() + } + } + } + }; + } +} + +fn generate_scrypto_test_stub( + input: &DefineInterfaceInput, + attributes: &[Attribute], +) -> TokenStream2 { + let struct_ident = input.struct_ident(); + let struct_ident = + format_ident!("{}InterfaceScryptoTestStub", struct_ident); + let blueprint_ident = &input.blueprint_ident; + + let try_from_impl = [ + "ComponentAddress", + "ResourceAddress", + "PackageAddress", + "InternalAddress", + "GlobalAddress", + ] + .iter() + .map(|ty| -> syn::Type { + let ty_ident = Ident::new(ty, blueprint_ident.span()); + parse_quote!(::radix_engine_interface::prelude::#ty_ident) + }) + .map(|ty| { + quote! { + #[allow(clippy::too_many_arguments)] + impl TryFrom<#struct_ident> for #ty + { + type Error = < + #ty as TryFrom<::radix_engine_interface::prelude::NodeId> + >::Error; + + fn try_from( + value: #struct_ident + ) -> Result + { + <#ty>::try_from( + *value.0.as_node_id() + ) + } + } + } + }) + .collect::>(); + + let functions = input + .signatures + .iter() + .map( + |Signature { + attrs, + token_fn, + ident, + arguments, + rtn, + .. + }| { + let arg_idents = arguments.arg_idents(); + + let mut arguments = arguments.clone(); + if arguments.is_function() { + arguments.add_argument_to_end( + Ident::new("blueprint_package_address", ident.span()), + parse_quote!(::radix_engine_interface::prelude::PackageAddress) + ); + } + arguments.add_argument_to_end( + Ident::new("env", ident.span()), + parse_quote!(&mut Y) + ); + + let inner = if arguments.is_function() { + quote! { + env.call_function( + blueprint_package_address, + stringify!(#blueprint_ident), + stringify!(#ident), + ::radix_engine_interface::scrypto_args!(#(#arg_idents),*) + ) + .map(|rtn| ::radix_engine_interface::prelude::scrypto_decode(&rtn).unwrap()) + } + } else { + quote! { + env.call_method( + &self.0.0, + stringify!(#ident), + ::radix_engine_interface::scrypto_args!(#(#arg_idents),*) + ) + .map(|rtn| ::radix_engine_interface::prelude::scrypto_decode(&rtn).unwrap()) + } + }; + + let rtn = match rtn { + ReturnType::Default => parse_quote!(()), + ReturnType::Type(_, ty) => *ty.clone(), + }; + + quote! { + #(#attrs)* + #[allow(clippy::too_many_arguments)] + pub #token_fn #ident ( #arguments ) -> Result<#rtn, E> + where + Y: ::radix_engine_interface::prelude::ClientApi, + E: ::core::fmt::Debug + { + #inner + } + } + }, + ) + .collect::>(); + + quote! { + #[derive( + ::radix_engine_interface::prelude::ScryptoSbor, + ::radix_engine_interface::prelude::ManifestSbor, + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash + )] + #(#attributes)* + #[sbor(transparent)] + pub struct #struct_ident ( + ::radix_engine_interface::prelude::Reference + ); + + #(#attributes)* + #[allow(clippy::too_many_arguments)] + const _: () = { + impl From for #struct_ident + where + T: ::core::convert::Into<::radix_engine_interface::prelude::NodeId> + { + fn from(value: T) -> Self { + Self(::radix_engine_interface::prelude::Reference(value.into())) + } + } + + #(#try_from_impl)* + + #[allow(clippy::too_many_arguments)] + impl #struct_ident { + #(#functions)* + + pub fn blueprint_id( + package_address: ::radix_engine_interface::prelude::PackageAddress + ) -> ::radix_engine_interface::prelude::BlueprintId { + ::radix_engine_interface::prelude::BlueprintId { + package_address, + blueprint_name: stringify!(#blueprint_ident).to_string() + } + } + } + }; + } +} + +fn generate_manifest_builder_stub( + input: &DefineInterfaceInput, + attributes: &[Attribute], +) -> syn::Result { + let struct_ident = input.struct_ident(); + let trait_ident = + format_ident!("{}InterfaceManifestBuilderExtensionTrait", struct_ident); + let blueprint_ident = &input.blueprint_ident; + + let signatures = input + .signatures + .iter() + .map( + |Signature { + attrs, + token_fn, + ident, + arguments, + semi_colon, + .. + }| { + let mut arguments = arguments.clone(); + if arguments.is_function() { + arguments.add_argument_to_beginning( + Ident::new("blueprint_package_address", ident.span()), + parse_quote!( + ::radix_engine_interface::prelude::PackageAddress + ), + ); + } else { + arguments.add_argument_to_beginning( + Ident::new("component_address", ident.span()), + parse_quote!( + impl ::transaction::builder::ResolvableGlobalAddress + ), + ); + } + + let fn_ident = format_ident!( + "{}_{}", + struct_ident.to_string().to_snake_case(), + ident + ); + + arguments.manifest_arguments().map(|arguments| quote! { + #(#attrs)* + #[allow(clippy::too_many_arguments)] + #token_fn #fn_ident ( self, #arguments ) -> Self #semi_colon + }) + }, + ) + .collect::>>()?; + + let implementations = input + .signatures + .iter() + .map( + |Signature { + attrs, + token_fn, + ident, + arguments: original_arguments, + .. + }| + -> syn::Result { + let mut arguments = original_arguments.clone(); + let inner = if arguments.is_function() { + arguments.add_argument_to_beginning( + Ident::new("blueprint_package_address", ident.span()), + parse_quote!( + ::radix_engine_interface::prelude::PackageAddress + ), + ); + + let original_arguments = original_arguments + .manifest_arguments()? + .iter() + .cloned() + .map(|Argument { ident, .. }| ident) + .collect::>(); + quote! { + self.call_function( + blueprint_package_address, + stringify!(#blueprint_ident), + stringify!(#ident), + &( #(#original_arguments,)* ) + ) + } + } else { + arguments.add_argument_to_beginning( + Ident::new("component_address", ident.span()), + parse_quote!( + impl ::transaction::builder::ResolvableGlobalAddress + ), + ); + + let original_arguments = original_arguments + .manifest_arguments()? + .iter() + .cloned() + .map(|Argument { ident, .. }| ident) + .collect::>(); + quote! { + self.call_method( + component_address, + stringify!(#ident), + &( #(#original_arguments,)* ) + ) + } + }; + + let fn_ident = format_ident!( + "{}_{}", + struct_ident.to_string().to_snake_case(), + ident + ); + + let arguments = arguments.manifest_arguments()?; + Ok(quote! { + #(#attrs)* + #[allow(clippy::too_many_arguments)] + #token_fn #fn_ident (self, #arguments) -> Self { + #inner + } + }) + }, + ) + .collect::>>()?; + + Ok(quote!( + #(#attributes)* + pub trait #trait_ident { + #(#signatures)* + } + + #(#attributes)* + #[allow(clippy::too_many_arguments)] + const _: () = { + impl #trait_ident for ::transaction::builder::ManifestBuilder { + #(#implementations)* + } + }; + )) +} + +pub fn handle_blueprint_with_traits( + _: TokenStream2, + item: TokenStream2, +) -> Result { + // Parse the passed token stream as a module. After we do that, we will + // remove all of the trait impls from inside. + let span = item.span(); + let mut module = syn::parse2::(item)?; + let trait_impls = if let Some((brace, items)) = module.content { + let (trait_impls, items) = + items.into_iter().partition::, _>(|item| { + matches!( + item, + Item::Impl(ItemImpl { + trait_: Some(_), + .. + }) + ) + }); + module.content = Some((brace, items)); + trait_impls + } else { + vec![] + }; + + // Find the impl block in the module that is not for a trait and then add + // all of the trait implementations to it. + if let Some((_, ref mut items)) = module.content { + let impl_item = items + .iter_mut() + .filter_map(|item| { + if let Item::Impl(item_impl @ ItemImpl { trait_: None, .. }) = + item + { + Some(item_impl) + } else { + None + } + }) + .next() + .ok_or(syn::Error::new( + span, + "No impl block found that is not for a trait", + ))?; + + for trait_impl_item in trait_impls.iter() { + let Item::Impl(ItemImpl { items, .. }) = trait_impl_item else { + continue; + }; + + // Make any item that accepts a vis become public + let items = items + .iter() + .cloned() + .map(|item| match item { + ImplItem::Const(mut item) => { + item.vis = Visibility::Public(Token![pub](span)); + ImplItem::Const(item) + } + ImplItem::Fn(mut item) => { + item.vis = Visibility::Public(Token![pub](span)); + ImplItem::Fn(item) + } + ImplItem::Type(mut item) => { + item.vis = Visibility::Public(Token![pub](span)); + ImplItem::Type(item) + } + item @ ImplItem::Macro(..) + | item @ ImplItem::Verbatim(..) => item, + _ => todo!(), + }) + .collect::>(); + + impl_item.items.extend(items) + } + } + + if let Some((_, ref items)) = module.content { + // Getting the name of the blueprint by finding the first struct item we + // find inside the module. + let blueprint_ident = items + .iter() + .filter_map(|item| { + if let Item::Struct(ItemStruct { ident, .. }) = item { + Some(ident) + } else { + None + } + }) + .next() + .ok_or(syn::Error::new( + span, + "No struct item found inside of module", + ))?; + + let unreachable_trait_impls = trait_impls + .clone() + .into_iter() + .filter_map(|item| { + if let Item::Impl(item) = item { + Some(item) + } else { + None + } + }) + .map(|mut impl_item| { + impl_item.items = impl_item + .items + .into_iter() + .map(|mut impl_item| { + if let ImplItem::Fn(ref mut func_impl_item) = impl_item + { + func_impl_item.block = + parse_quote!({ unreachable!() }); + }; + impl_item + }) + .collect(); + impl_item + }); + + // The module should now be a perfectly well structured blueprint that + // is ready to go through the blueprint code generation process. + Ok(quote::quote! { + #[::scrypto::prelude::blueprint] + #module + + #[allow(clippy::too_many_arguments)] + const _: () = { + struct #blueprint_ident; + + #[allow(unused_variables)] + #(#unreachable_trait_impls)* + }; + }) + } else { + // The module should now be a perfectly well structured blueprint that + // is ready to go through the blueprint code generation process. + Ok(quote::quote! { + #[::scrypto::prelude::blueprint] + #module + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::str::FromStr; + + #[test] + fn blueprint_with_trait_generates_expected_code() { + // Arrange + let input = r#" + #[blueprint_with_traits] + mod blueprint{ + struct Blueprint; + + impl Blueprint {} + + impl MyTrait for Blueprint { + fn func1() { + todo!("func1"); + } + fn func2(item: u32) { + todo!("func2"); + } + fn func3() -> u32 { + todo!("func3"); + } + fn func4(item: u32) -> u32 { + todo!("func4"); + } + + fn ref_method1(&self) { + todo!("ref_method1"); + } + fn ref_method2(&self, item: u32) { + todo!("ref_method2"); + } + fn ref_method3(&self) -> u32 { + todo!("ref_method3"); + } + fn ref_method4(&self, item: u32) -> u32 { + todo!("ref_method4"); + } + + fn mut_ref_method1(&mut self) { + todo!("mut_ref_method1"); + } + fn mut_ref_method2(&mut self, item: u32) { + todo!("mut_ref_method2"); + } + fn mut_ref_method3(&mut self) -> u32 { + todo!("mut_ref_method3"); + } + fn mut_ref_method4(&mut self, item: u32) -> u32 { + todo!("mut_ref_method4"); + } + } + } + "#; + let expected_output = r#" + #[::scrypto::prelude::blueprint] + #[blueprint_with_traits] + mod blueprint{ + struct Blueprint; + + impl Blueprint { + pub fn func1() { + todo!("func1"); + } + pub fn func2(item: u32) { + todo!("func2"); + } + pub fn func3() -> u32 { + todo!("func3"); + } + pub fn func4(item: u32) -> u32 { + todo!("func4"); + } + + pub fn ref_method1(&self) { + todo!("ref_method1"); + } + pub fn ref_method2(&self, item: u32) { + todo!("ref_method2"); + } + pub fn ref_method3(&self) -> u32 { + todo!("ref_method3"); + } + pub fn ref_method4(&self, item: u32) -> u32 { + todo!("ref_method4"); + } + + pub fn mut_ref_method1(&mut self) { + todo!("mut_ref_method1"); + } + pub fn mut_ref_method2(&mut self, item: u32) { + todo!("mut_ref_method2"); + } + pub fn mut_ref_method3(&mut self) -> u32 { + todo!("mut_ref_method3"); + } + pub fn mut_ref_method4(&mut self, item: u32) -> u32 { + todo!("mut_ref_method4"); + } + } + } + + #[allow(clippy::too_many_arguments)] + const _: () = { + struct Blueprint; + + #[allow (unused_variables)] + impl MyTrait for Blueprint { + fn func1() { + unreachable!() + } + fn func2(item: u32) { + unreachable!() + } + fn func3() -> u32 { + unreachable!() + } + fn func4(item: u32) -> u32 { + unreachable!() + } + + fn ref_method1(&self) { + unreachable!() + } + fn ref_method2(&self, item: u32) { + unreachable!() + } + fn ref_method3(&self) -> u32 { + unreachable!() + } + fn ref_method4(&self, item: u32) -> u32 { + unreachable!() + } + + fn mut_ref_method1(&mut self) { + unreachable!() + } + fn mut_ref_method2(&mut self, item: u32) { + unreachable!() + } + fn mut_ref_method3(&mut self) -> u32 { + unreachable!() + } + fn mut_ref_method4(&mut self, item: u32) -> u32 { + unreachable!() + } + } + }; + "#; + + // Act + let output = handle_blueprint_with_traits( + TokenStream2::from_str("").unwrap(), + TokenStream2::from_str(input).unwrap(), + ) + .unwrap(); + + // Assert + assert_eq!( + output.to_string(), + TokenStream2::from_str(expected_output).unwrap().to_string() + ); + } + + #[test] + fn simple_define_interface_works_as_expected() { + // Arrange + let define_interface = r#" + Blueprint as StructName { + fn func1(); + fn func2(&self) -> u32; + fn func3(&mut self, item: u32) -> (u32, u32); + } + "#; + + // Act + let rtn = handle_define_interface( + TokenStream2::from_str(define_interface).unwrap(), + ); + + // Assert + rtn.expect("Interface has been defined successfully!"); + } +} diff --git a/libraries/scrypto-interface/src/lib.rs b/libraries/scrypto-interface/src/lib.rs new file mode 100644 index 00000000..9911d81c --- /dev/null +++ b/libraries/scrypto-interface/src/lib.rs @@ -0,0 +1,462 @@ +#[macro_use] +mod decl_macros; +mod handlers; +mod types; + +use proc_macro::TokenStream; + +/// A procedural macro used to define the interface of blueprints and generate +/// stubs based on the defined interface. +/// +/// This macro defines a high-level trait-like DSL for defining the interface of +/// blueprints and defining what this macro should and should not generate. This +/// macro currently can generate the following four stubs based on the provided +/// blueprint interface: +/// +/// * Trait: A trait of the blueprint interface including all of the methods and +/// functions. +/// * Scrypto Stubs: Stubs that provide higher-level type-checked stubs for +/// interactions with the blueprint from Scrypto. +/// * Scrypto Test Stubs: Stubs that provide higher-level type-checked stubs for +/// interactions with the blueprint from the Scrypto Test framework. +/// * Manifest Builder Stubs: Extends the manifest builder with methods for +/// interacting with the blueprint and components of the blueprint through +/// the manifest builder. +/// +/// This macro can be configured to generate either all of the above stubs or +/// just a subset of them, this can be useful in situations and cases where the +/// crates required for the full stubs are not available in a particular setting +/// and thus should not be generated. +/// +/// # Example +/// +/// ```no_run +/// define_interface! { +/// // The name of the blueprint +/// Radiswap { +/// // All of the methods and functions that the blueprint has. +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// ``` +/// +/// # Usage +/// +/// This section provides a guide on how to use this macro and the different +/// settings and arguments that can be passed. +/// +/// ## Changing the Struct Name +/// +/// The name of the generated `struct` can be changed by adding an `as $Ident` +/// after the blueprint name. This is useful in cases where the blueprint is +/// named one thing but we would like for the generated stubs to use a different +/// name completely. +/// +/// # Example +/// +/// ```no_run +/// define_interface! { +/// // The name of the blueprint +/// Radiswap as Dex { +/// // All of the methods and functions that the blueprint has. +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// ``` +/// +/// ## Controlling What Is Generated +/// +/// As mentioned previously, this macro allows the user to specify what they +/// wish to have generated and defaults to generating all that it could if +/// nothing is specified explicitly. +/// +/// The user can control what they wish to have generated by passing an +/// `impl [$($expr),*]` after the struct name. The possible values that can be +/// there are: +/// +/// * `Trait` +/// * `ScryptoStub` +/// * `ScryptoTestStub` +/// * `ManifestBuilderStub` +/// +/// As an example, if we wish to only generate the scrypto test and the manifest +/// builder stubs for a particular blueprint then we would invoke this macro as +/// follows: +/// +/// ```no_run +/// define_interface! { +/// // The name of the blueprint - in this example, providing a struct +/// // name (the `as Dex` is the struct name) is optional, just shown to +/// // make it clear where the `impl` goes; after the blueprint and struct +/// // names. +/// Radiswap as Dex impl [ScryptoTestStub, ManifestBuilderStub] { +/// // All of the methods and functions that the blueprint has. +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// ``` +/// +/// ## Specifying the Manifest Types +/// +/// In some interfaces, the types to use in Scrypto and the manifest will be +/// different, this distinction is especially important when this macro will +/// generate the manifest builder stubs. As an example, `Bucket` is not a valid +/// type in the context of the manifest builder, `ManifestBucket` is. +/// +/// This macro allows you to specify the type that should be used for the +/// manifest builder by adding a `#[manifest_type = "$ty"]` on top of the +/// argument you wish to have their type changed. +/// +/// For the Radiswap example above, we can control the types to use for the +/// manifest builder as follows: +/// +/// ```no_run +/// define_interface! { +/// // The name of the blueprint - in this example, providing a struct +/// // name (the `as Dex` is the struct name) is optional, just shown to +/// // make it clear where the `impl` goes; after the blueprint and struct +/// // names. +/// Radiswap as Dex impl [ScryptoTestStub, ManifestBuilderStub] { +/// // All of the methods and functions that the blueprint has. +/// fn swap( +/// &mut self, +/// #[manifest_type = "ManifestBucket"] +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// ``` +/// +/// # Generated +/// +/// ## Trait +/// +/// The generated trait will have the name `$struct_name InterfaceTrait` and +/// will have the methods and functions of the blueprint in the exact way that +/// they were specified in the macro invocation with no difference at all. This +/// trait will not use any of the defined `manifest_type`s as those are meant +/// for `ManifestBuilderStub`s generated by this macro. +/// +/// This generated trait can be useful in a number of settings. An example of +/// that would be the development of a number of adapter blueprints that must +/// adhere to particular interface. This adherence to said interface can be +/// checked at compile-time by defining the interface through this macro and +/// then implementing the generated trait on the blueprint with the aid of the +/// `blueprint_with_traits` macro. As an example: +/// +/// ```no_run +/// use scrypto::prelude::*; +/// use scrypto_interface::*; +/// +/// define_interface! { +/// DexPairAdapter impl [Trait] { +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// +/// #[blueprint_with_traits] +/// mod adapter1 { +/// struct Adapter1; +/// +/// impl Adapter1 { +/// /* Some functions and methods */ +/// } +/// +/// // This trait has been generated by the `define_interface` trait above. +/// // The postfix added to the name is described in this sub-section. +/// impl DexPairAdapterInterfaceTrait for Adapter1 { +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option) { +/// todo!("Write an implementation here") +/// } +/// } +/// } +/// +/// #[blueprint_with_traits] +/// mod adapter1 { +/// struct Adapter2; +/// +/// impl Adapter2 { +/// /* Some functions and methods */ +/// } +/// +/// // This trait has been generated by the `define_interface` trait above. +/// // The postfix added to the name is described in this sub-section. +/// impl DexPairAdapterInterfaceTrait for Adapter2 { +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option) { +/// todo!("Write an implementation here") +/// } +/// } +/// } +/// ``` +/// +/// The adherence of the adapters to the `DexPairAdapterInterfaceTrait` trait +/// is checked at compile-time and so there is no chance of implementing the +/// interface in an incorrect way or in a way that is not expected by the +/// clients that will be calling into the adapters. +/// +/// ## Scrypto Stubs +/// +/// Scrypto stubs are generated from the provided interface to facilitate and +/// provide a typed-abstraction for invoking blueprints and components that +/// implement this interface. The generated struct has the name `$struct_name` +/// with a postfix of `InterfaceScryptoStub`. +/// +/// The generated struct has all of the interface functions and methods +/// implemented on it. The methods are implemented as is, with no changes +/// to the arguments and the returns. Functions have an additional argument at +/// the end named `blueprint_package_address` which is the `PackageAddress` of +/// the package that the blueprint belongs to. +/// +/// The generated struct is transparent in SBOR, meaning that is can be used as +/// an argument or a return type and will be treated as a `ComponentAddress` in +/// encoding and decoding. Thus, no manual casting needs to be done manually by +/// the user inside of the body of functions. +/// +/// This is especially user in areas where the `external_blueprint` and +/// `external_component` is not suitable, specifically in cases when the +/// package address or component address of said external entity is not known +/// at compile-time but the only thing that is known is the interface of it. +/// This could perhaps be due to the difference of addresses between networks or +/// due to the component or package being instantiated or published later on. +/// +/// The following is an example of this in action: +/// +/// ```no_run +/// use scrypto::prelude::*; +/// use scrypto_interface::*; +/// +/// define_interface! { +/// DexPairAdapter impl [ScryptoStub] { +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// +/// +/// #[blueprint_with_traits] +/// mod client { +/// struct Client; +/// +/// impl Client { +/// fn call_dex( +/// &mut self, +/// // A `DexPairAdapterInterfaceScryptoStub` can be decoded from a +/// // `ComponentAddress` passed in the manifest. +/// dex_adapter: DexPairAdapterInterfaceScryptoStub, +/// bucket: Bucket +/// ) { +/// // The methods are available and can be called. Everything is +/// // typed and type checked. +/// let (bucket, change) = dex_adapter.swap(bucket); +/// +/// todo!("Continue the implementation!"); +/// } +/// } +/// } +/// ``` +/// +/// ## Scrypto Test Stubs +/// +/// In a similar fashion to Scrypto stubs, this macro generated stubs to be used +/// for the Scrypto Test framework. These stubs are meant to provide a typed +/// abstraction over the blueprint removing the need to perform manual encoding +/// and decoding and adding compile-time enforced type checks on interactions +/// with the blueprint or components of the blueprint. The generated struct +/// has the name `$struct_name` with a postfix of `InterfaceScryptoTestStub`. +/// +/// The generated methods and functions have the same name as defined in the +/// macro invocation. All functions have an additional argument named +/// `blueprint_package_address` which is the `PackageAddress` of the package +/// that the blueprint belongs to, and all functions and methods end with an +/// argument called `env` which is a generic argument of any type that has a +/// `::radix_engine_interface::prelude::ClientApi` implementation. This is +/// practically going to be the scrypto test environment. The return types are +/// changed as well such that the functions return a `Result` +/// instead of `T` where `T` is their original return type. +/// +/// The stubs generated by this macro can be useful in cases when tests involve +/// blueprints external to the current project with no source code provided and +/// just a WASM and an RPD. Thus, no scrypto-test stubs are provided with them +/// from the `blueprint` macro. +/// +/// The following is an example of this macro in action: +/// +/// ```no_run +/// use scrypto::prelude::*; +/// use scrypto_test::prelude::*; +/// use scrypto_interface::*; +/// +/// define_interface! { +/// Radiswap impl [ScryptoTestStub] { +/// fn swap( +/// &mut self, +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// +/// +/// #[test] +/// fn some_test() { +/// // Arrange +/// let env = &mut TestEnvironment::new(); +/// let mut pool: RadiswapInterfaceScryptoTestStub = todo!(); +/// +/// // Act +/// let bucket: Bucket = todo!(); +/// let rtn = pool.swap(bucket, env); +/// +/// // Assert +/// assert!(rtn.is_ok()) +/// } +/// ``` +/// +/// ## Manifest Builder Stubs +/// +/// Each invocation of this macro extends the manifest builder adding methods +/// to it that are specific to the blueprint at hand. Similar to the other stubs +/// this also provides typed-abstractions for invocations of the blueprint in +/// manifest builder making it much easier to invoke the blueprint or components +/// of the blueprint from the manifest through the manifest builder. This +/// generates an extension trait of the name `$struct_name` and a postfix of +/// `InterfaceManifestBuilderExtensionTrait`. Since this is an extension trait, +/// this means that the methods that it provides should be available directly on +/// the `ManifestBuilder` type as soon as the trait is imported since this +/// macro also generates an implementation of this extension trait. +/// +/// Out of all of the generations performed by this macro, this one perhaps does +/// the most amount of changes to the functions and methods passed in the macro +/// invocation. Specifically: +/// +/// * The methods on the `ManifestBuilder` are provided as the snake case name +/// of the struct followed by the name of the method. As an example, for the +/// `Radiswap` interface used so far in this doc, the generated method would be +/// called `radiswap_swap` (`$struct_name _ $method_name`). +/// * A `PackageAddress` argument is added to the beginning for all functions +/// and ` ComponentAddress` argument is added to the beginning of all methods. +/// * The types are replaced by the types specified in the `manifest_type`, if +/// any types were specified there. +/// +/// The following is an example of this in action: +/// +/// ```no_run +/// use scrypto::prelude::*; +/// use scrypto_interface::*; +/// use transaction::builder::*; +/// +/// define_interface! { +/// Radiswap impl [ManifestBuilderStub] { +/// fn swap( +/// &mut self, +/// #[manifest_type = "ManifestBucket"] +/// bucket1: Bucket, +/// ) -> (Bucket, Option); +/// } +/// } +/// +/// #[test] +/// fn some_test() { +/// let account: ComponentAddress = todo!(); +/// let radiswap: ComponentAddress = todo!(); +/// let manifest = ManifestBuilder::new() +/// .withdraw_from_account(account, XRD, dec!(100)) +/// .take_all_from_worktop(XRD, "bucket") +/// .with_bucket("bucket", |builder, bucket| { +/// // This method is now available on the manifest builder and can +/// // be invoked directly. +/// builder.radiswap_swap(radiswap, bucket) +/// }) +/// .try_deposit_entire_worktop_or_abort(account, None); +/// } +/// ``` +#[proc_macro] +pub fn define_interface(input: TokenStream) -> TokenStream { + handlers::handle_define_interface(input.into()) + .unwrap_or_else(|err| err.to_compile_error()) + .into() +} + +/// A procedural blueprint macro with the added support for traits allowing for +/// compile-time checking of interfaces. +/// +/// This macro performs some logic and then delegates the remaining logic to +/// scrypto's blueprint macro, thus the logic of this macro should not diverge +/// from the main blueprint macro. +/// +/// This macro starts by finding all of the trait implementations inside the +/// module and removing them from there. It then copies the implementation of +/// the trait to the `impl` block of the blueprint. Then, a `const _: ()` block +/// is used to house a trait implementation for a private type. +/// +/// This means that: +/// * A blueprint can contain trait implementations. These implementations do +/// not have a fixed place and can occur in any order and will be handled as +/// expected by this macro. +/// * Functions and methods implemented through traits will be made public and +/// can not be changed. +/// * Functions and methods implemented through traits will be implemented in +/// the main impl block of the blueprint and will be considered as a normal +/// public function or method. +/// +/// This macro can be used just like the regular `blueprint` macro from Scrypto. +/// In fact, this macro just performs some post processing and delegates the +/// rest to the regular `blueprint` macro. +/// +/// # Example +/// +/// ```no_run +/// use scrypto::prelude::*; +/// use scrypto_interface::*; +/// +/// #[blueprint_with_traits] +/// mod blueprint { +/// pub struct MyBlueprint; +/// +/// impl MyBlueprint { +/// pub fn instantiate() -> Global { +/// todo!() +/// } +/// } +/// +/// // This is now permitted, these methods and functions will be +/// // implemented on the blueprint itself. +/// impl MyTrait for MyBlueprint { +/// pub fn my_method(&mut self) -> u32 { +/// todo!() +/// } +/// } +/// } +/// +/// pub trait MyTrait { +/// fn my_method(&mut self) -> u32; +/// } +/// ``` +#[proc_macro_attribute] +pub fn blueprint_with_traits( + meta: TokenStream, + item: TokenStream, +) -> TokenStream { + handlers::handle_blueprint_with_traits(meta.into(), item.into()) + .unwrap_or_else(|err| err.to_compile_error()) + .into() +} diff --git a/libraries/scrypto-interface/src/types.rs b/libraries/scrypto-interface/src/types.rs new file mode 100644 index 00000000..56bda10d --- /dev/null +++ b/libraries/scrypto-interface/src/types.rs @@ -0,0 +1,867 @@ +#![allow(clippy::type_complexity, clippy::enum_variant_names, dead_code)] + +use quote::*; +use syn::parse::*; +use syn::punctuated::*; +use syn::spanned::Spanned; +use syn::token::*; +use syn::*; + +#[derive(Clone, Debug)] +pub struct DefineInterfaceInput { + pub blueprint_ident: Ident, + pub struct_ident: Option<(Token![as], Ident)>, + pub generate: + Option<(Token![impl], Bracket, Punctuated)>, + pub brace: Brace, + pub signatures: Vec, +} + +impl DefineInterfaceInput { + pub fn struct_ident(&self) -> &Ident { + self.struct_ident + .as_ref() + .map(|(_, ident)| ident) + .unwrap_or(&self.blueprint_ident) + } +} + +impl Parse for DefineInterfaceInput { + fn parse(input: ParseStream) -> Result { + let blueprint_ident = input.parse()?; + let struct_ident = if input.peek(Token![as]) { + Some((input.parse()?, input.parse()?)) + } else { + None + }; + let generate = if input.peek(Token![impl]) { + let impl_token = input.parse()?; + + let content; + let bracket = bracketed!(content in input); + + let inner = + content.parse_terminated(GenerationItem::parse, Token![,])?; + Some((impl_token, bracket, inner)) + } else { + None + }; + + let content; + let brace = braced!(content in input); + let mut signatures = vec![]; + while content.peek(Token![fn]) || content.peek(Token![#]) { + signatures.push(content.parse()?); + } + + Ok(Self { + blueprint_ident, + struct_ident, + generate, + brace, + signatures, + }) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct GenerationItem { + pub attributes: Vec, + pub generate: Generate, +} + +impl Parse for GenerationItem { + fn parse(input: ParseStream) -> Result { + let attributes = input.call(Attribute::parse_outer)?; + let generate = input.parse::()?; + Ok(Self { + attributes, + generate, + }) + } +} + +impl_enum_parse! { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + pub enum Generate { + Trait, + ScryptoStub, + ScryptoTestStub, + ManifestBuilderStub, + } +} + +#[derive(Clone, Debug)] +pub struct Signature { + pub attrs: Vec, + pub token_fn: Token![fn], + pub ident: Ident, + pub paren: Paren, + pub arguments: Arguments, + pub rtn: ReturnType, + pub semi_colon: Token![;], +} + +impl Parse for Signature { + fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + + let token_fn = input.parse()?; + let ident = input.parse()?; + + let content; + let paren = parenthesized!(content in input); + + let arguments = content.parse()?; + let rtn = input.parse()?; + let semi_colon = input.parse()?; + + Ok(Self { + attrs, + token_fn, + ident, + paren, + arguments, + rtn, + semi_colon, + }) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Arguments { + NoReceiver { + arguments: Punctuated, + }, + SelfReferenceReceiver { + ampersand_token: Token![&], + self_token: Token![self], + arguments: Punctuated, + }, + SelfMutReferenceReceiver { + ampersand_token: Token![&], + mut_token: Token![mut], + self_token: Token![self], + arguments: Punctuated, + }, +} + +impl Arguments { + pub fn arguments(&self) -> &Punctuated { + match self { + Self::NoReceiver { ref arguments } + | Self::SelfReferenceReceiver { ref arguments, .. } + | Self::SelfMutReferenceReceiver { ref arguments, .. } => arguments, + } + } + + pub fn arguments_mut(&mut self) -> &mut Punctuated { + match self { + Self::NoReceiver { ref mut arguments } + | Self::SelfReferenceReceiver { + ref mut arguments, .. + } + | Self::SelfMutReferenceReceiver { + ref mut arguments, .. + } => arguments, + } + } + + pub fn manifest_arguments( + &self, + ) -> syn::Result> { + let mut list = Punctuated::new(); + + for argument in self.arguments() { + list.push(argument.manifest_argument()?) + } + + Ok(list) + } + + pub fn len(&self) -> usize { + match self { + Self::NoReceiver { arguments } => arguments.len(), + Self::SelfReferenceReceiver { arguments, .. } + | Self::SelfMutReferenceReceiver { arguments, .. } => { + // Unwrap here is fine, this all happens at compile time. Plus, + // who would have more than u64 or u32 worth of arguments? + arguments.len().checked_add(1).unwrap() + } + } + } + + pub fn is_function(&self) -> bool { + match self { + Self::NoReceiver { .. } => true, + Self::SelfReferenceReceiver { .. } + | Self::SelfMutReferenceReceiver { .. } => false, + } + } + + pub fn is_method(&self) -> bool { + match self { + Self::NoReceiver { .. } => false, + Self::SelfReferenceReceiver { .. } + | Self::SelfMutReferenceReceiver { .. } => true, + } + } + + pub fn arg_idents(&self) -> impl Iterator { + self.arguments().iter().map(|Argument { ident, .. }| ident) + } + + pub fn add_argument_to_end(&mut self, ident: Ident, ty: syn::Type) { + let span = ident.span(); + self.arguments_mut().push(Argument { + attributes: vec![], + ident, + colon: Token![:](span), + ty, + }) + } + + pub fn add_argument_to_beginning(&mut self, ident: Ident, ty: syn::Type) { + let span = ident.span(); + self.arguments_mut().insert( + 0, + Argument { + attributes: vec![], + ident, + colon: Token![:](span), + ty, + }, + ) + } +} + +impl ToTokens for Arguments { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let arguments = match self { + Arguments::NoReceiver { arguments } => arguments, + Arguments::SelfReferenceReceiver { + ampersand_token, + self_token, + arguments, + } => { + ampersand_token.to_tokens(tokens); + self_token.to_tokens(tokens); + Token![,](self_token.span()).to_tokens(tokens); + arguments + } + Arguments::SelfMutReferenceReceiver { + ampersand_token, + mut_token, + self_token, + arguments, + } => { + ampersand_token.to_tokens(tokens); + mut_token.to_tokens(tokens); + self_token.to_tokens(tokens); + Token![,](self_token.span()).to_tokens(tokens); + arguments + } + }; + + arguments.to_tokens(tokens) + } +} + +impl Parse for Arguments { + fn parse(input: ParseStream) -> Result { + let mut arguments = if input.peek(Token![&]) { + let ampersand_token = input.parse::()?; + + if input.peek(Token![self]) { + Self::SelfReferenceReceiver { + ampersand_token, + self_token: input.parse()?, + arguments: Punctuated::new(), + } + } else if input.peek(Token![mut]) & input.peek2(Token![self]) { + Self::SelfMutReferenceReceiver { + ampersand_token, + mut_token: input.parse()?, + self_token: input.parse()?, + arguments: Punctuated::new(), + } + } else { + return Err(input.error("Arguments are invalid")); + } + } else { + Self::NoReceiver { + arguments: Punctuated::new(), + } + }; + + if input.peek(Token![,]) { + input.parse::()?; + } + + let args_inner = match arguments { + Self::NoReceiver { ref mut arguments } + | Self::SelfReferenceReceiver { + ref mut arguments, .. + } + | Self::SelfMutReferenceReceiver { + ref mut arguments, .. + } => arguments, + }; + *args_inner = + Punctuated::::parse_terminated(input)?; + + Ok(arguments) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Argument { + pub attributes: Vec, + pub ident: Ident, + pub colon: Token![:], + pub ty: syn::Type, +} + +impl Argument { + pub fn manifest_type(&self) -> syn::Result { + for attribute in self.attributes.iter() { + if let Meta::NameValue(MetaNameValue { + ref path, + ref value, + .. + }) = attribute.meta + { + if path.is_ident("manifest_type") { + let Expr::Lit(ExprLit { + lit: Lit::Str(str_lit), + .. + }) = value + else { + return Err(syn::Error::new_spanned( + value, + "Expect this to be a string literal", + )); + }; + + return str_lit.parse_with(syn::Type::parse); + } + } + } + Ok(self.ty.clone()) + } + + pub fn manifest_argument(&self) -> syn::Result { + let mut argument = self.clone(); + argument.ty = argument.manifest_type()?; + Ok(argument) + } +} + +impl Parse for Argument { + fn parse(input: ParseStream) -> Result { + let attributes = input.call(Attribute::parse_outer)?; + let ident = input.parse::()?; + let colon = input.parse::()?; + let ty = input.parse::()?; + + Ok(Self { + attributes, + ident, + colon, + ty, + }) + } +} + +impl ToTokens for Argument { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.ident.to_tokens(tokens); + self.colon.to_tokens(tokens); + self.ty.to_tokens(tokens); + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use super::*; + + #[test] + fn parsing_of_no_arguments_produces_a_no_receiver_empty_arguments_list() { + // Arrange + let arguments = ""; + + // Act + let arguments = + parse::(arguments).expect("Parsing must succeed"); + + // Assert + assert_eq!( + arguments, + Arguments::NoReceiver { + arguments: Punctuated::new() + } + ); + } + + #[test] + fn parsing_of_a_self_reference_produced_self_reference_arguments_empty_arguments_list( + ) { + // Arrange + let arguments = "&self"; + + // Act + let arguments = + parse::(arguments).expect("Parsing must succeed"); + + // Assert + assert!(matches!( + arguments, + Arguments::SelfReferenceReceiver { arguments, .. } + if arguments.is_empty() + )); + } + + #[test] + fn parsing_of_a_mut_self_reference_produced_mut_self_reference_arguments_empty_arguments_list( + ) { + // Arrange + let arguments = "&mut self"; + + // Act + let arguments = + parse::(arguments).expect("Parsing must succeed"); + + // Assert + assert!(matches!( + arguments, + Arguments::SelfMutReferenceReceiver { arguments, .. } + if arguments.is_empty() + )); + } + + #[test] + fn trailing_comma_in_a_self_reference_is_ignored() { + // Arrange + let arguments = "&self,"; + + // Act + let arguments = + parse::(arguments).expect("Parsing must succeed"); + + // Assert + assert!(matches!( + arguments, + Arguments::SelfReferenceReceiver { arguments, .. } + if arguments.is_empty() + )); + } + + #[test] + fn trailing_comma_in_a_mut_self_reference_is_ignored() { + // Arrange + let arguments = "&mut self,"; + + // Act + let arguments = + parse::(arguments).expect("Parsing must succeed"); + + // Assert + assert!(matches!( + arguments, + Arguments::SelfMutReferenceReceiver { arguments, .. } + if arguments.is_empty() + )); + } + + #[test] + fn multiple_receivers_are_invalid_1() { + // Arrange + let arguments = "&self, &self"; + + // Act + let arguments = parse::(arguments); + + // Assert + assert!(arguments.is_err(), "Must fail"); + } + + #[test] + fn multiple_receivers_are_invalid_2() { + // Arrange + let arguments = "&self, &mut self"; + + // Act + let arguments = parse::(arguments); + + // Assert + assert!(arguments.is_err(), "Must fail"); + } + + #[test] + fn parsing_of_arguments_of_no_receiver_succeeds() { + // Arrange + let arguments = "name: String, item: u32"; + + // Act + let arguments = parse::(arguments).expect("Can't fail!"); + + // Assert + let Arguments::NoReceiver { arguments } = arguments else { + panic!("Must succeed!") + }; + assert_eq!(arguments.len(), 2); + assert_eq!(to_string(&arguments[0].ident), "name"); + assert_eq!(to_string(&arguments[0].ty), "String"); + assert_eq!(to_string(&arguments[1].ident), "item"); + assert_eq!(to_string(&arguments[1].ty), "u32"); + } + + #[test] + fn parsing_of_arguments_of_self_reference_receiver_succeeds() { + // Arrange + let arguments = "&self, name: String, item: u32"; + + // Act + let arguments = parse::(arguments).expect("Can't fail!"); + + // Assert + let Arguments::SelfReferenceReceiver { arguments, .. } = arguments + else { + panic!("Must succeed!") + }; + assert_eq!(arguments.len(), 2); + assert_eq!(to_string(&arguments[0].ident), "name"); + assert_eq!(to_string(&arguments[0].ty), "String"); + assert_eq!(to_string(&arguments[1].ident), "item"); + assert_eq!(to_string(&arguments[1].ty), "u32"); + } + + #[test] + fn parsing_of_arguments_of_mut_self_reference_receiver_succeeds() { + // Arrange + let arguments = "&mut self, name: String, item: u32"; + + // Act + let arguments = parse::(arguments).expect("Can't fail!"); + + // Assert + let Arguments::SelfMutReferenceReceiver { arguments, .. } = arguments + else { + panic!("Must succeed!") + }; + assert_eq!(arguments.len(), 2); + assert_eq!(to_string(&arguments[0].ident), "name"); + assert_eq!(to_string(&arguments[0].ty), "String"); + assert_eq!(to_string(&arguments[1].ident), "item"); + assert_eq!(to_string(&arguments[1].ty), "u32"); + } + + #[test] + fn parsing_of_arguments_of_self_reference_receiver_with_trailing_comma_succeeds( + ) { + // Arrange + let arguments = "&self, name: String, item: u32,"; + + // Act + let arguments = parse::(arguments).expect("Can't fail!"); + + // Assert + let Arguments::SelfReferenceReceiver { arguments, .. } = arguments + else { + panic!("Must succeed!") + }; + assert_eq!(arguments.len(), 2); + assert_eq!(to_string(&arguments[0].ident), "name"); + assert_eq!(to_string(&arguments[0].ty), "String"); + assert_eq!(to_string(&arguments[1].ident), "item"); + assert_eq!(to_string(&arguments[1].ty), "u32"); + } + + #[test] + fn parsing_of_arguments_of_mut_self_reference_receiver_with_trailing_comma_succeeds( + ) { + // Arrange + let arguments = "&mut self, name: String, item: u32,"; + + // Act + let arguments = parse::(arguments).expect("Can't fail!"); + + // Assert + let Arguments::SelfMutReferenceReceiver { arguments, .. } = arguments + else { + panic!("Must succeed!") + }; + assert_eq!(arguments.len(), 2); + assert_eq!(to_string(&arguments[0].ident), "name"); + assert_eq!(to_string(&arguments[0].ty), "String"); + assert_eq!(to_string(&arguments[1].ident), "item"); + assert_eq!(to_string(&arguments[1].ty), "u32"); + } + + #[test] + fn parsing_of_simple_function_succeeds() { + // Arrange + let signature = "fn item();"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!(signature.arguments.arguments().len(), 0); + assert_eq!(signature.rtn, ReturnType::Default); + } + + #[test] + fn parsing_of_function_with_return_type_succeeds() { + // Arrange + let signature = "fn item() -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!(signature.arguments.arguments().len(), 0); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_tuple_return_type_succeeds() { + // Arrange + let signature = "fn item() -> (u32, u32);"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!(signature.arguments.arguments().len(), 0); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "(u32 , u32)") + ); + } + + #[test] + fn parsing_of_function_with_attributes_succeeds() { + // Arrange + let signature = "#[doc = \"Some doc\"] fn item() -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 1); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!(signature.arguments.arguments().len(), 0); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_arguments_succeeds() { + // Arrange + let signature = "fn item(value: u32) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_arguments_and_trailing_comma_succeeds() { + // Arrange + let signature = "fn item(value: u32,) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_self_reference_with_arguments_succeeds() { + // Arrange + let signature = "fn item(&self, value: u32) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_self_reference_with_arguments_and_trailing_comma_succeeds( + ) { + // Arrange + let signature = "fn item(&self, value: u32,) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_mut_self_reference_with_arguments_succeeds() { + // Arrange + let signature = "fn item(&mut self, value: u32) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_function_with_mut_self_reference_with_arguments_and_trailing_comma_succeeds( + ) { + // Arrange + let signature = "fn item(&mut self, value: u32,) -> u32;"; + + // Act + let signature = parse::(signature).expect("Must succeed!"); + + // Assert + assert_eq!(signature.attrs.len(), 0); + assert_eq!(to_string(&signature.ident), "item"); + assert_eq!( + to_string(&signature.arguments.arguments()[0].ident), + "value" + ); + assert_eq!(to_string(&signature.arguments.arguments()[0].ty), "u32"); + assert!( + matches!(signature.rtn, ReturnType::Type(_, item) if to_string(&item) == "u32") + ); + } + + #[test] + fn parsing_of_define_interface_succeeds() { + // Arguments + let define_interface = r#" + Blueprint as StructName impl [Trait, ScryptoStub, ScryptoTestStub, ManifestBuilderStub] { + fn function1(); + fn function2(&self); + fn function3(&mut self); + + fn function4(item: u32); + fn function5(&self, item: u32); + fn function6(&mut self, item: u32); + } + "#; + + // Act + let define_interface = parse::(define_interface) + .expect("Must succeed!"); + + // Assert + assert_eq!(to_string(&define_interface.blueprint_ident), "Blueprint"); + assert!(define_interface + .struct_ident + .is_some_and(|item| to_string(&item.1) == "StructName")); + assert!(define_interface.generate.is_some_and(|item| item + .2 + .iter() + .map(|item| item.generate) + .collect::>() + == vec![ + Generate::Trait, + Generate::ScryptoStub, + Generate::ScryptoTestStub, + Generate::ManifestBuilderStub + ])) + } + + #[test] + fn manifest_types_specified_for_arguments_are_handled_as_expected() { + // Arrange + let argument = r#" + #[manifest_type = "ManifestBucket"] + bucket: Bucket + "#; + + // Act + let argument = parse::(argument).expect("Must succeed!"); + let manifest_argument = + argument.manifest_argument().expect("Must succeed!"); + + // Assert + assert_eq!(to_string(&manifest_argument.ident), "bucket"); + assert_eq!(to_string(&manifest_argument.ty), "ManifestBucket"); + } + + fn parse(input: &str) -> syn::Result + where + T: syn::parse::Parse, + { + let token_stream = + proc_macro2::token_stream::TokenStream::from_str(input)?; + syn::parse2(token_stream) + } + + fn to_string(item: &T) -> String + where + T: ToTokens, + { + quote!(#item).to_string() + } +} diff --git a/libraries/scrypto-math/Cargo.toml b/libraries/scrypto-math/Cargo.toml new file mode 100644 index 00000000..be77285e --- /dev/null +++ b/libraries/scrypto-math/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "scrypto-math" +version = "0.4.0" +edition = "2021" +license = "MIT" +description = "Math library extending Radix Scrypto with more advanced mathematical operations" +repository = "https://github.com/ociswap/scrypto-math" + +[dependencies] +utils = { workspace = true } +radix-engine-common = { workspace = true } +radix-engine-interface = { workspace = true } + +num-traits = { version = "0.2.15" } +pretty_assertions = { version = "1.4.0" } diff --git a/libraries/scrypto-math/LICENSE b/libraries/scrypto-math/LICENSE new file mode 100644 index 00000000..3cd6206d --- /dev/null +++ b/libraries/scrypto-math/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Ociswap + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libraries/scrypto-math/README.md b/libraries/scrypto-math/README.md new file mode 100644 index 00000000..f2ad090c --- /dev/null +++ b/libraries/scrypto-math/README.md @@ -0,0 +1,77 @@ +# scrypto_math + +## Why +Radix Scrypto currently is lacking more advanced mathematical operations like `exp`, `log` or `pow`. + +`scrypto_math` aims to provide an alternative until these functionalities are provided upstream. The ultimate goal of `scrypto_math` however is to make itself obsolete. + +## Usage +Add `scrypto_math` to your depdencies in the `Cargo.toml` of your Scrypto blueprint. +```rust +[dependencies] +scrypto_math = { git = "https://github.com/ociswap/scrypto-math", tag = "v0.4.0" } +``` +Import the module: +```rust +use scrypto_math::*; +``` + +## Featues + +### Exponential Function +The exponential function is provided for `Decimal` and `PreciseDecimal` with a polynomial approximation error lower than ~ 18 significant digits. +Background: the final result is calculated via `exp(x) = 2**k * R(r)` and the approximation `R(r)` is bound by an maximum error of `2**-59` (~ 18 decimal places). + +For `Decimal`: +```rust +let exp: Option = dec!(4).exp(); +``` + +For `PreciseDecimal`: +```rust +let exp: Option = pdec!(4).exp(); +``` + +You can see a full blueprint example including tests here [AdvancedMathDemo](examples/advanced_math/src/lib.rs). + +### Logarithm Function +Logarithm is available for `Decimal` and `PreciseDecimal` with a maximum polynomial approximation error bound by `2**-58.45` (~ 18 decimal places). + +For `Decimal`: +```rust +let ln: Option = dec!(2).ln(); +let log2: Option = dec!(3).log2(); +let log10: Option = dec!(4).log10(); +let log8: Option = dec!(5).log_base(base: dec!(8)); +``` + +For `PreciseDecimal`: +```rust +let ln: Option = pdec!(2).ln(); +let log2: Option = pdec!(3).log2(); +let log10: Option = pdec!(4).log10(); +let log8: Option = pdec!(5).log_base(base: pdec!(8)); +``` + +You can see a full blueprint example including tests here [AdvancedMathDemo](examples/advanced_math/src/lib.rs). + +### Power Function +The power function internally uses both `exp` and `ln` and also covers various special cases like `0**0` or `-2**3`. + +For `Decimal`: +```rust +let pow: Option = dec!("3.14").pow("-14.12"); +``` + +For `PreciseDecimal`: +```rust +let pow: Option = pdec!("3.14").pow("-45.97"); +``` + +You can see a full blueprint example including tests here [AdvancedMathDemo](examples/advanced_math/src/lib.rs). + +## Contributions +We are happy to collaborate and review and merge pull requests :) + +## Disclaimer +Though covered by an extensive test suite, use at your own risk. diff --git a/libraries/scrypto-math/src/exponential.rs b/libraries/scrypto-math/src/exponential.rs new file mode 100644 index 00000000..d8ff50d9 --- /dev/null +++ b/libraries/scrypto-math/src/exponential.rs @@ -0,0 +1,337 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: Reduce x to an r so that |r| <= 0.5*ln2 ~ + * 0.34658. Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on the + * interval [0,0.34658]: Write R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + + * r*r/6 - r**4/360 + ... We use a special Remez algorithm on + * [0,0.34658] to generate a polynomial of degree 5 to approximate R. + * The maximum error of this polynomial approximation is bounded by + * 2**-59. In other words, R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + + * P4*z**4 + P5*z**5 (where z=r*r, and the values of P1 to P5 are listed + * below) and | 5 | -59 | + * 2.0+P1*z+...+P5*z - R(z) | <= 2 | | + * The computation of exp(r) thus becomes 2*r exp(r) = 1 + ---------- + * R(r) - r r*c(r) = 1 + r + ----------- (for better accuracy) 2 - c(r) + * where 2 4 10 c(r) = r - (P1*r + P2*r + ... + P5*r + * ). + * + * 3. Scale back to obtain exp(x): From step 1, we have exp(x) = 2^k * + * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + */ + +use num_traits::ToPrimitive; +use radix_engine_common::math::{Decimal, PreciseDecimal}; +use radix_engine_interface::{dec, pdec}; + +const LN2: PreciseDecimal = pdec!("0.693147180559945309417232121458176568"); +const HALF_POSITIVE: PreciseDecimal = pdec!("0.5"); +const HALF_NEGATIVE: PreciseDecimal = pdec!("-0.5"); +const INVLN2: PreciseDecimal = pdec!("1.442695040888963407359924681001892137"); + +const P1: PreciseDecimal = pdec!("0.166666666666666019037"); // 1.66666666666666019037e-01 +const P2: PreciseDecimal = pdec!("-0.00277777777770155933842"); // -2.77777777770155933842e-03 +const P3: PreciseDecimal = pdec!("0.0000661375632143793436117"); // 6.61375632143793436117e-05 +const P4: PreciseDecimal = pdec!("-0.00000165339022054652515390"); // -1.65339022054652515390e-06 +const P5: PreciseDecimal = pdec!("0.0000000413813679705723846039"); //4.13813679705723846039e-08 + +pub trait ExponentialDecimal { + fn exp(&self) -> Option; +} + +pub trait ExponentialPreciseDecimal { + fn exp(&self) -> Option; +} + +impl ExponentialDecimal for Decimal { + /// Calculates the exponential function of a Decimal + /// Using the exponential function of a PreciseDecimal internally + fn exp(&self) -> Option { + if self < &dec!(-42) { + return Some(Decimal::ZERO); + } + if self > &dec!(90) { + return None; + } + PreciseDecimal::try_from(*self) + .ok()? + .exp() + .and_then(|e| e.try_into().ok()) + } +} + +impl ExponentialPreciseDecimal for PreciseDecimal { + /// Calculates the exponential function of a PreciseDecimal + fn exp(&self) -> Option { + // based on https://github.com/rust-lang/libm/blob/master/src/math/exp.rs + if self.is_zero() { + return Some(PreciseDecimal::ONE); + } + if self < &pdec!(-82) { + return Some(PreciseDecimal::ZERO); + } + if self > &pdec!(93) { + return None; + } + + // (1) Argument Reduction + let signed_half = if self.is_negative() { + HALF_NEGATIVE + } else { + HALF_POSITIVE + }; + // r = x - floor(x/ln(2) +- 0.5) * ln(2) + // https://www.wolframalpha.com/input?i=x+-+floor%28x%2Fln%282%29+%2B+0.5%29+*+ln%282%29 + let k = INVLN2 * *self + signed_half; + let k: i32 = (k.0 / PreciseDecimal::ONE.0).to_i32().unwrap(); + let r = *self - LN2 * k; + + // (2) Approximation of exp(r) + let rr = r * r; + let c = r - rr * (P1 + rr * (P2 + rr * (P3 + rr * (P4 + rr * P5)))); + let exp_r = PreciseDecimal::ONE + r + (r * c) / (dec!(2) - c); + + // (3) Scale back + let two_pow_k = if self.is_negative() { + PreciseDecimal(PreciseDecimal::ONE.0 >> k.abs() as u32) + } else { + PreciseDecimal(PreciseDecimal::ONE.0 << k as u32) // k <= 130 + }; + Some(two_pow_k * exp_r) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn test_constants() { + assert_eq!(LN2, pdec!("0.693147180559945309417232121458176568")); + assert_eq!(HALF_POSITIVE, pdec!("0.5")); + assert_eq!(HALF_NEGATIVE, pdec!("-0.5")); + assert_eq!(INVLN2, pdec!("1.442695040888963407359924681001892137")); + assert_eq!(P1, pdec!("0.166666666666666019037")); + assert_eq!(P2, pdec!("-0.00277777777770155933842")); + assert_eq!(P3, pdec!("0.0000661375632143793436117")); + assert_eq!(P4, pdec!("-0.00000165339022054652515390")); + assert_eq!(P5, pdec!("0.0000000413813679705723846039")); + } + + #[test] + fn test_exponent_positive() { + assert_eq!(dec!("0.1").exp(), Some(dec!("1.105170918075647624"))); + assert_eq!( + pdec!("0.1").exp(), + Some( + pdec!("1.105170918075647624811707826490246668") + + pdec!("0.000000000000000000073249221022502114") + ) + ); + assert_eq!( + dec!(1).exp(), + Some(dec!("2.718281828459045235") - dec!("0.000000000000000001")) + ); + assert_eq!( + pdec!(1).exp(), + Some( + pdec!("2.718281828459045235360287471352662497") + - pdec!("0.000000000000000000506600695098127761") + ) + ); + assert_eq!( + dec!(2).exp(), + Some(dec!("7.389056098930650227") - dec!("0.000000000000000001")) + ); + assert_eq!( + pdec!(2).exp(), + Some( + pdec!("7.389056098930650227230427460575007813") + - pdec!("0.000000000000000000502826567049772189") + ) + ); + assert_eq!( + dec!(5).exp(), + Some(dec!("148.413159102576603421") - dec!("0.000000000000000013")) + ); + assert_eq!( + pdec!(5).exp(), + Some( + pdec!("148.413159102576603421115580040552279623") + - pdec!("0.000000000000000012819743652169222343") + ) + ); + assert_eq!( + dec!(10).exp(), + Some( + dec!("22026.465794806716516957") - dec!("0.000000000000004654") + ) + ); + assert_eq!( + pdec!(10).exp(), + Some( + pdec!("22026.465794806716516957900645284244366353") + - pdec!("0.000000000000004654463413405594362897") + ) + ); + } + + #[test] + fn test_exponent_negative() { + assert_eq!(dec!("-0.1").exp(), Some(dec!("0.904837418035959573"))); + assert_eq!( + pdec!("-0.1").exp(), + Some( + pdec!("0.904837418035959573164249059446436621") + - pdec!("0.000000000000000000059971389890128697") + ) + ); + assert_eq!(dec!(-1).exp(), Some(dec!("0.367879441171442321"))); + assert_eq!( + pdec!(-1).exp(), + Some( + pdec!("0.367879441171442321595523770161460867") + + pdec!("0.000000000000000000068560948558969987") + ) + ); + assert_eq!(dec!(-2).exp(), Some(dec!("0.135335283236612691"))); + assert_eq!( + pdec!(-2).exp(), + Some( + pdec!("0.135335283236612691893999494972484403") + + pdec!("0.000000000000000000009209589825745512") + ) + ); + assert_eq!(dec!(-5).exp(), Some(dec!("0.006737946999085467"))); + assert_eq!( + pdec!(-5).exp(), + Some( + pdec!("0.006737946999085467096636048423148424") + + pdec!("0.000000000000000000000582015461381543") + ) + ); + assert_eq!(dec!(-10).exp(), Some(dec!("0.000045399929762484"))); + assert_eq!( + pdec!(-10).exp(), + Some( + pdec!("0.000045399929762484851535591515560550") + + pdec!("0.000000000000000000000009593564125049") + ) + ); + } + + #[test] + fn test_exponent_zero() { + assert_eq!(dec!(0).exp(), Some(dec!(1))); + assert_eq!(pdec!(0).exp(), Some(pdec!(1))); + } + + #[test] + fn test_exponent_large_value() { + assert_eq!( + dec!(80).exp(), + Some( + dec!("55406223843935100525711733958316612.924856728832685322") + - dec!("8411471907589238.909955041056771071") + ) + ); + assert_eq!( + pdec!(80).exp(), + Some( + pdec!("55406223843935100525711733958316612.924856728832685322870300188282045700") + - pdec!("8411471907589238.909955041056771071656863326999790852") + ) + ); + } + + #[test] + fn test_exponent_small_value() { + assert_eq!(dec!(-30).exp(), Some(dec!("0.000000000000093576"))); + assert_eq!( + pdec!(-60).exp(), + Some( + pdec!("0.000000000000000000000000008756510762") + - pdec!("0.000000000000000000000000000000000001") + ) + ); + } + + #[test] + fn test_exponent_smallest_value() { + assert_eq!(dec!(-41).exp(), Some(dec!("0.000000000000000001"))); + assert_eq!( + pdec!(-82).exp(), + Some(pdec!("0.000000000000000000000000000000000002")) + ); + } + + #[test] + fn test_exponent_largest_value() { + assert_eq!( + dec!(90).exp(), + Some( + dec!("1220403294317840802002710035136369753970.746421099767546244") + - dec!("62783923595896661921.607585533121275855") + ) + ); + assert_eq!( + pdec!(93).exp(), + Some( + pdec!("24512455429200857855527729431109153423487.564149646906095458338836041506325882") + + pdec!("673513250279373616826.005878421400866518707554460260006534") + ) + ); + } + + #[test] + fn test_exponent_value_too_small() { + assert_eq!(dec!(-42).exp(), Some(dec!(0))); + assert_eq!(pdec!(-83).exp(), Some(pdec!(0))); + } + + #[test] + fn test_exponent_value_too_large() { + assert_eq!(dec!(91).exp(), None); + assert_eq!(pdec!(94).exp(), None); + } + + #[test] + fn test_exponent_negative_min() { + assert_eq!(Decimal::MIN.exp(), Some(dec!(0))); + assert_eq!(PreciseDecimal::MIN.exp(), Some(pdec!(0))); + } + + #[test] + fn test_exponent_positive_max() { + assert_eq!(Decimal::MAX.exp(), None); + assert_eq!(PreciseDecimal::MAX.exp(), None); + } +} diff --git a/libraries/scrypto-math/src/lib.rs b/libraries/scrypto-math/src/lib.rs new file mode 100644 index 00000000..1894b5d8 --- /dev/null +++ b/libraries/scrypto-math/src/lib.rs @@ -0,0 +1,7 @@ +pub mod exponential; +pub mod logarithm; +pub mod power; + +pub use exponential::*; +pub use logarithm::*; +pub use power::*; diff --git a/libraries/scrypto-math/src/logarithm.rs b/libraries/scrypto-math/src/logarithm.rs new file mode 100644 index 00000000..c5f4800b --- /dev/null +++ b/libraries/scrypto-math/src/logarithm.rs @@ -0,0 +1,449 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that x = 2^k * (1+f), where + * sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). Let s = f/(2+f) ; based on log(1+f) = + * log(1+s) - log(1-s) = 2s + 2/3 s**3 + 2/5 s**5 + ....., = 2s + s*R We + * use a special Remez algorithm on [0,0.1716] to generate a polynomial + * of degree 14 to approximate R The maximum error of this polynomial + * approximation is bounded by 2**-58.45. In other words, 2 4 + * 6 8 10 12 14 R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s + * +Lg5*s +Lg6*s +Lg7*s (the values of Lg1 to Lg7 are listed in the + * program) and | 2 14 | -58.45 | Lg1*s + * +...+Lg7*s - R(z) | <= 2 | | Note + * that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. In order + * to guarantee error in log below 1ulp, we compute log by log(1+f) = f + * - s*(f - R) (if f is not too large) log(1+f) = f - (hfsq - + * s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). = + * k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) Here ln2 is split into two + * floating point number: ln2_hi + ln2_lo, where n*ln2_hi is always + * exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc: + * hi and lo separation is not needed for Decimal and PreciseDecimal in + * Scrypto due to exact integer calculation. + */ + +use num_traits::Zero; +use radix_engine_common::math::{Decimal, PreciseDecimal}; +use radix_engine_interface::pdec; + +const LN2: PreciseDecimal = pdec!("0.693147180559945309417232121458176568"); +const LN10: PreciseDecimal = pdec!("2.302585092994045684017991454684364207"); +const SQRT: PreciseDecimal = pdec!("1.414213562373095048801688724209698078"); +const SQRT_HALF: PreciseDecimal = + pdec!("0.707106781186547524400844362104849039"); +const LG1: PreciseDecimal = pdec!("0.6666666666666735130"); // 6.666666666666735130e-01 +const LG2: PreciseDecimal = pdec!("0.3999999999940941908"); // 3.999999999940941908e-01 +const LG3: PreciseDecimal = pdec!("0.2857142874366239149"); // 2.857142874366239149e-01 +const LG4: PreciseDecimal = pdec!("0.2222219843214978396"); // 2.222219843214978396e-01 +const LG5: PreciseDecimal = pdec!("0.1818357216161805012"); // 1.818357216161805012e-01 +const LG6: PreciseDecimal = pdec!("0.1531383769920937332"); // 1.531383769920937332e-01 +const LG7: PreciseDecimal = pdec!("0.1479819860511658591"); // 1.479819860511658591e-01 + +pub trait LogarithmDecimal { + fn ln(&self) -> Option; + fn log2(&self) -> Option; + fn log10(&self) -> Option; + fn log_base(&self, base: Decimal) -> Option; +} + +pub trait LogarithmPreciseDecimal { + fn ln(&self) -> Option; + fn log2(&self) -> Option; + fn log10(&self) -> Option; + fn log_base(&self, base: PreciseDecimal) -> Option; +} + +/// Reduces the argument x by finding k and f such that +/// x = 2^k * (1+f) where sqrt(2)/2 < 1+f < sqrt(2) +fn log_reduce_argument(number: PreciseDecimal) -> (i32, PreciseDecimal) { + let full_integer = number.0 / PreciseDecimal::ONE.0; + + if full_integer.is_zero() { + if number >= SQRT_HALF { + return (0, number); + } + + // uses leading zeros of the full big integer to derive k + let k = number.0.leading_zeros() as i32 + - SQRT_HALF.0.leading_zeros() as i32; + let r = number * PreciseDecimal(PreciseDecimal::ONE.0 << k as u32); + + if r >= SQRT_HALF { + return (-k, r); + } + + // r can be smaller than SQRT_HALF but still having the same amount of + // leading zeros + return (-k - 1, r * pdec!(2)); + } + + // uses leading zeros of the full big integer to derive k + // 255 bits only because the first bit is the sign bit + let k = 255 - full_integer.leading_zeros() as i32; // index highest integer bit + let r = number / PreciseDecimal(PreciseDecimal::ONE.0 << k as u32); + + if r <= SQRT { + return (k, r); + } + + // r can be larger than SQRT but still having the same amount of leading + // zeros + return (k + 1, r / pdec!(2)); +} + +impl LogarithmDecimal for Decimal { + /// Calculates the natural logarithm of a Decimal + /// Using the natural logarithm of PreciseDecimal internally + fn ln(&self) -> Option { + PreciseDecimal::try_from(*self) + .ok()? + .ln() + .and_then(|log| log.try_into().ok()) + } + + /// Calculates the logarithm to base 2 of a Decimal + /// Using the logarithm to base 2 of PreciseDecimal internally + fn log2(&self) -> Option { + PreciseDecimal::try_from(*self) + .ok()? + .log2() + .and_then(|log| log.try_into().ok()) + } + + /// Calculates the logarithm to base 10 of a Decimal + /// Using the logarithm to base 10 of PreciseDecimal internally + fn log10(&self) -> Option { + PreciseDecimal::try_from(*self) + .ok()? + .log10() + .and_then(|log| log.try_into().ok()) + } + + /// Calculates the logarithm to an arbitrary base of a Decimal + /// Using the logarithm to an abitrary base of PreciseDecimal internally + fn log_base(&self, base: Decimal) -> Option { + let base = PreciseDecimal::try_from(base).ok()?; + PreciseDecimal::try_from(*self) + .ok()? + .log_base(base) + .and_then(|log| log.try_into().ok()) + } +} + +impl LogarithmPreciseDecimal for PreciseDecimal { + /// Calculates the natural logarithm of a PreciseDecimal + fn ln(&self) -> Option { + // based on https://github.com/rust-lang/libm/blob/master/src/math/log.rs + if !self.is_positive() { + return None; + } + + // (1) Argument Reduction + let (k, r) = log_reduce_argument(*self); + // println!("k = {:?}, r = {:?}", k, r); + // println!("x_n = {:?}", pdec!(2).checked_powi(k.into())? * r); + // println!("x_o = {:?}", self); + + // (2) Approximation of log(1+f) + let f = r - PreciseDecimal::ONE; + let s = f / (pdec!(2) + f); + let z = s * s; + let w = z * z; + let remez = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))) + + w * (LG2 + w * (LG4 + w * LG6)); + let log_1_f = f - s * (f - remez); + + // (3) log(x) = k*ln2 + log(1+f) + Some(LN2 * k + log_1_f) + } + + /// Calculates the logarithm to base 2 of a PreciseDecimal + fn log2(&self) -> Option { + Some(self.ln()? / LN2) + } + + /// Calculates the logarithm to base 10 of a PreciseDecimal + fn log10(&self) -> Option { + Some(self.ln()? / LN10) + } + + /// Calculates the logarithm to an arbitrary base of a PreciseDecimal + fn log_base(&self, base: PreciseDecimal) -> Option { + let base_ln = base.ln()?; + Some(self.ln()? / base_ln) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use radix_engine_interface::dec; + + #[test] + fn test_constants() { + assert_eq!(LN2, pdec!("0.693147180559945309417232121458176568")); + assert_eq!(LN10, pdec!("2.302585092994045684017991454684364207")); + assert_eq!(SQRT, pdec!("1.414213562373095048801688724209698078")); + assert_eq!(SQRT_HALF, pdec!("0.707106781186547524400844362104849039")); + assert_eq!(LG1, pdec!("0.6666666666666735130")); + assert_eq!(LG2, pdec!("0.3999999999940941908")); + assert_eq!(LG3, pdec!("0.2857142874366239149")); + assert_eq!(LG4, pdec!("0.2222219843214978396")); + assert_eq!(LG5, pdec!("0.1818357216161805012")); + assert_eq!(LG6, pdec!("0.1531383769920937332")); + assert_eq!(LG7, pdec!("0.1479819860511658591")); + } + + #[test] + fn test_ln_positive_number() { + assert_eq!( + dec!(10).ln(), + Some(dec!("2.302585092994045684") - dec!("0.000000000000000001")) + ); + assert_eq!( + pdec!(10).ln(), + Some( + pdec!("2.302585092994045684017991454684364207") + - pdec!("0.000000000000000000093151926716540583") + ) + ); + } + + #[test] + fn test_ln_e() { + assert_eq!( + dec!("2.718281828459045235").ln(), + Some(dec!(1) - dec!("0.000000000000000001")) + ); + assert_eq!( + pdec!("2.718281828459045235360287471352662497").ln(), + Some(pdec!(1) - pdec!("0.000000000000000000072256402139088204")) + ); + } + + #[test] + fn test_ln_one() { + assert_eq!(dec!(1).ln(), Some(dec!(0))); + assert_eq!(pdec!(1).ln(), Some(pdec!(0))); + } + + #[test] + fn test_ln_zero() { + assert_eq!(dec!(0).ln(), None); + assert_eq!(pdec!(0).ln(), None); + } + + #[test] + fn test_ln_negative_number() { + assert_eq!(dec!(-1).ln(), None); + assert_eq!(pdec!(-1).ln(), None); + } + + #[test] + fn test_ln_lesser_sqrt_half() { + assert_eq!( + (SQRT_HALF - pdec!("0.000000000000000000000000000000000001")).ln(), + Some( + pdec!("-0.346573590279972654708616060729088286") + - pdec!("0.000000000000000000349708283169683682") + ) + ); // * 2 + assert_eq!( + dec!("0.664613997892457936").ln(), + Some(dec!("-0.408548861152152805") + dec!("0.000000000000000001")) + ); // * 2; equal leading zeros of sqrt_half and number (~ 2 ** 119 = + // 1000...) + assert_eq!(dec!("0.5").ln(), Some(dec!("-0.693147180559945309"))); // * 2 + assert_eq!(dec!("0.25").ln(), Some(dec!("-1.386294361119890618"))); // * 2^2 + assert_eq!(dec!("0.125").ln(), Some(dec!("-2.079441541679835928"))); // * 2^3 + } + + #[test] + fn test_ln_equal_sqrt_half() { + assert_eq!( + SQRT_HALF.ln(), + Some( + pdec!("-0.346573590279972654708616060729088284") + + pdec!("0.000000000000000000349708283169683683") + ) + ); + } + + #[test] + fn test_ln_between_sqrt_half_and_sqrt() { + assert_eq!( + (SQRT_HALF + pdec!("0.000000000000000000000000000000000001")).ln(), + Some( + pdec!("-0.346573590279972654708616060729088284") + + pdec!("0.000000000000000000349708283169683685") + ) + ); + assert_eq!(dec!("0.8").ln(), Some(dec!("-0.223143551314209755"))); + assert_eq!( + dec!("1.329227995784915872").ln(), + Some(dec!("0.284598319407792504") + dec!("0.000000000000000001")) + ); // equal leading zeros of sqrt_half and number (~ 2 ** 120 - 1 = + // 1111...) + assert_eq!( + dec!("1.329227995784915873").ln(), + Some(dec!("0.284598319407792505")) + ); // equal leading zeros of sqrt and number (~ 2 ** 120 = 1000...) + assert_eq!(dec!("1.2").ln(), Some(dec!("0.182321556793954626"))); + assert_eq!( + (SQRT - pdec!("0.000000000000000000000000000000000001")).ln(), + Some( + pdec!("0.346573590279972654708616060729088282") + - pdec!("0.000000000000000000349708283169683681") + ) + ); + } + + #[test] + fn test_ln_equal_sqrt() { + assert_eq!( + SQRT.ln(), + Some( + pdec!("0.346573590279972654708616060729088284") + - pdec!("0.000000000000000000349708283169683683") + ) + ); + } + + #[test] + fn test_ln_greater_sqrt() { + assert_eq!( + (SQRT + pdec!("0.000000000000000000000000000000000001")).ln(), + Some( + pdec!("0.346573590279972654708616060729088284") + + pdec!("0.000000000000000000349708283169683683") + ) + ); // * 2 + assert_eq!( + dec!("2.658455991569831745").ln(), + Some(dec!("0.977745499967737814")) + ); // equal leading zeros for sqrt and number (~ 2**121 - 1 = 1111...) + assert_eq!(dec!("2").ln(), Some(dec!("0.693147180559945309"))); // / 2 + assert_eq!(dec!("4").ln(), Some(dec!("1.386294361119890618"))); // / 2^2 + assert_eq!(dec!("8").ln(), Some(dec!("2.079441541679835928"))); // / 2^3 + } + + #[test] + fn test_ln_decimal_precision() { + assert_eq!( + dec!("1000000000000000000000000000000").ln(), + Some(dec!("69.077552789821370520")) + ); + assert_eq!( + pdec!("1000000000000000000000000000000").ln(), + Some( + pdec!("69.077552789821370520539743640530926228") + + pdec!("0.000000000000000000274111421367606147") + ) + ); + } + + #[test] + fn test_ln_smallest_positive() { + assert_eq!( + dec!("0.000000000000000001").ln(), + Some(dec!("-41.446531673892822312")) + ); + assert_eq!( + pdec!("0.000000000000000000000000000000000001").ln(), + Some( + pdec!("-82.893063347785644624647692368637111474") + + pdec!("0.000000000000000000345534790097727621") + ) + ); + } + + #[test] + fn test_ln_maximum_possible() { + assert_eq!(Decimal::MAX.ln(), Some(dec!("90.944579813056731786"))); + assert_eq!( + PreciseDecimal::MAX.ln(), + Some( + pdec!("93.859467695000409276746498603197913385") + + pdec!("0.000000000000000000345534790097727602") + ) + ); + } + + #[test] + fn test_log_2() { + assert_eq!(dec!(-1).log2(), None); + assert_eq!(dec!(0).log2(), None); + assert_eq!(dec!(1).log2(), Some(dec!(0))); + assert_eq!( + dec!("1.5").log2(), + Some(dec!("0.584962500721156181") - dec!("0.000000000000000001")) + ); + assert_eq!(dec!(2).log2(), Some(dec!(1))); + assert_eq!(dec!(10).log2(), Some(dec!("3.321928094887362347"))); + } + + #[test] + fn test_log_10() { + assert_eq!(dec!(-1).log10(), None); + assert_eq!(dec!(0).log10(), None); + assert_eq!(dec!(1).log10(), Some(dec!(0))); + assert_eq!(dec!(5).log10(), Some(dec!("0.698970004336018804"))); + assert_eq!( + dec!(10).log10(), + Some(dec!(1) - dec!("0.000000000000000001")) + ); + assert_eq!(dec!(20).log10(), Some(dec!("1.301029995663981195"))); + } + + #[test] + fn test_log_base() { + assert_eq!(dec!(-1).log_base(dec!(8)), None); + assert_eq!(dec!(0).log_base(dec!(8)), None); + assert_eq!(dec!(1).log_base(dec!(8)), Some(dec!(0))); + assert_eq!( + dec!(5).log_base(dec!(8)), + Some(dec!("0.773976031629120782")) + ); + assert_eq!(dec!(8).log_base(dec!(8)), Some(dec!(1))); + assert_eq!( + dec!(10).log_base(dec!(8)), + Some(dec!("1.107309364962454115")) + ); + assert_eq!( + dec!(20).log_base(dec!(8)), + Some(dec!("1.440642698295787449")) + ); + assert_eq!( + Decimal::MAX.log_base(dec!(8)), + Some(dec!("43.735098097342492579")) + ); + } +} diff --git a/libraries/scrypto-math/src/power.rs b/libraries/scrypto-math/src/power.rs new file mode 100644 index 00000000..cec60a4b --- /dev/null +++ b/libraries/scrypto-math/src/power.rs @@ -0,0 +1,266 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// (does not apply - due to integer math) log2(x) = w1 + w2, where w1 +// has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// (does not apply - due to integer math) arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// (x**y = exp(ln(x) * y)) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// (does not apply - no NAN) +// 4. NAN ** (anything except 0) is NAN +// (does not apply - no NAN) +// 5. +-(|x| > 1) ** +INF is +INF +// (does not apply - no INF) +// 6. +-(|x| > 1) ** -INF is +0 +// (does not apply - no INF) +// 7. +-(|x| < 1) ** +INF is +0 +// (does not apply - no INF) +// 8. +-(|x| < 1) ** -INF is +INF +// (does not apply - no INF) +// 9. -1 ** +-INF is 1 +// (does not apply - no INF) +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// (does not apply - only positive zero) +// 12. +0 ** (-anything except 0, NAN) is +INF, raise +// divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise +// divbyzero (does not apply - only positive zero) +// 14. -0 ** (+odd integer) is -0 +// (does not apply - only positive zero) +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// (does not apply - only positive zero) +// 16. +INF ** (+anything except 0,NAN) is +INF +// (does not apply - no INF) +// 17. +INF ** (-anything except 0,NAN) is +0 +// (does not apply - no INF) +// 18. -INF ** (+odd integer) is -INF +// (does not apply - no INF) +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd +// integer) (does not apply - no INF) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// + +use crate::exponential::ExponentialPreciseDecimal; +use crate::logarithm::LogarithmPreciseDecimal; +use num_traits::ToPrimitive; +use radix_engine_common::math::{CheckedMul, Decimal, PreciseDecimal}; +use radix_engine_interface::pdec; + +pub trait PowerDecimal { + fn pow(&self, exp: Decimal) -> Option; +} + +pub trait PowerPreciseDecimal { + fn pow(&self, exp: PreciseDecimal) -> Option; +} + +impl PowerDecimal for Decimal { + /// Calculates the power of a Decimal + /// Using the natural logarithm of PreciseDecimal internally + fn pow(&self, exp: Decimal) -> Option { + let exp = PreciseDecimal::try_from(exp).ok()?; + PreciseDecimal::try_from(*self) + .ok()? + .pow(exp) + .and_then(|e| e.try_into().ok()) + } +} + +impl PowerPreciseDecimal for PreciseDecimal { + /// Calculates the power of a PreciseDecimal + fn pow(&self, exp: PreciseDecimal) -> Option { + // based on https://github.com/rust-lang/libm/blob/master/src/math/pow.rs + if exp == PreciseDecimal::ZERO { + // special case (1) + return Some(PreciseDecimal::ONE); + } + if *self == PreciseDecimal::ONE { + // special case (2) + return Some(PreciseDecimal::ONE); + } + if *self == PreciseDecimal::ZERO && exp.is_positive() { + // special case (10) + return Some(PreciseDecimal::ZERO); + } + if *self == PreciseDecimal::ZERO && exp.is_negative() { + // special case (12) + return None; + } + if exp == PreciseDecimal::ONE { + // special case (20) + return Some(self.clone()); + } + if exp == pdec!(-1) { + // special case (21) + return Some(PreciseDecimal::ONE / *self); + } + + if self.is_negative() { + let exp_is_integer = PreciseDecimal( + exp.0 / PreciseDecimal::ONE.0 * PreciseDecimal::ONE.0, + ) == exp; + if !exp_is_integer { + // special case (23) + return None; + } + // special case (22) + let is_even = (exp.0 / PreciseDecimal::ONE.0).to_i32()? % 2 == 0; + let pow = (self.checked_abs()?.ln()? * exp).exp(); + if is_even { + return pow; + } + return Some(pdec!(-1) * pow?); + } + + Some((self.ln()?.checked_mul(exp))?.exp()?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use radix_engine_interface::dec; + + #[test] + fn test_pow_exp_zero() { + assert_eq!(dec!(-2).pow(dec!(0)), Some(dec!(1))); + assert_eq!(dec!(-1).pow(dec!(0)), Some(dec!(1))); + assert_eq!(dec!(0).pow(dec!(0)), Some(dec!(1))); + assert_eq!(dec!(1).pow(dec!(0)), Some(dec!(1))); + assert_eq!(dec!(2).pow(dec!(0)), Some(dec!(1))); + } + + #[test] + fn test_pow_base_one() { + assert_eq!(dec!(1).pow(dec!(2)), Some(dec!(1))); + assert_eq!(dec!(1).pow(dec!(-2)), Some(dec!(1))); + } + + #[test] + fn test_pow_base_zero() { + assert_eq!(dec!(0).pow(dec!(-2)), None); + assert_eq!(dec!(0).pow(dec!(-1)), None); + assert_eq!(dec!(0).pow(dec!(0)), Some(dec!(1))); + assert_eq!(dec!(0).pow(dec!(1)), Some(dec!(0))); + assert_eq!(dec!(0).pow(dec!(2)), Some(dec!(0))); + } + + #[test] + fn test_pow_exp_one() { + assert_eq!(dec!(2).pow(dec!(1)), Some(dec!(2))); + assert_eq!(dec!(-2).pow(dec!(1)), Some(dec!(-2))); + } + + #[test] + fn test_pow_exp_minus_one() { + assert_eq!(dec!(2).pow(dec!(-1)), Some(dec!("0.5"))); + assert_eq!(dec!(-2).pow(dec!(-1)), Some(dec!("-0.5"))); + } + + #[test] + fn test_pow_base_negative_exp_integer() { + assert_eq!(dec!(2).pow(dec!(-2)), Some(dec!("0.25"))); + assert_eq!(dec!(-2).pow(dec!(2)), Some(dec!("4"))); + assert_eq!(dec!(-2).pow(dec!(-2)), Some(dec!("0.25"))); + assert_eq!(dec!(5).pow(dec!(-5)), Some(dec!("0.00032"))); + assert_eq!( + dec!(-5).pow(dec!(5)), + Some(dec!("-3125") + dec!("0.000000000000001660")) + ); + assert_eq!(dec!(-5).pow(dec!(-5)), Some(dec!("-0.00032"))); + } + + #[test] + fn test_pow_base_negative_exp_non_integer() { + assert_eq!(dec!("-1.1").pow(dec!("0.00000000000000001")), None); + assert_eq!(dec!("-3.4").pow(dec!("15.43")), None); + assert_eq!(dec!("-3.4").pow(dec!("-15.43")), None); + } + + #[test] + fn test_pow_base_maximum_exp_non_integer() { + assert_eq!(dec!("-1.1").pow(dec!("0.00000000000000001")), None); + assert_eq!(dec!("-3.4").pow(dec!("15.43")), None); + assert_eq!(dec!("-3.4").pow(dec!("-15.43")), None); + } + + #[test] + fn test_pow_smallest_value() { + assert_eq!( + dec!("3.4").pow(dec!("-33.43")), + Some(dec!("0.000000000000000001")) + ); + } + + #[test] + fn test_pow_largest_value() { + assert_eq!( + dec!("3.4").pow(dec!("71.43")), + Some( + dec!( + "91947313437872693600354888137039353441.244419982586019069" + ) - dec!("187832408272640032348.012171022248677284") + ) + ); + } + + #[test] + fn test_pow_base_minimum() { + assert_eq!(Decimal::MIN.pow(dec!(3)), None); + assert_eq!(Decimal::MIN.pow(Decimal::MIN), None); + assert_eq!(Decimal::MIN.pow(Decimal::MAX), None); + } + + #[test] + fn test_pow_base_maximum() { + assert_eq!(Decimal::MAX.pow(dec!(3)), None); + assert_eq!(Decimal::MAX.pow(Decimal::MIN), None); + assert_eq!(Decimal::MAX.pow(Decimal::MAX), None); + } + + #[test] + fn test_pow_base_positive_normal() { + assert_eq!(dec!(2).pow(dec!(2)), Some(dec!(4))); + assert_eq!( + dec!("3.4").pow(dec!("15.43")), + Some( + dec!("158752177.142935864260984228") + - dec!("0.000000000094162353") + ) + ); + assert_eq!( + dec!("3.4").pow(dec!("-15.43")), + Some(dec!("0.000000006299126210")) + ); + } +} diff --git a/packages/caviarnine-v1-adapter-v1/Cargo.toml b/packages/caviarnine-v1-adapter-v1/Cargo.toml new file mode 100644 index 00000000..c3d91c97 --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "caviarnine-v1-adapter-v1" +version.workspace = true +edition.workspace = true +description = "Defines the adapter for Caviarnine" + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +radix-engine-interface = { workspace = true } +transaction = { workspace = true, optional = true } + +scrypto-interface = { path = "../../libraries/scrypto-interface" } +scrypto-math = { path = "../../libraries/scrypto-math" } +ports-interface = { path = "../../libraries/ports-interface" } +common = { path = "../../libraries/common" } + +[features] +default = [] +test = [] + +manifest-builder-stubs = ["dep:transaction"] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/packages/caviarnine-v1-adapter-v1/README.md b/packages/caviarnine-v1-adapter-v1/README.md new file mode 100644 index 00000000..78a63723 --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/README.md @@ -0,0 +1,94 @@ +# Caviarnine Adapter + +## Calculation of Fees + +This section of the document describes how the adapter estimates how much fees have been earned on a liquidity position for the period that it's been opened. There is some amount of knowledge of Caviarnine required to fully understand this calculation which is also described in this section as we go. + +First, I will describe some of the basics of Caviarnine that we will build the model on. Caviarnine allows users to concentrate their liquidity in a Uniswap V3 style where users can add liquidity to different bins. A bin is a discrete range in the price range between 0 and infinity. Adding liquidity to a specific bin means that the user's liquidity is only active when the price is inside that bin's range. Once the price exits that of the bin that the user has their assets in then the user stops earning fees. Of course, the user is allowed to add liquidity to multiple different bins so that their liquidity is active in a wider price range. + +

+ +

+ +The above diagram depicts the liquidity in some pool that is made up of assets X and Y and the various bins that exist in this pool. The x-axis of the diagram is the bin number. The distance between each bin and the other is called the bin span. In this diagram, the bin span is 10 which we can calculate by subtracting the second bin from the first (27010 - 27000). The bin span is the same throughout the pool and could change for different pools. + +The spot price can be calculated from the bin number by using the following equation: + +$$ +\mathrm{Spot \space Price}(\mathrm{Bin}) = 1.0005 ^ {2\mathrm{Bin} - 54000} +$$ + +The first bin in the diagram above is 27000 and the last bin starts at 27060 and ends at 27070. With the equation above this means that the diagram has a price range of: + +$$ +\mathrm{Spot \space Price}(27000) = 1.0005 ^ {54000 - 54000} = 1.0005 ^ 0 = 1 +$$ + +$$ +\mathrm{Spot \space Price}(27070) = 1.0005 ^ {54140 - 54000} = 1.0005 ^ {140} = 1.07248941878 +$$ + +The y-axis in the diagram represents the amount of liquidity in each of the bins. To simplify things, this diagram assumes that each of the bins contains an equal amount of liquidity, which is of course not realistic but simplifies things. + +The bin where the current price of the asset lies is called the _active bin_. Not all bins hold both the X and Y assets: + +* The currently active bin is the only bin that holds both X and Y assets. +* All bins above the active bin hold X assets +* All bins below the active bin hold Y assets + +This is seen in the diagram with the two different colors used for the bins and the active bin (the middle one) being split in half containing both of the colors. + +> This bit is not too relevant to the calculation of fees or anything, but is relevant for the overall understanding of the reader on the Caviarnine system. As you've read above, some of the bins only contain one of the assets and not both. Therefore, unlike Uniswap V2 where the users are obligated to provide two assets of equal value to the pool, the users in this case are not obligated to do that and is free to provide a single side of the liquidity or provide both as they see fit. + +As such, if a user wishes to contribute liquidity to three bins: the currently active bin, one to the left, and one to the right, then they would contribute X and Y assets to the currently active bin, Y assets only to the lower bin and X assets only to the higher bin. The Caviarnine pool will accept the contribution to the higher and lower bins in full and will only accept contributions to the active bin according to the ratio of assets. This means that there can never be change for contributions to non-active bins but there can be change for contributions to the active bin. + +Say that the price has increased from being in bin 27030 as seen in the current diagram to being in 27050 bin, the diagram for that can be seen below: + +

+ +

+ +The previous active bin, 27030, is no longer made up of both assets; since the price has increased, it is now a lower bin than the current active bin and now contains only the Y asset according to the rules described in this document. Similarly, as 27050 has become the new active bin it is now composed of a mixture of X and Y assets instead of just X. All of the higher bins saw no changes. All of the X assets that used to be in the bins 27030, 27040, and some of the ones in 27050 have been exchanged for Y assets. + +> Another important point to note, in Caviarnine we do not own a percentage of the pool. Rather, we own a percentage of the bins we've contributed to. + +With the above background information in mind, we can begin to come up with a model for estimating the fees. This will follow a similar model to what we've come up with for Ociswap the will involve calculating the amount we expect to get back based on price action alone. The fees are the difference between the amount we expect to get back based on price action alone and the amount of assets we actually get back when the liquidity position is closed. + +Therefore, in simple terms we can say that: + +$$ +x_{\mathrm{fees}} = x_{\mathrm{actual}} - x_{\mathrm{Price \space Action (calculated)}} +$$ + +$$ +y_{\mathrm{fees}} = y_{\mathrm{actual}} - y_{\mathrm{Price \space Action (calculated)}} +$$ + +On how to calculate the amount we expect to get back when closing a liquidity position due to price action alone, we do the following: + +* When the user opens a liquidity position we record all of the bins that we added liquidity to and the corresponding amount of liquidity added to them. +* When the user closes the liquidity position we calculate the amount of resources we expect to find in each bin based on the pool's current price the amount we expect to find follows the following logic, which is also summarized in the table below: + * If a bin contained only X resource when the position was first opened and the current price of the pool is below that bin then we expect to get back the same amount of X tokens we initially put in that bin. + * If a bin contained only Y resource when the position was first opened and the current price of the pool is above that bin then we expect to get back the same amount of Y tokens we initially put in that bin. + * If a bin contained only X resource when the position was first opened and the current price of the pool is above that bin then we expect that the full amount of X put in that bin was swapped for Y. + * If a bin contained only Y resource when the position was first opened and the current price of the pool is below that bin then we expect that the full amount of Y put in that bin was swapped for X. + * If a bin contained only X resource when the position was first opened and the current price of the pool is inside that bin then some amount of the X resources will be swapped for Y (How much?). + * If a bin contained only Y resource when the position was first opened and the current price of the pool is inside that bin then some amount of the Y resources will be swapped for X (How much?). + * If a bin contained a composite amount of X and Y resources when the position was first opened and the current price of the pool is above that bin then all of the X resources that were there will be swapped for Y resources. + * If a bin contained a composite amount of X and Y resources when the position was first opened and the current price of the pool is below that bin then all of the Y resources that were there will be swapped for X resources. + * If a bin contained a composite amount of X and Y resources when the position was first opened and the current price of the pool is inside that bin then some amount of X or Y resources will be converted into the other resource. + + +| Original Bin Composition | Current Bin Composition | Expected Amount | +| ---- | ---- | ---- | +| Entirely X | Entirely X | No Action - Should be same as original | +| Entirely X | Entirely Y | Full swap of amount X to amount Y | +| Entirely X | Composite of X and Y | Partial Swap of some X | +| Entirely Y | Entirely X | Full swap of amount Y to amount X | +| Entirely Y | Entirely Y | No Action - Should be same as original | +| Entirely Y | Composite of X and Y | Partial Swap of some Y | +| Composite of X and Y | Entirely X | Partial Swap of some Y | +| Composite of X and Y | Entirely Y | Partial Swap of some X | +| Composite of X and Y | Composite of X and Y | Partial Swap of some X or Y | + + diff --git a/packages/caviarnine-v1-adapter-v1/src/blueprint_interface.rs b/packages/caviarnine-v1-adapter-v1/src/blueprint_interface.rs new file mode 100644 index 00000000..b84a58d8 --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/src/blueprint_interface.rs @@ -0,0 +1,94 @@ +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + QuantaSwap as CaviarnineV1Pool impl [ + ScryptoStub, + ScryptoTestStub, + #[cfg(feature = "manifest-builder-stubs")] + ManifestBuilderStub + ] { + fn new( + owner_rule: AccessRule, + user_rule: AccessRule, + token_x_address: ResourceAddress, + token_y_address: ResourceAddress, + bin_span: u32, + #[manifest_type = "Option"] + reservation: Option, + ) -> Self; + fn get_fee_controller_address(&self) -> ComponentAddress; + fn get_fee_vaults_address(&self) -> ComponentAddress; + fn get_token_x_address(&self) -> ResourceAddress; + fn get_token_y_address(&self) -> ResourceAddress; + fn get_liquidity_receipt_address(&self) -> ResourceAddress; + fn get_bin_span(&self) -> u32; + fn get_amount_x(&self) -> Decimal; + fn get_amount_y(&self) -> Decimal; + fn get_active_tick(&self) -> Option; + fn get_price(&self) -> Option; + fn get_active_bin_price_range(&self) -> Option<(Decimal, Decimal)>; + fn get_active_amounts(&self) -> Option<(Decimal, Decimal)>; + fn get_bins_above( + &self, + start_tick: Option, + stop_tick: Option, + number: Option, + ) -> Vec<(u32, Decimal)>; + fn get_bins_below( + &self, + start_tick: Option, + stop_tick: Option, + number: Option, + ) -> Vec<(u32, Decimal)>; + fn get_liquidity_claims( + &self, + liquidity_receipt_id: NonFungibleLocalId, + ) -> IndexMap; + fn get_redemption_value(&self, liquidity_receipt_id: NonFungibleLocalId) -> (Decimal, Decimal); + fn get_redemption_bin_values( + &self, + liquidity_receipt_id: NonFungibleLocalId, + ) -> Vec<(u32, Decimal, Decimal)>; + fn mint_liquidity_receipt(&mut self) -> Bucket; + fn burn_liquidity_receipt( + &mut self, + #[manifest_type = "ManifestBucket"] + liquidity_receipt: Bucket + ); + fn add_liquidity_to_receipt( + &mut self, + #[manifest_type = "ManifestBucket"] + liquidity_receipt: Bucket, + #[manifest_type = "ManifestBucket"] + tokens_x: Bucket, + #[manifest_type = "ManifestBucket"] + tokens_y: Bucket, + positions: Vec<(u32, Decimal, Decimal)>, + ) -> (Bucket, Bucket, Bucket); + fn add_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + tokens_x: Bucket, + #[manifest_type = "ManifestBucket"] + tokens_y: Bucket, + positions: Vec<(u32, Decimal, Decimal)>, + ) -> (Bucket, Bucket, Bucket); + fn remove_specific_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + liquidity_receipt: Bucket, + claims: Vec<(u32, Decimal)>, + ) -> (Bucket, Bucket, Bucket); + fn remove_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + liquidity_receipt: Bucket + ) -> (Bucket, Bucket); + fn swap( + &mut self, + #[manifest_type = "ManifestBucket"] + tokens: Bucket + ) -> (Bucket, Bucket); + } +} diff --git a/packages/caviarnine-v1-adapter-v1/src/lib.rs b/packages/caviarnine-v1-adapter-v1/src/lib.rs new file mode 100644 index 00000000..1d8bb52b --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/src/lib.rs @@ -0,0 +1,905 @@ +#![allow(clippy::new_without_default)] + +mod blueprint_interface; +mod tick_math; +mod tick_selector; + +pub use crate::blueprint_interface::*; +pub use crate::tick_math::*; +pub use crate::tick_selector::*; + +use common::prelude::*; +use ports_interface::prelude::*; +use scrypto::prelude::*; +use scrypto_interface::*; + +use std::cmp::*; +use std::ops::*; + +macro_rules! define_error { + ( + $( + $name: ident => $item: expr; + )* + ) => { + $( + const $name: &'static str = concat!("[Caviarnine v1 Adapter v1]", " ", $item); + )* + }; +} + +define_error! { + RESOURCE_DOES_NOT_BELONG_ERROR + => "One or more of the resources do not belong to pool."; + NO_ACTIVE_AMOUNTS_ERROR => "Pool has no active amounts."; + NO_PRICE_ERROR => "Pool has no price."; + OVERFLOW_ERROR => "Overflow error."; +} + +macro_rules! pool { + ($address: expr) => { + $crate::blueprint_interface::CaviarnineV1PoolInterfaceScryptoStub::from( + $address, + ) + }; +} + +/// The total number of bins that we will be using on the left and the right +/// excluding the one in the middle. This number, in addition to the bin span +/// of the pool determines how much upside and downside we're covering. The +/// upside and downside we should cover is a business decision and its 20x up +/// and down. To calculate how much bins are needed (on each side) we can do +/// the following: +/// +/// ```math +/// bins_required = floor(log(value = multiplier, base = 1.0005) / (2 * bin_span)) +/// ``` +/// +/// In the case of a bin span of 50, the amount of bins we want to contribute to +/// on each side is 60 bins (60L and 60R). Therefore, the amount of bins to +/// contribute to is dependent on the bin span of the pool. However, in this +/// implementation we assume pools of a fixed bin span of 50 since we can't find +/// the number of bins required in Scrypto due to a missing implementation of a +/// function for computing the log. +pub const PREFERRED_TOTAL_NUMBER_OF_HIGHER_AND_LOWER_BINS: u32 = 30 * 2; + +#[blueprint_with_traits] +#[types(ComponentAddress, PoolInformation, Decimal, PreciseDecimal)] +pub mod adapter { + struct CaviarnineV1Adapter { + /// A cache of the information of the pool, this is done so that we do + /// not need to query the pool's information each time. Note: I would've + /// preferred to keep the adapter completely stateless but it seems like + /// we're pretty much forced to cache this data to get some fee gains. + pool_information_cache: + KeyValueStore, + } + + impl CaviarnineV1Adapter { + pub fn instantiate( + metadata_init: MetadataInit, + owner_role: OwnerRole, + address_reservation: Option, + ) -> Global { + let address_reservation = + address_reservation.unwrap_or_else(|| { + Runtime::allocate_component_address(BlueprintId { + package_address: Runtime::package_address(), + blueprint_name: Runtime::blueprint_name(), + }) + .0 + }); + + Self { + pool_information_cache: KeyValueStore::new_with_registered_type( + ), + } + .instantiate() + .prepare_to_globalize(owner_role) + .metadata(ModuleConfig { + init: metadata_init, + roles: Default::default(), + }) + .with_address(address_reservation) + .globalize() + } + + pub fn preload_pool_information( + &mut self, + pool_address: ComponentAddress, + ) -> PoolInformation { + let pool = pool!(pool_address); + let resource_address_x = pool.get_token_x_address(); + let resource_address_y = pool.get_token_y_address(); + let bin_span = pool.get_bin_span(); + + let pool_information = PoolInformation { + bin_span, + resources: ResourceIndexedData { + resource_x: resource_address_x, + resource_y: resource_address_y, + }, + }; + self.pool_information_cache + .insert(pool_address, pool_information); + pool_information + } + + pub fn liquidity_receipt_data( + // Does not depend on state, this is kept in case this is required + // in the future for whatever reason. + &mut self, + global_id: NonFungibleGlobalId, + ) -> LiquidityReceipt { + // Read the non-fungible data. + let LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } = ResourceManager::from_address(global_id.resource_address()) + .get_non_fungible_data::>( + global_id.local_id(), + ); + let adapter_specific_information = adapter_specific_information + .as_typed::() + .unwrap(); + + LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } + } + + // This function is here to optimize the adapter for fees. Previously, + // getting the price and the active tick were two separate invocations + // which proved to be rather costly. Therefore, since we typically need + // both pieces of data, this function makes an invocation for the price + // and then calculates the active tick from it. The relationship between + // the price and tick is: `p(t) = 1.0005 ^ (2*(t - 27000))`. + pub fn price_and_active_tick( + &mut self, + pool_address: ComponentAddress, + pool_information: Option, + ) -> Option<(Decimal, u32)> { + let pool = pool!(pool_address); + let PoolInformation { bin_span, .. } = pool_information + .unwrap_or_else(|| self.get_pool_information(pool_address)); + let price = pool.get_price()?; + // The following division and multiplication by the bin span rounds + // the calculated tick down to the nearest multiple of the bin span. + // This is because in Caviarnine valid ticks depend on the pool's + // bin span and there only exist valid ticks at multiples of the bin + // span. Alternatively, you can think of the following bit of code + // as active_tick = active_tick - active_tick % bin_span. + let active_tick = spot_to_tick(price) + .and_then(|value| value.checked_div(bin_span)) + .and_then(|value| value.checked_mul(bin_span))?; + Some((price, active_tick)) + } + + fn get_pool_information( + &mut self, + pool_address: ComponentAddress, + ) -> PoolInformation { + let entry = self.pool_information_cache.get(&pool_address); + if let Some(entry) = entry { + *entry + } else { + drop(entry); + self.preload_pool_information(pool_address) + } + } + } + + impl PoolAdapterInterfaceTrait for CaviarnineV1Adapter { + fn open_liquidity_position( + &mut self, + pool_address: ComponentAddress, + buckets: (Bucket, Bucket), + ) -> OpenLiquidityPositionOutput { + let mut pool = pool!(pool_address); + + // Split the two buckets into bucket_x and bucket_y in the same way + // that they're defined in the pool itself. + let pool_information @ PoolInformation { + bin_span, + resources: + ResourceIndexedData { + resource_x: resource_address_x, + resource_y: resource_address_y, + }, + } = self.get_pool_information(pool_address); + + let bucket_0_resource_address = buckets.0.resource_address(); + let bucket_1_resource_address = buckets.1.resource_address(); + + let (bucket_x, bucket_y) = if bucket_0_resource_address + == resource_address_x + && bucket_1_resource_address == resource_address_y + { + (buckets.0, buckets.1) + } else if bucket_1_resource_address == resource_address_x + && bucket_0_resource_address == resource_address_y + { + (buckets.1, buckets.0) + } else { + panic!("{}", RESOURCE_DOES_NOT_BELONG_ERROR) + }; + let amount_x = bucket_x.amount(); + let amount_y = bucket_y.amount(); + + // Select the bins that we will contribute to. + let (price, active_tick) = self + .price_and_active_tick(pool_address, Some(pool_information)) + .expect(NO_PRICE_ERROR); + + let SelectedTicks { + higher_ticks, + lower_ticks, + .. + } = SelectedTicks::select( + active_tick, + bin_span, + PREFERRED_TOTAL_NUMBER_OF_HIGHER_AND_LOWER_BINS, + ); + + // This comment was quickly going out of sync with the constant that + // is defined above of the number of bins to contribute to. Thus, to + // make this simple, let's say that the number of bins to contribute + // to is defined as `m` such that we're contributing to `m` bins to + // the left and `m` to the right. + // + // Determine the amount of resources that we will add to each of the + // bins. We have m on the left and m on the right. But, we also + // have the active bin that is composed of both x and y. So, this + // be like contributing to m.x and m.y bins where x = 1-y. X here + // is the percentage of resources x in the active bin. + let (amount_in_active_bin_x, amount_in_active_bin_y) = + pool.get_active_amounts().expect(NO_ACTIVE_AMOUNTS_ERROR); + + let percentage_in_active_bin_x = amount_in_active_bin_x + .checked_mul(price) + .and_then(|value| { + value.checked_div( + amount_in_active_bin_x + .checked_mul(price)? + .checked_add(amount_in_active_bin_y)?, + ) + }) + .expect(OVERFLOW_ERROR); + let percentage_in_active_bin_y = Decimal::one() + .checked_sub(percentage_in_active_bin_x) + .expect(OVERFLOW_ERROR); + + // In here, we decide the amount x by the number of higher bins plus + // the percentage of the x in the currently active bin since the + // pool starting from the current price and upward is + // entirely composed of X. Similarly, we divide amount_y + // by the number of lower positions plus the percentage + // of y in the active bin since the pool starting from + // the current price and downward is composed just of y. + let position_amount_x = Decimal::from(higher_ticks.len() as u32) + .checked_add(percentage_in_active_bin_x) + .and_then(|value| amount_x.checked_div(value)) + .expect(OVERFLOW_ERROR); + let position_amount_y = Decimal::from(lower_ticks.len() as u32) + .checked_add(percentage_in_active_bin_y) + .and_then(|value| amount_y.checked_div(value)) + .expect(OVERFLOW_ERROR); + + let position_amount_x_in_y = + position_amount_x.checked_mul(price).expect(OVERFLOW_ERROR); + let (position_amount_x, position_amount_y) = + if position_amount_x_in_y > position_amount_y { + let position_amount_y_in_x = position_amount_y + .checked_div(price) + .expect(OVERFLOW_ERROR); + (position_amount_y_in_x, position_amount_y) + } else { + (position_amount_x, position_amount_x_in_y) + }; + + let mut positions = vec![( + active_tick, + position_amount_x + .checked_mul(percentage_in_active_bin_x) + .expect(OVERFLOW_ERROR), + position_amount_y + .checked_mul(percentage_in_active_bin_y) + .expect(OVERFLOW_ERROR), + )]; + positions.extend( + lower_ticks + .into_iter() + .map(|bin_id| (bin_id, dec!(0), position_amount_y)), + ); + positions.extend( + higher_ticks + .into_iter() + .map(|bin_id| (bin_id, position_amount_x, dec!(0))), + ); + + let (receipt, change_x, change_y) = + pool.add_liquidity(bucket_x, bucket_y, positions); + + let receipt_global_id = { + let resource_address = receipt.resource_address(); + let local_id = + receipt.as_non_fungible().non_fungible_local_id(); + NonFungibleGlobalId::new(resource_address, local_id) + }; + + let adapter_specific_information = + CaviarnineV1AdapterSpecificInformation { + bin_contributions: pool + .get_redemption_bin_values( + receipt_global_id.local_id().clone(), + ) + .into_iter() + .map(|(tick, amount_x, amount_y)| { + ( + tick, + ResourceIndexedData { + resource_x: amount_x, + resource_y: amount_y, + }, + ) + }) + .collect(), + liquidity_receipt_non_fungible_global_id: receipt_global_id, + price_when_position_was_opened: price, + }; + + OpenLiquidityPositionOutput { + pool_units: receipt, + change: indexmap! { + change_x.resource_address() => change_x, + change_y.resource_address() => change_y, + }, + others: vec![], + adapter_specific_information: adapter_specific_information + .into(), + } + } + + fn close_liquidity_position( + &mut self, + pool_address: ComponentAddress, + pool_units: Bucket, + adapter_specific_information: AnyValue, + ) -> CloseLiquidityPositionOutput { + let mut pool = pool!(pool_address); + let pool_information @ PoolInformation { + bin_span, + resources: + ResourceIndexedData { + resource_x, + resource_y, + }, + } = self.get_pool_information(pool_address); + let (current_price, active_tick) = self + .price_and_active_tick(pool_address, Some(pool_information)) + .expect(NO_PRICE_ERROR); + + // Decoding the adapter specific information as the type we expect + // it to be. + let CaviarnineV1AdapterSpecificInformation { + bin_contributions, + price_when_position_was_opened, + .. + } = adapter_specific_information.as_typed().unwrap(); + + let (bucket_x, bucket_y) = pool.remove_liquidity(pool_units); + + let fees = { + // Calculate how much we expect to find in the bins at this + // price. + let expected_bin_amounts = + calculate_bin_amounts_due_to_price_action( + bin_contributions, + current_price, + price_when_position_was_opened, + active_tick, + bin_span, + ) + .expect(OVERFLOW_ERROR); + + // Based on the calculated bin amounts calculate how much we + // should expect to get back if we close the liquidity position + // by just summing them all up. + let expected_amount_back = expected_bin_amounts + .into_iter() + .map(|(_, amount_in_bin)| amount_in_bin) + .fold(ResourceIndexedData::default(), |acc, item| { + acc.checked_add(item).expect(OVERFLOW_ERROR) + }); + + // The difference between the amount we got back and the amount + // calculated up above is the fees. + indexmap! { + resource_x => max( + bucket_x.amount() + .checked_sub(expected_amount_back.resource_x) + .expect(OVERFLOW_ERROR), + Decimal::ZERO + ), + resource_y => max( + bucket_y.amount() + .checked_sub(expected_amount_back.resource_y) + .expect(OVERFLOW_ERROR), + Decimal::ZERO + ) + } + }; + + CloseLiquidityPositionOutput { + resources: indexmap! { + resource_x => bucket_x, + resource_y => bucket_y, + }, + others: Default::default(), + fees, + } + } + + fn price(&mut self, pool_address: ComponentAddress) -> Price { + let pool = pool!(pool_address); + + let PoolInformation { + resources: + ResourceIndexedData { + resource_x: resource_address_x, + resource_y: resource_address_y, + }, + .. + } = self.get_pool_information(pool_address); + let price = pool.get_price().expect(NO_PRICE_ERROR); + + Price { + base: resource_address_x, + quote: resource_address_y, + price, + } + } + + fn resource_addresses( + &mut self, + pool_address: ComponentAddress, + ) -> (ResourceAddress, ResourceAddress) { + let pool = pool!(pool_address); + + (pool.get_token_x_address(), pool.get_token_y_address()) + } + } +} + +#[derive(ScryptoSbor, Debug, Clone, Copy)] +pub struct PoolInformation { + pub bin_span: u32, + pub resources: ResourceIndexedData, +} + +#[derive(ScryptoSbor, Debug, Clone)] +pub struct CaviarnineV1AdapterSpecificInformation { + /// Stores how much was contributed to the bin. + pub bin_contributions: IndexMap>, + + /// The price in the pool when the position was opened. + pub price_when_position_was_opened: Decimal, + + /// Stores the non-fungible global id of the liquidity receipt. + pub liquidity_receipt_non_fungible_global_id: NonFungibleGlobalId, +} + +impl CaviarnineV1AdapterSpecificInformation { + pub fn new( + liquidity_receipt_non_fungible_global_id: NonFungibleGlobalId, + price_when_position_was_opened: Decimal, + ) -> Self { + CaviarnineV1AdapterSpecificInformation { + bin_contributions: Default::default(), + liquidity_receipt_non_fungible_global_id, + price_when_position_was_opened, + } + } + + pub fn contributions(&self) -> Vec<(u32, Decimal, Decimal)> { + let mut contributions = self + .bin_contributions + .iter() + .map(|(bin, contribution)| { + (*bin, contribution.resource_x, contribution.resource_y) + }) + .collect::>(); + contributions.sort_by(|a, b| a.0.cmp(&b.0)); + contributions + } +} + +impl From for AnyValue { + fn from(value: CaviarnineV1AdapterSpecificInformation) -> Self { + AnyValue::from_typed(&value).unwrap() + } +} + +#[derive(ScryptoSbor, Debug, Clone, Default)] +pub struct BinInformation { + /// The reserves of resources x and y in the bin. + pub reserves: ResourceIndexedData, + /// The amount of resources contributed to the bin. + pub contribution: ResourceIndexedData, +} + +/// A type-safe way of representing two-resources without using a map that is +/// indexed by a resource address. +/// +/// This guarantees that there is only two [`T`] fields, one for each resource +/// and that they're both of the same type. This also allows for addition and +/// subtraction over two [`ResourceIndexedData`] where [`T`] is the same in +/// both. +#[derive(ScryptoSbor, Debug, Clone, Copy, Default)] +pub struct ResourceIndexedData { + pub resource_x: T, + pub resource_y: T, +} + +impl Add for ResourceIndexedData +where + Self: CheckedAdd, +{ + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self.checked_add(rhs).unwrap() + } +} + +impl Sub for ResourceIndexedData +where + Self: CheckedSub, +{ + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + self.checked_sub(rhs).unwrap() + } +} + +impl CheckedAdd for ResourceIndexedData +where + T: CheckedAdd, +{ + type Output = Self; + + fn checked_add(self, rhs: Self) -> Option + where + Self: Sized, + { + Some(Self { + resource_x: self.resource_x.checked_add(rhs.resource_x)?, + resource_y: self.resource_y.checked_add(rhs.resource_y)?, + }) + } +} + +impl CheckedSub for ResourceIndexedData +where + T: CheckedSub, +{ + type Output = Self; + + fn checked_sub(self, rhs: Self) -> Option + where + Self: Sized, + { + Some(Self { + resource_x: self.resource_x.checked_sub(rhs.resource_x)?, + resource_y: self.resource_y.checked_sub(rhs.resource_y)?, + }) + } +} + +#[derive(Clone, Debug, Copy)] +pub enum Composition { + EntirelyX, + EntirelyY, + Composite, +} + +/// This method calculates the liquidity or the `l` of each bin based on the +/// reserves in the bin and the lower and upper ticks of the bin. +pub fn calculate_liquidity( + bin_reserves: ResourceIndexedData, + lower_price: Decimal, + upper_price: Decimal, +) -> Option { + let ResourceIndexedData { + resource_x: reserves_x, + resource_y: reserves_y, + } = bin_reserves; + + let reserves_x = PreciseDecimal::from(reserves_x); + let reserves_y = PreciseDecimal::from(reserves_y); + // TODO: Consider caching the the sqrt. + let lower_price_sqrt = PreciseDecimal::from(lower_price).checked_sqrt()?; + let upper_price_sqrt = PreciseDecimal::from(upper_price).checked_sqrt()?; + + // Solve quadratic for liquidity + let a = lower_price_sqrt + .checked_div(upper_price_sqrt)? + .checked_sub(PreciseDecimal::ONE)?; + let b = reserves_x + .checked_mul(lower_price_sqrt)? + .checked_add(reserves_y.checked_div(upper_price_sqrt)?)?; + let c = reserves_x.checked_mul(reserves_y)?; + + let nominator = b.checked_neg()?.checked_sub( + b.checked_powi(2)? + .checked_sub(pdec!(4).checked_mul(a)?.checked_mul(c)?)? + .checked_sqrt()?, + )?; + let denominator = pdec!(2).checked_mul(a)?; + + nominator + .checked_div(denominator) + .and_then(|value| Decimal::try_from(value).ok()) +} + +/// Given the amount of assets that used to be in the bin and a certain change +/// in price, this function calculates the new composition of the bins based on +/// price action alone. +fn calculate_bin_amounts_due_to_price_action( + bin_amounts: IndexMap>, + current_price: Decimal, + price_when_position_was_opened: Decimal, + active_tick: u32, + bin_span: u32, +) -> Option)>> { + bin_amounts + .into_iter() + .map(|(tick, bin_amount_at_opening_time)| { + // Calculating the lower and upper prices of the bin based on the + // the starting tick and the bin span. + let lower_tick = tick; + let upper_tick = tick.checked_add(bin_span)?; + + let bin_lower_price = tick_to_spot(lower_tick)?; + let bin_upper_price = tick_to_spot(upper_tick)?; + + let bin_composition_when_position_opened = match ( + bin_amount_at_opening_time.resource_x.is_zero(), + bin_amount_at_opening_time.resource_y.is_zero(), + ) { + (true, true) => return None, + (true, false) => Composition::EntirelyY, + (false, true) => Composition::EntirelyX, + (false, false) => Composition::Composite, + }; + + // Determine what we expect the composition of this bin to be based + // on the current active tick. + let expected_bin_composition_now = match tick.cmp(&active_tick) { + // Case A: The current price is inside this bin. Since we are + // the current active bin then it's expected that this bin has + // both X and Y assets. + Ordering::Equal => Composition::Composite, + // Case B: The current price of the pool is greater than the + // upper bound of the bin. We're outside of that range and there + // should only be Y assets in the bin. + Ordering::Less => Composition::EntirelyY, + // Case C: The current price of the pool is smaller than the + // lower bound of the bin. We're outside of that range and there + // should only be X assets in the bin. + Ordering::Greater => Composition::EntirelyX, + }; + + let new_contents = match ( + bin_composition_when_position_opened, + expected_bin_composition_now, + ) { + // The bin was entirely made of X and is still the same. Thus, + // this bin "has not been touched" and should in theory contain + // the same amount as before. Difference found can therefore be + // attributed to fees. The other case is when the bin was made + // of up just Y and still is just Y. + (Composition::EntirelyX, Composition::EntirelyX) => Some(( + bin_amount_at_opening_time.resource_x, + bin_amount_at_opening_time.resource_y, + )), + (Composition::EntirelyY, Composition::EntirelyY) => Some(( + bin_amount_at_opening_time.resource_x, + bin_amount_at_opening_time.resource_y, + )), + // The bin was entirely made up of one asset and is now made up + // of another. We therefore want to do a full "swap" of that + // amount. For this calculation we use y = sqrt(pa * pb) * x. + // We can also use the equation used in the later cases but it + // is very expensive to run. + (Composition::EntirelyX, Composition::EntirelyY) => Some(( + dec!(0), + bin_lower_price + .checked_mul(bin_upper_price) + .and_then(|value| value.checked_sqrt()) + .and_then(|value| { + value.checked_mul( + bin_amount_at_opening_time.resource_x, + ) + }) + .expect(OVERFLOW_ERROR), + )), + (Composition::EntirelyY, Composition::EntirelyX) => Some(( + bin_lower_price + .checked_mul(bin_upper_price) + .and_then(|value| value.checked_sqrt()) + .and_then(|value| { + bin_amount_at_opening_time + .resource_y + .checked_div(value) + }) + .expect(OVERFLOW_ERROR), + dec!(0), + )), + // The bin was entirely made up of one of the assets and + // is now made up of both of them. + (Composition::EntirelyX, Composition::Composite) => { + let (starting_price, ending_price) = + (bin_lower_price, current_price); + calculate_bin_amount_using_liquidity( + bin_amount_at_opening_time, + bin_lower_price, + bin_upper_price, + starting_price, + ending_price, + ) + } + (Composition::EntirelyY, Composition::Composite) => { + let (starting_price, ending_price) = + (bin_upper_price, current_price); + calculate_bin_amount_using_liquidity( + bin_amount_at_opening_time, + bin_lower_price, + bin_upper_price, + starting_price, + ending_price, + ) + } + // The bin was made up of both assets and is now just made + // up of one of them. + (Composition::Composite, Composition::EntirelyX) => { + let (starting_price, ending_price) = + (price_when_position_was_opened, bin_lower_price); + calculate_bin_amount_using_liquidity( + bin_amount_at_opening_time, + bin_lower_price, + bin_upper_price, + starting_price, + ending_price, + ) + } + (Composition::Composite, Composition::EntirelyY) => { + let (starting_price, ending_price) = + (price_when_position_was_opened, bin_upper_price); + calculate_bin_amount_using_liquidity( + bin_amount_at_opening_time, + bin_lower_price, + bin_upper_price, + starting_price, + ending_price, + ) + } + // The bin was made up of both assets and is still made up + // of both assets. + (Composition::Composite, Composition::Composite) => { + let (starting_price, ending_price) = + (price_when_position_was_opened, current_price); + calculate_bin_amount_using_liquidity( + bin_amount_at_opening_time, + bin_lower_price, + bin_upper_price, + starting_price, + ending_price, + ) + } + }; + + new_contents.map(|contents| { + ( + tick, + ResourceIndexedData { + resource_x: contents.0, + resource_y: contents.1, + }, + ) + }) + }) + .collect() +} + +fn calculate_bin_amount_using_liquidity( + bin_amount: ResourceIndexedData, + bin_lower_price: Decimal, + bin_upper_price: Decimal, + starting_price: Decimal, + ending_price: Decimal, +) -> Option<(Decimal, Decimal)> { + let liquidity = + calculate_liquidity(bin_amount, bin_lower_price, bin_upper_price)?; + + let change_x = liquidity.checked_mul( + Decimal::ONE + .checked_div(ending_price.checked_sqrt()?)? + .checked_sub( + Decimal::ONE.checked_div(starting_price.checked_sqrt()?)?, + )?, + )?; + let change_y = liquidity.checked_mul( + ending_price + .checked_sqrt()? + .checked_sub(starting_price.checked_sqrt()?)?, + )?; + + let new_x = + max(bin_amount.resource_x.checked_add(change_x)?, Decimal::ZERO); + let new_y = + max(bin_amount.resource_y.checked_add(change_y)?, Decimal::ZERO); + + Some((new_x, new_y)) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn simple_resource_indexed_data_addition_produces_expected_output() { + // Arrange + let a = ResourceIndexedData { + resource_x: Decimal::ZERO, + resource_y: dec!(200), + }; + let b = ResourceIndexedData { + resource_x: dec!(500), + resource_y: dec!(12), + }; + + // Act + let c = a + b; + + // Assert + assert_eq!(c.resource_x, dec!(500)); + assert_eq!(c.resource_y, dec!(212)); + } + + #[test] + fn simple_resource_indexed_data_subtraction_produces_expected_output() { + // Arrange + let a = ResourceIndexedData { + resource_x: Decimal::ZERO, + resource_y: dec!(200), + }; + let b = ResourceIndexedData { + resource_x: dec!(500), + resource_y: dec!(12), + }; + + // Act + let c = a - b; + + // Assert + assert_eq!(c.resource_x, dec!(-500)); + assert_eq!(c.resource_y, dec!(188)); + } +} diff --git a/packages/caviarnine-v1-adapter-v1/src/tick_math.rs b/packages/caviarnine-v1-adapter-v1/src/tick_math.rs new file mode 100644 index 00000000..854861a2 --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/src/tick_math.rs @@ -0,0 +1,24 @@ +use scrypto::prelude::*; +use scrypto_math::*; + +pub const BASE: Decimal = dec!(1.0005); +pub const MIN_TICK: u32 = 0; +pub const MAX_TICK: u32 = 54000; + +/// Converts a tick to spot price through checked math. +pub fn tick_to_spot(tick: u32) -> Option { + if tick > MAX_TICK { + None + } else { + BASE.checked_powi((tick as i64).checked_sub(27000)?.checked_mul(2)?) + } +} + +pub fn spot_to_tick(price: Decimal) -> Option { + price + .log_base(BASE) + .and_then(|value| value.checked_div(dec!(2))) + .and_then(|value| value.checked_add(dec!(27000))) + .and_then(|value| value.0.checked_div(Decimal::ONE.0)) + .and_then(|value| u32::try_from(value).ok()) +} diff --git a/packages/caviarnine-v1-adapter-v1/src/tick_selector.rs b/packages/caviarnine-v1-adapter-v1/src/tick_selector.rs new file mode 100644 index 00000000..3b54d41d --- /dev/null +++ b/packages/caviarnine-v1-adapter-v1/src/tick_selector.rs @@ -0,0 +1,239 @@ +//! A module implementing the logic for the selection of the ticks to contribute +//! liquidity to based on the current active bin, the bin span, and the maximum +//! number of allowed ticks. + +/// Ticks are in the range [0, 54000]. +const MINIMUM_TICK_VALUE: usize = 0; +const MAXIMUM_TICK_VALUE: usize = 54000; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SelectedTicks { + pub active_tick: u32, + pub lower_ticks: Vec, + pub higher_ticks: Vec, +} + +impl SelectedTicks { + /// Selects the ticks that the positions should be made out of. + /// + /// Given the pool's active bin, bin span, and the preferred number of ticks + /// we wish to have, this function determines which ticks the liquidity + /// should go to without determining the exact formation of the liquidity + /// (e.g., flat or triangle). This function is specifically suited to handle + /// edge cases when selecting the bin that could lead to failures, and + /// handles such cases in a correct graceful manner. + /// + /// In simple cases where the active bin is in the middle of the bin range + /// and the bin span is small enough, the selection of the lower and higher + /// ticks is simple enough: preferred number of ticks (divided by 2) to the + /// left and the same on the right. This gives the caller the number of + /// ticks that they wish to have on the left and the right of the active + /// bin. + /// + /// There are cases however where the number of lower ticks can't be equal + /// to the number of higher ticks. Specifically, cases when the active + /// bin's value is too small or too large or cases when the bin span is + /// too large. In such cases, this function attempts to compensate the + /// other side. As an example, if we wish to have 10 ticks and can only + /// have 2 lower ticks, then the higher ticks will have 8, thus + /// achieving the preferred number of lower and higher ticks specified + /// by the caller. A similar thing happens if the current active bin is + /// too close to the maximum. + /// + /// There are cases when the proffered number of ticks can not be achieved + /// by the function, specifically, cases when the bin span is too large + /// that any bin to the right or the left will be outside of the range + /// is allowed ticks. In such cases, this function returns a number of + /// left and right ticks that is less than the desired. + /// + /// # Examples + /// + /// This section has examples with concrete numbers to to explain the + /// behavior of this function better. + /// + /// ## Example 1: Simple Case + /// + /// * `active_tick`: 100 + /// * `bin_span`: 10 + /// * `preferred_total_number_of_higher_and_lower_ticks`: 4 + /// + /// This function will return the following: + /// + /// * `active_tick`: 100 + /// * `lower_ticks`: [90, 80] + /// * `higher_ticks`: [110, 120] + /// + /// ## Example 2: Left Skew + /// + /// * `active_tick`: 20 + /// * `bin_span`: 10 + /// * `preferred_total_number_of_higher_and_lower_ticks`: 6 + /// + /// This function will return the following: + /// + /// * `active_tick`: 20 + /// * `lower_ticks`: [10, 0] + /// * `higher_ticks`: [30, 40, 50, 60] + /// + /// At this currently active bin, there can only exist 2 ticks on the lower + /// side. Thus, these ticks are selected and left's remaining share of the + /// ticks is given to the right. This results in a total of 6 ticks. + /// + /// ## Example 3: Right Skew + /// + /// * `active_tick`: 53980 + /// * `bin_span`: 10 + /// * `preferred_total_number_of_higher_and_lower_ticks`: 6 + /// + /// This function will return the following: + /// + /// * `active_tick`: 53980 + /// * `lower_ticks`: [53970, 53960, 53950, 53940] + /// * `higher_ticks`: [53990, 54000] + /// + /// At this currently active bin, there can only exist 2 ticks on the higher + /// side. Thus, these ticks are selected and right's remaining share of the + /// ticks is given to the left. This results in a total of 6 ticks. + /// + /// Example 4: Bin Size too large + /// + /// * `active_tick`: 27000 + /// * `bin_span`: 54000 + /// * `preferred_total_number_of_higher_and_lower_ticks`: 6 + /// + /// This function will return the following: + /// + /// * `active_tick`: 27000 + /// * `lower_ticks`: [] + /// * `higher_ticks`: [] + /// + /// Given this pool's bin span, we can not get any ticks that are lower or + /// higher and so we return just the active bin and return no lower or + /// higher ticks. + /// + /// Example 4: Bin Size too large with a skew + /// + /// * `active_tick`: 54000 + /// * `bin_span`: 30000 + /// * `preferred_total_number_of_higher_and_lower_ticks`: 6 + /// + /// This function will return the following: + /// + /// * `active_tick`: 54000 + /// * `lower_ticks`: [24000] + /// * `higher_ticks`: [] + /// + /// # Arguments: + /// + /// * `active_tick`: [`u32`] - The pool's currently active bin. + /// * `bin_span`: [`u32`] - The span between each bin and another or the + /// distance between them. + /// * `preferred_total_number_of_higher_and_lower_ticks`: [`u32`] - The + /// total number of ticks the caller wishes to have on the right and the + /// left (summed). As detailed above, this may or may not be achieved + /// depending on the pool's current bin and bin span. + /// + /// # Returns: + /// + /// [`SelectedTicks`] - A struct with the ticks that have been selected by + /// this function. + // TODO: Look into making this non-iterative. + pub fn select( + active_tick: u32, + bin_span: u32, + preferred_total_number_of_higher_and_lower_ticks: u32, + ) -> Self { + let mut selected_ticks = Self { + active_tick, + higher_ticks: vec![], + lower_ticks: vec![], + }; + + let mut remaining = preferred_total_number_of_higher_and_lower_ticks; + + let mut forward_counter = + BoundedU32::(active_tick); + let mut backward_counter = + BoundedU32::(active_tick); + + while remaining > 0 { + let mut forward_counter_incremented = false; + let mut backward_counter_decremented = false; + + if forward_counter.checked_add_assign(bin_span).is_some() { + remaining = remaining + .checked_sub(1) + .expect("Impossible, we do the check somewhere else"); + selected_ticks.higher_ticks.push(forward_counter.0); + forward_counter_incremented = true; + } + if remaining > 0 + && backward_counter.checked_sub_assign(bin_span).is_some() + { + remaining = remaining + .checked_sub(1) + .expect("Impossible, we do the check somewhere else"); + selected_ticks.lower_ticks.push(backward_counter.0); + backward_counter_decremented = true; + } + + if !forward_counter_incremented && !backward_counter_decremented { + break; + } + } + + selected_ticks + } +} + +struct BoundedU32(u32); + +impl BoundedU32 { + pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { + if let Some(value) = self.checked_add(other) { + *self = value; + Some(()) + } else { + None + } + } + + pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { + if let Some(value) = self.checked_sub(other) { + *self = value; + Some(()) + } else { + None + } + } + + pub fn checked_add(&self, other: impl Into) -> Option { + let this = self.0; + let other = other.into(); + + if let Some(result) = this.checked_add(other) { + if result as usize > MAX { + None + } else { + Some(Self(result)) + } + } else { + None + } + } + + pub fn checked_sub(&self, other: impl Into) -> Option { + let this = self.0; + let other = other.into(); + + if let Some(result) = this.checked_sub(other) { + if (result as usize).lt(&MIN) { + None + } else { + Some(Self(result)) + } + } else { + None + } + } +} diff --git a/packages/ignition/Cargo.toml b/packages/ignition/Cargo.toml new file mode 100644 index 00000000..308e99e9 --- /dev/null +++ b/packages/ignition/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ignition" +version.workspace = true +edition.workspace = true +description = "The implementation of the Ignition protocol" + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +radix-engine-derive = { workspace = true } + +ports-interface = { path = "../../libraries/ports-interface" } +common = { path = "../../libraries/common" } + +[features] +default = [] +test = [] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/packages/ignition/src/blueprint.rs b/packages/ignition/src/blueprint.rs new file mode 100644 index 00000000..75aab1f8 --- /dev/null +++ b/packages/ignition/src/blueprint.rs @@ -0,0 +1,1924 @@ +//! This module implements the main project ignition blueprint and protocol. +//! +//! In simple terms, project ignition allows for users to provide one side of +//! liquidity and for itself to provide the other side of the liquidity. The +//! protocol is not quite made to be profit-generating, its main purpose is to +//! incentivize people to provide liquidity by providing users with a number of +//! benefits: +//! +//! * User's contribution is doubled in value; Ignition will contribute the +//! other side of the liquidity. +//! * Users get some percentage of rewards upfront. +//! * Users have impermanent loss protection and in most cases are guaranteed +//! to withdraw out the same amount of tokens that they put in plus fees earned +//! on their position. +//! +//! This makes Ignition a perfect incentive for users who already own an amount +//! of some of the supported tokens and who wish to provide liquidity with very +//! low downside, upfront rewards, and impermanent loss protection. +//! +//! The user locks their tokens for some period of time allowed by the protocol +//! and based on that they get some amount of upfront rewards. The longer the +//! lockup period is, the higher the rewards are. When the period is over, the +//! protocol will try to provide the user with the same amount of tokens that +//! they put in plus any trading fees earned in the process (on their asset). +//! If that can't be given, then the protocol will try to provide the user of +//! as much of the protocol's asset as possible to make them whole in terms of +//! value. +//! +//! In Ignition, the term "protocol's asset" refers to the asset that Ignition +//! has and that the protocol is willing to lend out to users when they wish to +//! provide liquidity. The term "user asset" refers to the asset or resource +//! that was provided by the user. So, the protocol and user assets are the two +//! sides of the liquidity that go into a liquidity pool, which name is used +//! depends on their source: the protocol for the ledger's resource and the user +//! for the user's resource. +//! +//! An important thing to note is that the protocol's protocol's asset can't be +//! changed at runtime after the component has been instantiated, it will be +//! forever stuck with that protocol's asset. The user assets can be added and +//! removed by adding and removing pools to the allowed pools list. In the case +//! of the protocol officially run by RDX Works, the protocol's asset will be +//! XRD and the user's asset will be BTC, ETH, USDC, and USDT. However, Ignition +//! is actually general enough that it can be used by projects who would like to +//! improve their liquidity and who're willing to lose some tokens in the +//! process. +//! +//! The protocol's blueprint is made to be quite modular and to allow for easy +//! upgrading if needed. This means that the protocol's assets can be withdrawn +//! by the protocol owner and that many of the external components that the +//! protocol relies on can be swapped at runtime with little trouble. As an +//! example, the protocol communicates with Dexes through adapters meaning that +//! additional Dexes can be supported by writing and registering new adapters to +//! the existing component on ledger and that support for dexes can be removed +//! by removing their adapter. Additionally, the oracle can be swapped and +//! changed at any point of time to a new oracle. Changing the oracle or the +//! adapters relies on the interface being the same, if the interface is +//! different then, unfortunately, there is no way for the protocol to check at +//! runtime but calls using the oracle or adapter would fail. Thus, changes must +//! be preceded by an interface check. +//! +//! Similarly, the reward rates are quite modular too and are added at runtime +//! and not baked into the blueprint itself allowing additional reward rates to +//! be added and for some reward rates to be removed. + +#![allow(clippy::type_complexity)] + +use crate::errors::*; +use common::prelude::*; +use ports_interface::prelude::*; +use scrypto::prelude::*; +use std::cmp::*; + +type PoolAdapter = PoolAdapterInterfaceScryptoStub; +type OracleAdapter = OracleAdapterInterfaceScryptoStub; + +#[blueprint] +#[types( + Decimal, + ResourceAddress, + NonFungibleGlobalId, + BlueprintId, + Vault, + Vec, + FungibleVault, + LockupPeriod, + Volatility, + StoredPoolBlueprintInformation, +)] +mod ignition { + enable_method_auth! { + roles { + protocol_owner => updatable_by: [protocol_owner]; + protocol_manager => updatable_by: [protocol_manager, protocol_owner]; + }, + methods { + set_oracle_adapter => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_pool_adapter => restrict_to: [ + protocol_owner, + protocol_manager + ]; + add_allowed_pool => restrict_to: [ + protocol_owner, + protocol_manager + ]; + remove_allowed_pool => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_liquidity_receipt => restrict_to: [ + protocol_owner, + protocol_manager + ]; + insert_pool_information => restrict_to: [ + protocol_owner, + protocol_manager + ]; + remove_pool_information => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_maximum_allowed_price_staleness => restrict_to: [ + protocol_owner, + protocol_manager + ]; + remove_reward_rate => restrict_to: [ + protocol_owner, + protocol_manager + ]; + add_reward_rate => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_is_open_position_enabled => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_is_close_position_enabled => restrict_to: [ + protocol_owner, + protocol_manager + ]; + set_maximum_allowed_price_difference_percentage => restrict_to: [ + protocol_owner, + protocol_manager + ]; + insert_user_resource_volatility => restrict_to: [ + protocol_owner, + protocol_manager + ]; + deposit_protocol_resources => restrict_to: [protocol_owner]; + withdraw_protocol_resources => restrict_to: [protocol_owner]; + deposit_user_resources => restrict_to: [protocol_owner]; + withdraw_user_resources => restrict_to: [protocol_owner]; + deposit_pool_units => restrict_to: [protocol_owner]; + withdraw_pool_units => restrict_to: [protocol_owner]; + forcefully_liquidate => restrict_to: [protocol_owner]; + /* User methods */ + open_liquidity_position => PUBLIC; + close_liquidity_position => PUBLIC; + /* Getters */ + get_user_resource_reserves_amount => PUBLIC; + get_protocol_resource_reserves_amount => PUBLIC; + } + } + + struct Ignition { + /// A reference to the resource manager of the protocol's resource. + /// This is the resource that the protocol will be lending out + /// to users who wish to provide liquidity. In other words, + /// this is the one side of the liquidity that will be provided + /// by the protocol and the other side must be provided by the + /// user. This can't be changed after the component has been + /// instantiated. Thus, it would be chosen with some caution. + /// + /// Even though Ignition will only be lending out XRD this information + /// is kept dynamic instead of static to allow for easier testing of + /// Ignition and to allow for it to be deployed and tested on testnets + /// with mintable resources. + protocol_resource: ResourceManager, + + /// The adapter of the oracle to use for the protocol. The oracle is + /// expected to have a specific interface that is required by this + /// blueprint. This adapter can be updated and changed at runtime to + /// a new one whose underlying oracle is completely different. Thus + /// we can switch between oracle providers at runtime by developing a + /// new adapter for said oracle provider. + oracle_adapter: OracleAdapter, + + /// Information about the pool blueprints, indexed by the id of the + /// blueprint. This contains information about the adapter to use, the + /// list of pools that contributions are allowed to, and a reference + /// to the resource manager of the liquidity receipt. Everything about + /// this is updatable. Entries can be added and removed, adapters can + /// be changed, pools can be added or removed from the list of allowed + /// pools, and liquidity receipt addresses can be changed. + /// + /// The mapping of the [`BlueprintId`] to the pool information means + /// that each Dex, or at least Dex blueprint, has a single entry in the + /// protocol. + /// + /// Note: it is well understood that [`StoredPoolBlueprintInformation`] + /// data is unbounded in size and that it can lead to state explosion. + /// But, we will only have four allowed pools in Ignition and therefore + /// we are not worried about the state explosion problems. Additionally, + /// using a [`KeyValueStore`] there would mean that the pool information + /// entires can not be removed or replaced from the map due to the fact + /// that a kv-store can't be dropped. Therefore, a regular [`IndexMap`] + /// is used and its guaranteed that there will only be four pools there. + pool_information: + KeyValueStore, + + /// Maps a resource address to its volatility classification in the + /// protocol. This is used to store whether a resource is considered to + /// be volatile or non-volatile to then determine which vault of the + /// protocol resources to use when matching the contributions. + /// + /// This is not quite meant to be an allow or deny list so the only + /// operation that is allowed to this KVStore is an upsert, removals + /// are not allowed. + user_resource_volatility: KeyValueStore, + + /* Vaults */ + /// The reserves of the ignition protocol resource where they are split + /// by the resources to use for volatile assets and the ones to use for + /// non-volatile assets. + protocol_resource_reserves: ProtocolResourceReserves, + + /// A key value store of all of the vaults of ignition that contain the + /// user resources. These vaults do not need to be funded with anything + /// for the protocol to run, they're primarily used by the protocol to + /// deposit some of the user assets obtained when closing liquidity + /// positions. `protocol_resource_reserves` stores the protocol assets + /// required for the protocol operations. Only the owner of the + /// protocol is allowed to deposit and withdraw from these + /// vaults. + user_resources_vaults: KeyValueStore, + + /// The vaults storing the pool units and liquidity receipts obtained + /// from providing the liquidity. It is indexed by the non-fungible + /// global id of the liquidity receipt non-fungible token minted by + /// the protocol when liquidity is provided. Only the owner of the + /// protocol is allowed to deposit or withdraw into these vaults. + pool_units: KeyValueStore, + + /// A KeyValueStore that stores all of the tokens owed to users of the + /// protocol whose liquidity claims have been forcefully liquidated. + /// + /// Note: It is understood that the value type used here can in theory + /// lead to state explosion. However, realistically, there would only + /// be 2 vaults in here since the pools we're interacting with are all + /// of two resources. Perhaps there would be a third if some of the + /// DEXs has an incentive program. However, it is very unlikely + /// that there would be more than that. + forced_liquidation_claims: + KeyValueStore>, + + /* Configuration */ + /// The upfront reward rates supported by the protocol. This is a map + /// of the lockup period to the reward rate ratio. In this + /// case, the value is a decimal in the range [0, ∞] where 0 + /// means 0%, 0.5 means 50%, and 1 means 100%. + reward_rates: KeyValueStore, + + /// Controls whether the protocol currently allows users to open + /// liquidity positions or not. + is_open_position_enabled: bool, + + /// Controls whether the protocol currently allows users to close + /// liquidity positions or not. + is_close_position_enabled: bool, + + /// The maximum allowed staleness of prices in seconds. If a price is + /// found to be older than this then it is deemed to be invalid. + maximum_allowed_price_staleness: i64, + + /// The maximum percentage of price difference the protocol is willing + /// to accept before deeming the price difference to be too much. This + /// is a decimal in the range [0, ∞] where 0 means 0%, 0.5 means 50%, + /// and 1 means 100%. + maximum_allowed_price_difference_percentage: Decimal, + } + + impl Ignition { + /// Instantiates a new Ignition protocol component based on the provided + /// protocol parameters. + pub fn instantiate( + metadata_init: MetadataInit, + /* Rules */ + owner_role: OwnerRole, + protocol_owner_role: AccessRule, + protocol_manager_role: AccessRule, + /* Initial Configuration */ + protocol_resource: ResourceManager, + oracle_adapter: ComponentAddress, + maximum_allowed_price_staleness: i64, + maximum_allowed_price_difference_percentage: Decimal, + /* Initializers */ + initialization_parameters: InitializationParameters, + /* Misc */ + address_reservation: Option, + ) -> Global { + // If no address reservation is provided then reserve an address to + // globalize the component to - this is to provide us with a non + // branching way of globalizing the component. + let address_reservation = address_reservation.unwrap_or_else(|| + Runtime::allocate_component_address(Ignition::blueprint_id()).0, + ); + + let ignition = { + let InitializationParameters { + initial_pool_information, + initial_user_resource_volatility, + initial_reward_rates, + initial_volatile_protocol_resources, + initial_non_volatile_protocol_resources, + initial_is_open_position_enabled, + initial_is_close_position_enabled, + } = initialization_parameters; + + let mut ignition = Self { + protocol_resource, + oracle_adapter: oracle_adapter.into(), + pool_information: KeyValueStore::new_with_registered_type(), + user_resources_vaults: + KeyValueStore::new_with_registered_type(), + pool_units: KeyValueStore::new_with_registered_type(), + reward_rates: KeyValueStore::new_with_registered_type(), + is_open_position_enabled: false, + is_close_position_enabled: false, + maximum_allowed_price_staleness, + maximum_allowed_price_difference_percentage, + user_resource_volatility: + KeyValueStore::new_with_registered_type(), + protocol_resource_reserves: ProtocolResourceReserves::new( + protocol_resource.address(), + ), + forced_liquidation_claims: + KeyValueStore::new_with_registered_type(), + }; + + if let Some(resource_volatility) = + initial_user_resource_volatility + { + for (resource_address, volatility) in + resource_volatility.into_iter() + { + ignition.insert_user_resource_volatility( + resource_address, + volatility, + ) + } + } + + if let Some(pool_information) = initial_pool_information { + for (blueprint_id, information) in + pool_information.into_iter() + { + ignition + .insert_pool_information(blueprint_id, information) + } + } + + if let Some(reward_rates) = initial_reward_rates { + for (lockup_period, reward) in reward_rates.into_iter() { + ignition.add_reward_rate(lockup_period, reward) + } + } + + if let Some(volatile_protocol_resources) = + initial_volatile_protocol_resources + { + ignition.deposit_protocol_resources( + volatile_protocol_resources, + Volatility::Volatile, + ) + } + + if let Some(non_volatile_protocol_resources) = + initial_non_volatile_protocol_resources + { + ignition.deposit_protocol_resources( + non_volatile_protocol_resources, + Volatility::NonVolatile, + ) + } + + ignition.is_open_position_enabled = + initial_is_open_position_enabled.unwrap_or(false); + ignition.is_close_position_enabled = + initial_is_close_position_enabled.unwrap_or(false); + + ignition + }; + + ignition + .instantiate() + .prepare_to_globalize(owner_role) + .roles(roles! { + protocol_owner => protocol_owner_role; + protocol_manager => protocol_manager_role; + }) + .metadata(ModuleConfig { + init: metadata_init, + roles: Default::default(), + }) + .with_address(address_reservation) + .globalize() + } + + /// Opens a liquidity position for the user. + /// + /// Given some bucket of tokens, this method matches this bucket with + /// XRD of the same value and contributes that XRD to the pool specified + /// as an argument. The liquidity is locked in that pool for the lockup + /// period specified as an argument and the user is given back a non + /// fungible token that represents their portion in the pool. + /// + /// If opening a liquidity pool returns more than the pool units and the + /// change, then these additional tokens are returned back to the caller + /// and not kept by the protocol. + /// + /// # Panics + /// + /// There are a number of situations when this method panics and leads + /// the transaction to fail. Some of them are: + /// + /// * If the specified pool is not a registered pool in Ignition and + /// thus, no liquidity is allowed to be provided to this pool. + /// * If the lockup period specified by the caller has no corresponding + /// upfront rewards percentage, and thus it is not a recognized lockup + /// period by the pool. + /// * If no adapter is registered for the liquidity pool. + /// * If the price difference between the pool and the oracle is higher + /// than what is allowed by the protocol. + /// + /// # Arguments + /// + /// * `bucket`: [`FungibleBucket`] - A fungible bucket of tokens to + /// contribute to the pool. Ignition will match the value of this bucket + /// in XRD and contribute it alongside it to the specified pool. + /// * `pool_address`: [`ComponentAddress`] - The address of the pool to + /// contribute to, this must be a valid pool that is registered in the + /// protocol and that has an adapter. + /// * `lockup_period`: [`LockupPeriod`] - The amount of time (in + /// seconds) to lockup the liquidity. This must be a registered lockup + /// period with a defined upfront rewards rate. + /// + /// # Returns + /// + /// * [`NonFungibleBucket`] - A non-fungible bucket of the liquidity + /// position resource that gives the holder the right to close their + /// liquidity position when the lockup period is up. + /// * [`FungibleBucket`] - A bucket of the change. + /// * [`Vec`] - A vector of other buckets that the pools can + /// return upon contribution, this can be their rewards tokens or + /// anything else. + pub fn open_liquidity_position( + &mut self, + bucket: FungibleBucket, + pool_address: ComponentAddress, + lockup_period: LockupPeriod, + ) -> (NonFungibleBucket, FungibleBucket, Vec) { + // Ensure that we currently allow opening liquidity positions. + assert!( + self.is_open_position_enabled, + "{}", + OPENING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR + ); + + // Caching a few information so that it is not constantly read from + // the engine. + let user_resource_address = bucket.resource_address(); + let user_resource_amount = bucket.amount(); + + // Getting the volatility of the user asset from the volatility map. + let volatility = *self + .user_resource_volatility + .get(&user_resource_address) + .expect(USER_RESOURCES_VOLATILITY_UNKNOWN_ERROR); + + // Ensure that the pool has an adapter and that it is a registered + // pool. If it is, this means that we can move ahead with the pool. + // Also, it means that the pool is guaranteed to have the protocol + // resource on one of its sides. + let (mut adapter, liquidity_receipt_resource, pool_resources, _) = + self.checked_get_pool_adapter_information(pool_address) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR); + + // Ensure that the passed bucket belongs to the pool and that it is + // not some random resource. + { + let (resource1, resource2) = pool_resources; + + assert!( + resource1 == user_resource_address + || resource2 == user_resource_address, + "{}", + USER_ASSET_DOES_NOT_BELONG_TO_POOL_ERROR + ); + + assert_ne!( + user_resource_address, + self.protocol_resource.address(), + "{}", + USER_MUST_NOT_PROVIDE_PROTOCOL_ASSET_ERROR + ) + } + + // Compare the price difference between the oracle reported price + // and the pool reported price - ensure that it is within the + // allowed price difference range. + let oracle_reported_price = { + let oracle_reported_price = self.checked_get_price( + user_resource_address, + self.protocol_resource.address(), + ); + let pool_reported_price = adapter.price(pool_address); + let relative_difference = oracle_reported_price + .relative_difference(&pool_reported_price) + .expect(USER_ASSET_DOES_NOT_BELONG_TO_POOL_ERROR); + + assert!( + relative_difference + <= self.maximum_allowed_price_difference_percentage, + "{}", + RELATIVE_PRICE_DIFFERENCE_LARGER_THAN_ALLOWED_ERROR + ); + + oracle_reported_price + }; + + let oracle_reported_value_of_user_resource_in_protocol_resource = + oracle_reported_price + .exchange(user_resource_address, user_resource_amount) + .expect(UNEXPECTED_ERROR) + .1; + + // Contribute the resources to the pool. + let user_side_of_liquidity = bucket; + let protocol_side_of_liquidity = self.withdraw_protocol_resources( + oracle_reported_value_of_user_resource_in_protocol_resource, + WithdrawStrategy::Rounded(RoundingMode::ToZero), + volatility, + ); + let OpenLiquidityPositionOutput { + pool_units, + mut change, + others, + adapter_specific_information, + } = adapter.open_liquidity_position( + pool_address, + (user_side_of_liquidity.0, protocol_side_of_liquidity.0), + ); + + // Calculate the amount of resources that was actually contributed + // based on the amount of change that we got back. + let amount_of_user_tokens_contributed = user_resource_amount + .checked_sub( + change + .get(&user_resource_address) + .map(Bucket::amount) + .unwrap_or(Decimal::ZERO), + ) + // Impossible to get here. This is saying that not only did we + // get change back that exceeded the amount that was put in, but + // that the change we got back was so large that it lead us to + // underflow. + .expect(OVERFLOW_ERROR); + let amount_of_protocol_tokens_contributed = + oracle_reported_value_of_user_resource_in_protocol_resource + .checked_sub( + change + .get(&self.protocol_resource.address()) + .map(Bucket::amount) + .unwrap_or(Decimal::ZERO), + ) + // Impossible to get here. This is saying that not only did + // we get change back that exceeded the amount that was put + // in, but that the change we got back was so large that it + // lead us to underflow. + .expect(OVERFLOW_ERROR); + + // Determine the amount of upfront tokens to provide to the user + // based on the lockup period specified. + let upfront_rewards_amount_in_protocol_resource = { + let oracle_reported_value_of_user_resource_actually_contributed_in_protocol_resource = + oracle_reported_price + .exchange( + user_resource_address, + amount_of_user_tokens_contributed, + ) + .expect(UNEXPECTED_ERROR) + .1; + + let associated_rewards_rate = self + .reward_rates + .get(&lockup_period) + .expect(LOCKUP_PERIOD_HAS_NO_ASSOCIATED_REWARDS_RATE_ERROR); + + oracle_reported_value_of_user_resource_actually_contributed_in_protocol_resource + .checked_mul(*associated_rewards_rate) + .expect(OVERFLOW_ERROR) + }; + + let upfront_reward = self.withdraw_protocol_resources( + upfront_rewards_amount_in_protocol_resource, + WithdrawStrategy::Rounded(RoundingMode::ToZero), + volatility, + ); + + // Deposit the pool units into the protocol itself and mint an NFT + // used to represent these locked pool units. + let liquidity_receipt = { + let data = LiquidityReceipt::new( + lockup_period, + pool_address, + user_resource_address, + amount_of_user_tokens_contributed, + volatility, + amount_of_protocol_tokens_contributed, + adapter_specific_information, + ); + let liquidity_receipt = liquidity_receipt_resource + .mint_ruid_non_fungible(data) + .as_non_fungible(); + + let global_id = NonFungibleGlobalId::new( + liquidity_receipt_resource.address(), + liquidity_receipt.non_fungible_local_id(), + ); + self.pool_units + .insert(global_id, Vault::with_bucket(pool_units)); + + liquidity_receipt + }; + + // Create the buckets to return back to the user. + if let Some(bucket) = + change.remove(&self.protocol_resource.address()) + { + self.deposit_protocol_resources( + FungibleBucket(bucket), + volatility, + ) + } + let buckets_to_return = + change.into_values().chain(others).collect(); + + // Return all + (liquidity_receipt, upfront_reward, buckets_to_return) + } + + /// Closes a liquidity position after its maturity period has elapsed. + /// + /// Given the non-fungible representing the liquidity receipt, this + /// method closes the liquidity position after the maturity period + /// elapses. The liquidity receipt is burned and the user is given + /// back some amount of assets. If the user has been forcefully + /// liquidated by the owner of the protocol then the amount returned + /// will be the amount they were owed at liquidation time. + /// + /// # Arguments + /// + /// `liquidity_receipt`: [`NonFungibleBucket`] - A bucket of the non + /// fungible liquidity receipt. + /// + /// # Returns + /// + /// [`Vec`] - A vector of buckets of the amount to give back to + /// the user. + pub fn close_liquidity_position( + &mut self, + liquidity_receipt: NonFungibleBucket, + ) -> Vec { + // Ensure that there is only a single NFT in the bucket, we do not + // service more than a single one at a time. + assert_eq!( + liquidity_receipt.amount(), + Decimal::ONE, + "{}", + MORE_THAN_ONE_LIQUIDITY_RECEIPT_NFTS_ERROR + ); + + // At this point it is safe to get the non-fungible global id of the + // liquidity receipt NFT. + let liquidity_receipt_global_id = liquidity_receipt + .non_fungible::>() + .global_id() + .clone(); + + // If the passed non-fungible is found in the KVStore of liquidity + // claims then it has been forcefully closed and it can be claimed + // from there. + let entry = self + .forced_liquidation_claims + .get_mut(&liquidity_receipt_global_id); + if let Some(mut vaults) = entry { + // The liquidity receipt is no longer needed and can be burned. + liquidity_receipt.burn(); + + // Take all of the funds in the vaults and return them back to + // the user. + vaults.iter_mut().map(Vault::take_all).collect() + } + // There is no entry in the forced liquidations for this receipt. So + // we can close it. + else { + drop(entry); + + // A liquidity position can only be closed when the closing + // period is opened. Otherwise, it can't be. However, this + // does not apply for claiming already liquidated positions. + assert!( + self.is_close_position_enabled, + "{}", + CLOSING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR + ); + + let buckets = self.liquidate(liquidity_receipt_global_id); + + // The liquidity receipt is no longer needed and can be burned. + liquidity_receipt.burn(); + + buckets + } + } + + /// Forcefully liquidates a liquidity position keeping the resources + /// in a separate claims KVStore such that users can claim them at any + /// point of time. + /// + /// # Arguments + /// + /// `liquidity_receipt_global_id`: [`NonFungibleGlobalId`] - The non + /// fungible global id of liquidity receipt to liquidate. + pub fn forcefully_liquidate( + &mut self, + liquidity_receipt_global_id: NonFungibleGlobalId, + ) { + let buckets = self.liquidate(liquidity_receipt_global_id.clone()); + self.forced_liquidation_claims.insert( + liquidity_receipt_global_id, + buckets.into_iter().map(Vault::with_bucket).collect(), + ); + } + + /// Liquidates a liquidity position after its maturity period has + /// elapsed. + /// + /// Given the non-fungible representing the liquidity receipt, this + /// method closes the liquidity position after the maturity period + /// elapses. The liquidity receipt is burned and the user is given + /// back some amount of assets. + /// + /// The assets given back to the user depends on what the protocol gets + /// back from closing the liquidity position. The following is the + /// algorithm employed to determine what and how much should be returned + /// + /// * Is the amount of the user asset the protocol got back greater than + /// or equal to the amount that they initially put in? + /// * Yes: Return the same amount to them plus any fees from the + /// _user_ asset. + /// * No: Return to them all of the user asset the protocol got back + /// plus the amount required to buy back their missing amount or the + /// protocol assets returned when closing the liquidity position, + /// whichever one is smaller. + /// + /// Whatever the amount obtained from the algorithm defined at the top + /// is the amount returned to the user. Some of the calculations take + /// place in the adapters: specifically the estimation of fees. + /// + /// # Arguments + /// + /// `liquidity_receipt_global_id`: [`NonFungibleGlobalId`] - The non + /// fungible global id of liquidity receipt to liquidate. + /// + /// # Returns + /// + /// [`Vec`] - A vector of buckets of the amount to give back to + /// the user. + fn liquidate( + &mut self, + liquidity_receipt_global_id: NonFungibleGlobalId, + ) -> Vec { + let ( + mut adapter, + liquidity_receipt_data, + liquidity_receipt_global_id, + ) = { + // Reading the data of the non-fungible resource passed and then + // validating that the resource address is what we expect. We do + // this as we need to check it against the data of the blueprint + // of the pool. So, that must be read first. + let non_fungible = + NonFungible::>::from( + liquidity_receipt_global_id, + ); + let liquidity_receipt_data = non_fungible.data(); + let (pool_adapter, liquidity_receipt_resource, _, _) = self + .checked_get_pool_adapter_information( + liquidity_receipt_data.pool_address, + ) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR); + + assert_eq!( + non_fungible.resource_address(), + liquidity_receipt_resource.address(), + "{}", + NOT_A_VALID_LIQUIDITY_RECEIPT_ERROR + ); + + // At this point, the non-fungible can be trusted to belong to + // the liquidity receipt resource of the blueprint. + ( + pool_adapter, + liquidity_receipt_data, + non_fungible.global_id().clone(), + ) + }; + + // Assert that we're after the maturity date. + assert!( + Clock::current_time_is_at_or_after( + liquidity_receipt_data.maturity_date, + TimePrecision::Minute + ), + "{}", + LIQUIDITY_POSITION_HAS_NOT_MATURED_ERROR + ); + + // Compare the price difference between the oracle reported price + // and the pool reported price - ensure that it is within the + // allowed price difference range. + let oracle_reported_price = { + let oracle_reported_price = self.checked_get_price( + liquidity_receipt_data.user_resource_address, + self.protocol_resource.address(), + ); + let pool_reported_price = + adapter.price(liquidity_receipt_data.pool_address); + let relative_difference = oracle_reported_price + .relative_difference(&pool_reported_price) + .expect(USER_ASSET_DOES_NOT_BELONG_TO_POOL_ERROR); + + assert!( + relative_difference + <= self.maximum_allowed_price_difference_percentage, + "{}", + RELATIVE_PRICE_DIFFERENCE_LARGER_THAN_ALLOWED_ERROR + ); + + oracle_reported_price + }; + + /* The liquidity position can be closed! */ + + // Withdraw all of the pool units associated with the position and + // close it through the adapter. + let CloseLiquidityPositionOutput { + resources, + others, + mut fees, + } = { + let pool_units = self + .pool_units + .get_mut(&liquidity_receipt_global_id) + .expect(UNEXPECTED_ERROR) + .take_all(); + adapter.close_liquidity_position( + liquidity_receipt_data.pool_address, + pool_units, + liquidity_receipt_data.adapter_specific_information, + ) + }; + + let (mut user_resource_bucket, mut protocol_resource_bucket) = { + let user_resource = resources + .get(&liquidity_receipt_data.user_resource_address) + .map(|item| Bucket(item.0)) + .expect(UNEXPECTED_ERROR); + let protocol_resource = resources + .get(&self.protocol_resource.address()) + .map(|item| Bucket(item.0)) + .expect(UNEXPECTED_ERROR); + drop(resources); + (user_resource, protocol_resource) + }; + + let user_resource_bucket_amount = user_resource_bucket.amount(); + let protocol_resource_bucket_amount = + protocol_resource_bucket.amount(); + + fees.values_mut().for_each(|value| { + // Disallowing any fees from being zero by having a lower bound + // at 0. This is enforced by the protocol itself such that any + // adapter that returns any negative fees due to estimations + // does not cause the protocol to calculate incorrectly. + *value = max(*value, Decimal::ZERO) + }); + let (user_resource_fees, _) = { + let user_resource = fees + .get(&liquidity_receipt_data.user_resource_address) + .copied() + .unwrap_or(Decimal::ZERO); + let protocol_resource = fees + .get(&self.protocol_resource.address()) + .copied() + .unwrap_or(Decimal::ZERO); + drop(fees); + (user_resource, protocol_resource) + }; + + // Determine the amount of resources that the user should be given + // back. + // + // Branch 1: There is enough of the user asset to give the user back + // the same amount that they put in. + let ( + amount_of_protocol_resource_to_give_user, + amount_of_user_resource_to_give_user, + ) = if user_resource_bucket_amount + >= liquidity_receipt_data.user_contribution_amount + { + let amount_of_protocol_resource_to_give_user = dec!(0); + let amount_of_user_resource_to_give_user = min( + user_resource_bucket_amount, + liquidity_receipt_data + .user_contribution_amount + .checked_add(user_resource_fees) + .expect(OVERFLOW_ERROR), + ); + + ( + amount_of_protocol_resource_to_give_user, + amount_of_user_resource_to_give_user, + ) + } + // Branch 2: There is not enough of the user token to given them + // back the same amount that they put in. + else { + let amount_of_protocol_resource_to_give_user = { + let user_amount_missing = liquidity_receipt_data + .user_contribution_amount + .checked_sub(user_resource_bucket_amount) + .expect(OVERFLOW_ERROR); + let (_, protocol_resources_required_for_buy_back) = + oracle_reported_price + .exchange( + liquidity_receipt_data.user_resource_address, + user_amount_missing, + ) + .expect(UNEXPECTED_ERROR); + min( + protocol_resources_required_for_buy_back, + protocol_resource_bucket_amount, + ) + }; + let amount_of_user_resource_to_give_user = + user_resource_bucket_amount; + + ( + amount_of_protocol_resource_to_give_user, + amount_of_user_resource_to_give_user, + ) + }; + + let mut bucket_returns = others; + bucket_returns.push(user_resource_bucket.take_advanced( + amount_of_user_resource_to_give_user, + WithdrawStrategy::Rounded(RoundingMode::ToZero), + )); + bucket_returns.push(protocol_resource_bucket.take_advanced( + amount_of_protocol_resource_to_give_user, + WithdrawStrategy::Rounded(RoundingMode::ToZero), + )); + + // Deposit the remaining resources back into the protocol. + self.deposit_user_resources(user_resource_bucket.as_fungible()); + self.deposit_protocol_resources( + protocol_resource_bucket.as_fungible(), + liquidity_receipt_data.user_resource_volatility_classification, + ); + + // Return the buckets back + bucket_returns + } + + /// Updates the oracle adapter used by the protocol to a different + /// adapter. + /// + /// This method does _not_ check that the interface of the new oracle + /// matches that we expect. Thus, such a check must be performed + /// off-ledger. + /// + /// To be more specific, this method takes in the component address of + /// the oracle's _adapter_ and not the oracle itself. The adapter must + /// have the interface defined in [`OracleAdapter`]. + /// + /// # Example Scenario + /// + /// We may wish to change the oracle provider for any number of reasons. + /// As an example, imagine if the initial oracle provider goes under and + /// stops operations. This allows for the oracle to be replaced with one + /// that has the same interface without the need to jump to a new + /// component. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Arguments + /// + /// * `oracle`: [`ComponentAddress`] - The address of the new oracle + /// component to use. + /// + /// # Note + /// + /// This performs no interface checks and can theoretically accept the + /// address of a component that does not implement the oracle interface. + pub fn set_oracle_adapter(&mut self, oracle_adapter: ComponentAddress) { + self.oracle_adapter = oracle_adapter.into(); + } + + /// Sets the pool adapter that should be used by a pools belonging to a + /// particular blueprint. + /// + /// Given the blueprint id of a pool whose information is already known + /// to the protocol, this method changes it to use a new adapter instead + /// of its existing one. All future opening and closing of liquidity + /// positions happens through the new adapter. + /// + /// This method does not check that the provided adapter conforms to the + /// [`PoolAdapter`] interface. It is the job of the caller to perform + /// this check off-ledger. + /// + /// # Panics + /// + /// This function panics in the following cases: + /// + /// * If the provided address's blueprint has no corresponding + /// blueprint. + /// + /// # Example Scenario + /// + /// We may wish to add support for additional decentralized exchanges + /// after the protocol goes live. To do this, we would just need to + /// develop and deploy an adapter and then register the adapter to the + /// protocol through this method. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Arguments + /// + /// `blueprint_id`: [`BlueprintId`] - The package address and blueprint + /// name of the pool blueprint. + /// `pool_adapter`: [`ComponentAddress`] - The address of the adapter + /// component. + /// + /// # Note + /// + /// This performs no interface checks and can theoretically accept the + /// address of a component that does not implement the oracle interface. + pub fn set_pool_adapter( + &mut self, + blueprint_id: BlueprintId, + pool_adapter: ComponentAddress, + ) { + self.pool_information + .get_mut(&blueprint_id) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR) + .adapter = pool_adapter.into(); + } + + /// Adds an allowed pool to the protocol. + /// + /// This protocol does not provide an incentive to any liquidity pool. + /// Only a small set of pools that are chosen by the pool manager. This + /// method adds a pool to the set of pools that the protocol provides an + /// incentive for and that users can provide liquidity to. + /// + /// This method checks that an adapter exists for the passed component. + /// If no adapter exists then this method panics and the transaction + /// fails. + /// + /// # Panics + /// + /// This function panics in two main cases: + /// + /// * If the provided address's blueprint has no corresponding + /// blueprint. + /// * If neither side of the pool is the protocol resource. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Example Scenario + /// + /// We may wish to incentivize liquidity for a new bridged resource and + /// a new set of pools. An even more compelling scenario, we may wish to + /// provide incentives for a newly released DEX. + /// + /// # Arguments + /// + /// * `component`: [`ComponentAddress`] - The address of the pool + /// component to add to the set of allowed pools. + pub fn add_allowed_pool(&mut self, pool_address: ComponentAddress) { + let protocol_resource_address = self.protocol_resource.address(); + let user_resource_volatility = KeyValueStore { + id: self.user_resource_volatility.id, + key: PhantomData, + value: PhantomData, + }; + + self.with_pool_blueprint_information_mut( + pool_address, + |pool_information| { + let resources = PoolAdapter::from(pool_information.adapter) + .resource_addresses(pool_address); + + Self::check_pool_resources( + resources, + protocol_resource_address, + &user_resource_volatility, + ); + + pool_information + .allowed_pools + .insert(pool_address, resources); + }, + ) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR) + } + + /// Removes one of the existing allowed liquidity pools. + /// + /// Given the component address of the liquidity pool, this method + /// removes that liquidity pool from the list of allowed liquidity + /// pools. + /// + /// # Panics + /// + /// This function panics in the following cases: + /// + /// * If the provided address's blueprint has no corresponding + /// blueprint. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Example Scenario + /// + /// We may wish to to remove or stop a certain liquidity pool from the + /// incentive program essentially disallowing new liquidity positions + /// but permitting closure of liquidity positions. + /// + /// # Arguments + /// + /// * `component`: [`ComponentAddress`] - The address of the pool + /// component to remove from the set of allowed pools. + pub fn remove_allowed_pool(&mut self, pool_address: ComponentAddress) { + self.with_pool_blueprint_information_mut( + pool_address, + |pool_information| { + pool_information.allowed_pools.remove(&pool_address); + }, + ) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR) + } + + /// Sets the liquidity receipt resource associated with a particular + /// pool blueprint. + /// + /// # Panics + /// + /// This function panics in the following cases: + /// + /// * If the provided address's blueprint has no corresponding + /// blueprint. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Arguments + /// + /// `blueprint_id`: [`BlueprintId`] - The blueprint id of the pool + /// blueprint. + /// `liquidity_receipt``: [`ResourceManager`] - The resource address of + /// the new liquidity receipt resource to use. + pub fn set_liquidity_receipt( + &mut self, + blueprint_id: BlueprintId, + liquidity_receipt: ResourceManager, + ) { + self.pool_information + .get_mut(&blueprint_id) + .expect(NO_ADAPTER_FOUND_FOR_POOL_ERROR) + .liquidity_receipt = liquidity_receipt.address(); + } + + /// Inserts the pool information, adding it to the protocol, performing + /// an upsert. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Arguments + /// + /// * `blueprint_id`: [`BlueprintId`] - The id of the pool blueprint + /// to add the information for. + /// * `PoolBlueprintInformation`: [`PoolBlueprintInformation`] The + /// protocol information related to the blueprint. + pub fn insert_pool_information( + &mut self, + blueprint_id: BlueprintId, + pool_information: PoolBlueprintInformation, + ) { + let protocol_resource_address = self.protocol_resource.address(); + let pool_information = StoredPoolBlueprintInformation { + adapter: PoolAdapter::from(pool_information.adapter), + liquidity_receipt: pool_information.liquidity_receipt, + allowed_pools: pool_information + .allowed_pools + .into_iter() + .map(|pool_component_address| { + let mut adapter = + PoolAdapter::from(pool_information.adapter); + + let resources = + adapter.resource_addresses(pool_component_address); + + Self::check_pool_resources( + resources, + protocol_resource_address, + &self.user_resource_volatility, + ); + + (pool_component_address, resources) + }) + .collect(), + }; + + self.pool_information.insert(blueprint_id, pool_information) + } + + /// Removes the pool's blueprint information from the protocol. + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Arguments + /// + /// * `blueprint_id`: [`BlueprintId`] - The id of the pool blueprint + /// to remove the information for. + pub fn remove_pool_information(&mut self, blueprint_id: BlueprintId) { + self.pool_information.remove(&blueprint_id); + } + + /// Deposits protocol resources into the appropriate vaults. + /// + /// Depending on whether the protocol resources deposited are to be used + /// for volatile or non-volatile contributions this method deposits them + /// into the appropriate vaults. + /// + /// # Access + /// + /// Requires the `protocol_owner` roles. + /// + /// # Arguments + /// + /// * `bucket`: [`FungibleBucket`] - A bucket of the protocol resources + /// to deposit into the protocol, making them available to the protocol + /// to be used in matching the contribution of users. + /// * `volatility`: [`Volatility`] - Whether the resources are to be + /// used for matching volatile or non-volatile user assets. + pub fn deposit_protocol_resources( + &mut self, + bucket: FungibleBucket, + volatility: Volatility, + ) { + self.protocol_resource_reserves.deposit(bucket, volatility) + } + + /// Withdraws protocol resources from the protocol. + /// + /// Withdraws the specified amount from the appropriate vault which is + /// either that of the volatile or non-volatile contributions. + /// + /// # Access + /// + /// Requires the `protocol_owner` roles. + /// + /// # Arguments + /// + /// * `amount`: [`Decimal`] - The amount of resources to withdraw. + /// * `withdraw_strategy`: [`WithdrawStrategy`] - The strategy to use + /// when withdrawing. This is only relevant when the protocol resource's + /// divisibility is not 18. If it is 18, then this does not really make + /// any difference. + /// * `volatility`: [`Volatility`] - Controls whether the withdraw + /// should happen against the volatile or non-volatile vaults. + /// + /// # Returns + /// + /// * [`FungibleBucket`] - A bucket of the fungible protocol resources + /// withdrawn from the protocol. + pub fn withdraw_protocol_resources( + &mut self, + amount: Decimal, + withdraw_strategy: WithdrawStrategy, + volatility: Volatility, + ) -> FungibleBucket { + self.protocol_resource_reserves.withdraw( + amount, + withdraw_strategy, + volatility, + ) + } + + /// Deposits resources into the protocol. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Example Scenario + /// + /// This method can be used to fund the incentive program with XRD and + /// deposit other resources as well. + /// + /// # Arguments + /// + /// * `bucket`: [`FungibleBucket`] - A bucket of resources to deposit + /// into the protocol. + pub fn deposit_user_resources(&mut self, bucket: FungibleBucket) { + let entry = self + .user_resources_vaults + .get_mut(&bucket.resource_address()); + if let Some(mut vault) = entry { + vault.put(bucket); + } else { + drop(entry); + self.user_resources_vaults.insert( + bucket.resource_address(), + FungibleVault::with_bucket(bucket), + ) + } + } + + /// Withdraws resources from the protocol. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Example Scenario + /// + /// This method can be used to end the incentive program by withdrawing + /// the XRD in the protocol. Additionally, it can be used for upgrading + /// the protocol by withdrawing the resources in the protocol. + /// + /// # Arguments + /// + /// * `resource_address`: [`ResourceAddress`] - The address of the + /// resource to withdraw. + /// * `amount`: [`Decimal`] - The amount to withdraw. + /// + /// # Returns + /// + /// * [`FungibleBucket`] - A bucket of the withdrawn tokens. + pub fn withdraw_user_resources( + &mut self, + resource_address: ResourceAddress, + amount: Decimal, + ) -> FungibleBucket { + self.user_resources_vaults + .get_mut(&resource_address) + .expect(NO_ASSOCIATED_VAULT_ERROR) + .take(amount) + } + + /// Deposits pool units into the protocol. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Arguments + /// + /// * `global_id`: [`NonFungibleGlobalId`] - The global id of the + /// non-fungible liquidity position NFT whose associated pool units + /// are to be deposited. + /// * `pool_units`: [`Bucket`] - The pool units to deposit into the + /// protocol. + pub fn deposit_pool_units( + &mut self, + global_id: NonFungibleGlobalId, + pool_units: Bucket, + ) { + let entry = self.pool_units.get_mut(&global_id); + if let Some(mut vault) = entry { + vault.put(pool_units); + } else { + drop(entry); + self.pool_units + .insert(global_id, Vault::with_bucket(pool_units)) + } + } + + /// Withdraws pool units from the protocol. This is primarily for any + /// upgradeability needs that the protocol has. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Example Scenario + /// + /// This method can be used to withdraw the pool units from the protocol + /// for the purposes of upgradeability to move them to another component + /// + /// # Arguments + /// + /// * `id`: [`NonFungibleGlobalId`] - The global id of the non-fungible + /// liquidity position NFTs to withdraw the pool units associated with. + /// + /// # Returns + /// + /// * [`Bucket`] - A bucket of the withdrawn tokens. + pub fn withdraw_pool_units( + &mut self, + global_id: NonFungibleGlobalId, + ) -> Bucket { + self.pool_units + .get_mut(&global_id) + .expect(NO_ASSOCIATED_LIQUIDITY_RECEIPT_VAULT_ERROR) + .take_all() + } + + /// Updates the value of the maximum allowed price staleness used by + /// the protocol. + /// + /// This means that any price checks that happen when opening or closing + /// liquidity positions will be subjected to the new maximum allowed + /// staleness. + /// + /// # Access + /// + /// Requires the `protocol_owner` or `protocol_manager` role. + /// + /// # Example Scenario + /// + /// We may wish to change the allowed staleness of prices to a very + /// short period if we get an oracle that operates at realtime speeds + /// or if we change oracle vendors. + /// + /// # Arguments + /// + /// * `value`: [`i64`] - The maximum allowed staleness period in + /// seconds. + pub fn set_maximum_allowed_price_staleness(&mut self, value: i64) { + self.maximum_allowed_price_staleness = value + } + + /// Adds a rewards rate to the protocol. + /// + /// Given a certain lockup period in seconds and a percentage rewards + /// rate, this method adds this rate to the protocol allowing users to + /// choose this option when contributing liquidity. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Example Scenario + /// + /// We might wish to add a new higher rate with a longer lockup period + /// to incentivize people to lock up their liquidity for even shorter. + /// Or, we might want to introduce a new 3 months category, or anything + /// in between. + /// + /// # Arguments + /// + /// * `lockup_period`: [`LockupPeriod`] - The lockup period. + /// * `rate`: [`Decimal`] - The rewards rate as a percent. This is a + /// percentage value where 0 represents 0%, 0.5 represents 50% and 1 + /// represents 100%. + pub fn add_reward_rate( + &mut self, + lockup_period: LockupPeriod, + percentage: Decimal, + ) { + self.reward_rates.insert(lockup_period, percentage) + } + + /// Removes a rewards rate from the protocol. + /// + /// # Access + /// + /// Requires the `protocol_owner` role. + /// + /// # Example Scenario + /// + /// A certain rate might get used too much and we might want to switch + /// off this rate (even if temporarily). This allows us to remove this + /// rate and add it back later when we want to. + /// + /// # Arguments + /// + /// * `lockup_period`: [`LockupPeriod`] - The lockup period in seconds + /// associated with the rewards rate that we would like to remove. + pub fn remove_reward_rate(&mut self, lockup_period: LockupPeriod) { + self.reward_rates.remove(&lockup_period); + } + + /// Inserts the volatility of the user resource to the protocol. + /// + /// # Arguments + /// + /// * `resource_address`: [`ResourceAddress`] - The address of the + /// resource to add a volatility classification for. + /// * `volatility`: [`Volatility`] - The volatility classification of + /// the resource. + pub fn insert_user_resource_volatility( + &mut self, + resource_address: ResourceAddress, + volatility: Volatility, + ) { + self.user_resource_volatility + .insert(resource_address, volatility) + } + + /// Enables or disables the ability to open new liquidity positions + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Example Scenario + /// + /// We might want to pause the incentive program for some period due to + /// any number of reasons. + /// + /// # Arguments + /// + /// * `value`: [`bool`] - Controls whether opening of liquidity + /// positions is enabled or disabled. + pub fn set_is_open_position_enabled(&mut self, value: bool) { + self.is_open_position_enabled = value + } + + /// Enables or disables the ability to close new liquidity positions + /// + /// # Access + /// + /// Requires the `protocol_manager` or `protocol_owner` roles. + /// + /// # Example Scenario + /// + /// We might want to pause the incentive program for some period due to + /// any number of reasons. + /// + /// # Arguments + /// + /// * `value`: [`bool`] - Controls whether closing of liquidity + /// positions is enabled or disabled. + pub fn set_is_close_position_enabled(&mut self, value: bool) { + self.is_close_position_enabled = value + } + + /// Updates the value of the maximum allowed price difference between + /// the pool and the oracle. + /// + /// # Access + /// + /// Requires the `protocol_owner` or `protocol_manager` role. + /// + /// # Example Scenario + /// + /// As more and more arbitrage bots get created, we may want to make the + /// price difference allowed narrower and narrower. + /// + /// # Arguments + /// + /// `value`: [`Decimal`] - The maximum allowed percentage difference. + /// This is a percentage value where 0 represents 0%, 0.5 represents + /// 50% and 1 represents 100%. + pub fn set_maximum_allowed_price_difference_percentage( + &mut self, + value: Decimal, + ) { + self.maximum_allowed_price_difference_percentage = value + } + + /* Getters */ + pub fn get_user_resource_reserves_amount( + &self, + resource_address: ResourceAddress, + ) -> Decimal { + self.user_resources_vaults + .get(&resource_address) + .map(|vault| vault.amount()) + .unwrap_or_default() + } + + pub fn get_protocol_resource_reserves_amount( + &self, + volatility: Volatility, + ) -> Decimal { + self.protocol_resource_reserves.vault(volatility).amount() + } + + /// An internal method that is used to execute callbacks against the + /// blueprint of some pool. + fn with_pool_blueprint_information_mut( + &mut self, + pool_address: ComponentAddress, + callback: F, + ) -> Option + where + F: FnOnce( + &mut KeyValueEntryRefMut<'_, StoredPoolBlueprintInformation>, + ) -> O, + { + let blueprint_id = ScryptoVmV1Api::object_get_blueprint_id( + pool_address.as_node_id(), + ); + let entry = self.pool_information.get_mut(&blueprint_id); + entry.map(|mut entry| callback(&mut entry)) + } + + /// Gets the adapter and the liquidity receipt given a pool address. + /// + /// This method first gets the pool information associated with the pool + /// blueprint and then checks to ensure that the pool is in the allow + /// list of pools. If it is, it returns the adapter and the resource + /// manager reference of the liquidity receipt. + /// + /// If a [`None`] is returned it means that no pool information was + /// found for the pool and that it has no corresponding adapter that + /// we can use. + /// + /// # Panics + /// + /// * If the pool is not in the list of allowed pools. + /// + /// # Arguments + /// + /// `pool_address`: [`ComponentAddress`] - The address of the component + /// to get the adapter and liquidity receipt for. + /// + /// # Returns + /// + /// * [`PoolAdapter`] - The adapter to use for the pool. + /// * [`ResourceManager`] - The resource manager reference of the + /// liquidity receipt token. + /// * [`(ResourceAddress, ResourceAddress)`] - A tuple of the resource + /// addresses of the pool. + /// + /// # Note + /// + /// The [`KeyValueEntryRef<'_, PoolBlueprintInformation>`] is returned + /// to allow the references of the addresses to remain. + fn checked_get_pool_adapter_information( + &self, + pool_address: ComponentAddress, + ) -> Option<( + PoolAdapter, + ResourceManager, + (ResourceAddress, ResourceAddress), + KeyValueEntryRef<'_, StoredPoolBlueprintInformation>, + )> { + let blueprint_id = ScryptoVmV1Api::object_get_blueprint_id( + pool_address.as_node_id(), + ); + let entry = self.pool_information.get(&blueprint_id); + + entry.map(|entry| { + let resources = entry + .allowed_pools + .get(&pool_address) + .expect(POOL_IS_NOT_IN_ALLOW_LIST_ERROR); + + (entry.adapter, entry.liquidity_receipt(), *resources, entry) + }) + } + + /// Gets the price of the `base` resource in terms of the `quote` + /// resource from the currently configured oracle, checks for + /// staleness, and returns the price. + /// + /// # Arguments + /// + /// * `base`: [`ResourceAddress`] - The base resource address. + /// * `quote`: [`ResourceAddress`] - The quote resource address. + /// + /// # Returns + /// + /// [`Price`] - The price of the base resource in terms of the quote + /// resource. + fn checked_get_price( + &self, + base: ResourceAddress, + quote: ResourceAddress, + ) -> Price { + // Get the price + let (price, last_update) = + self.oracle_adapter.get_price(base, quote); + let final_price_validity = last_update + .add_seconds(self.maximum_allowed_price_staleness) + .unwrap_or(Instant::new(i64::MAX)); + + // Check for staleness + assert!( + Clock::current_time_is_at_or_before( + final_price_validity, + TimePrecision::Minute + ), + "{}", + ORACLE_REPORTED_PRICE_IS_STALE_ERROR + ); + + // Return price + Price { price, base, quote } + } + + fn check_pool_resources( + resources: (ResourceAddress, ResourceAddress), + protocol_resource_address: ResourceAddress, + user_resource_volatility: &KeyValueStore< + ResourceAddress, + Volatility, + >, + ) { + // Ensure that one of the resources is the protocol resource. + assert!( + resources.0 == protocol_resource_address + || resources.1 == protocol_resource_address, + "{}", + NEITHER_POOL_RESOURCE_IS_PROTOCOL_RESOURCE_ERROR + ); + + // Ensure that the user asset has a registered volatility. + let user_resource = if resources.0 == protocol_resource_address { + resources.1 + } else if resources.1 == protocol_resource_address { + resources.0 + } else { + unreachable!("{}", NEITHER_POOL_RESOURCE_IS_USER_RESOURCE_ERROR) + }; + + // Ensure that the user's resource is not the protocol resource. + // A pool whose two assets is the same is an issue. + assert_ne!( + user_resource, protocol_resource_address, + "{}", + BOTH_POOL_ASSETS_ARE_THE_PROTOCOL_RESOURCE + ); + + user_resource_volatility + .get(&user_resource) + .expect(USER_RESOURCES_VOLATILITY_UNKNOWN_ERROR); + } + } +} + +/// Represents the information of pools belonging to a particular blueprint that +/// the Ignition component stores in its state. This type is not public as it +/// does not need to be. +#[derive(Clone, Debug, PartialEq, Eq, ScryptoSbor, ManifestSbor)] +struct StoredPoolBlueprintInformation { + /// The adapter to utilize when making calls to pools belonging to this + /// blueprint. + pub adapter: PoolAdapter, + + /// A map of the pools that the protocol allows contributions to. A pool + /// that is not found in this map for their corresponding blueprint will + /// not be allowed to be contributed to. The value in this map is the + pub allowed_pools: + IndexMap, + + /// A reference to the resource manager of the resource used as a receipt + /// for providing liquidity to pools of this blueprint + pub liquidity_receipt: ResourceAddress, +} + +/// Represents the information of pools belonging to a particular blueprint. +#[derive(Clone, Debug, PartialEq, Eq, ScryptoSbor, ManifestSbor)] +pub struct PoolBlueprintInformation { + /// The adapter to utilize when making calls to pools belonging to this + /// blueprint. + pub adapter: ComponentAddress, + + /// A vector of the pools that the protocol allows contributions to. A pool + /// that is not found in this list for their corresponding blueprint will + /// not be allowed to be contributed to. + pub allowed_pools: IndexSet, + + /// A reference to the resource manager of the resource used as a receipt + /// for providing liquidity to pools of this blueprint + pub liquidity_receipt: ResourceAddress, +} + +impl StoredPoolBlueprintInformation { + pub fn liquidity_receipt(&self) -> ResourceManager { + ResourceManager::from(self.liquidity_receipt) + } +} + +/// The reserves of the ignition protocol asset split by the assets to use in +/// volatile and non-volatile contributions. +#[derive(Debug, PartialEq, Eq, ScryptoSbor)] +pub struct ProtocolResourceReserves { + /// A fungible vault of the protocol asset used for matching contributions + /// to pools of volatile assets. + pub volatile: FungibleVault, + /// A fungible vault of the protocol asset used for matching contributions + /// to pools of non volatile assets. + pub non_volatile: FungibleVault, +} + +impl ProtocolResourceReserves { + pub fn new(protocol_resource_address: ResourceAddress) -> Self { + Self { + volatile: FungibleVault::new(protocol_resource_address), + non_volatile: FungibleVault::new(protocol_resource_address), + } + } + + pub fn withdraw( + &mut self, + amount: Decimal, + withdraw_strategy: WithdrawStrategy, + volatility: Volatility, + ) -> FungibleBucket { + self.vault_mut(volatility) + .take_advanced(amount, withdraw_strategy) + } + + pub fn deposit(&mut self, bucket: FungibleBucket, volatility: Volatility) { + self.vault_mut(volatility).put(bucket) + } + + fn vault_mut(&mut self, volatility: Volatility) -> &mut FungibleVault { + match volatility { + Volatility::Volatile => &mut self.volatile, + Volatility::NonVolatile => &mut self.non_volatile, + } + } + + fn vault(&self, volatility: Volatility) -> &FungibleVault { + match volatility { + Volatility::Volatile => &self.volatile, + Volatility::NonVolatile => &self.non_volatile, + } + } +} + +/// Optional parameters to set on Ignition when its first instantiated. All of +/// the items here are not required to be provided when ignition is first +/// created, but providing them this way saves on fees. +#[derive(Debug, PartialEq, Eq, ScryptoSbor, Default)] +pub struct InitializationParameters { + /// The initial set of pool information to add to to Ignition. + pub initial_pool_information: + Option>, + + /// The initial volatility settings to add to Ignition. + pub initial_user_resource_volatility: + Option>, + + /// The initial set of reward rates to add to Ignition. + pub initial_reward_rates: Option>, + + /// The initial volatile protocol resources to deposit into that vault. + pub initial_volatile_protocol_resources: Option, + + /// The initial non volatile protocol resources to deposit into that vault. + pub initial_non_volatile_protocol_resources: Option, + + /// The initial control of whether the user is allowed to open a liquidity + /// position or not. Defaults to [`false`] if not specified. + pub initial_is_open_position_enabled: Option, + + /// The initial control of whether the user is allowed to close a liquidity + /// position or not. Defaults to [`false`] if not specified. + pub initial_is_close_position_enabled: Option, +} + +#[derive(Debug, PartialEq, Eq, ManifestSbor, Default)] +pub struct InitializationParametersManifest { + /// The initial set of pool information to add to to Ignition. + pub initial_pool_information: + Option>, + + /// The initial volatility settings to add to Ignition. + pub initial_user_resource_volatility: + Option>, + + /// The initial set of reward rates to add to Ignition. + pub initial_reward_rates: Option>, + + /// The initial volatile protocol resources to deposit into that vault. + pub initial_volatile_protocol_resources: Option, + + /// The initial non volatile protocol resources to deposit into that vault. + pub initial_non_volatile_protocol_resources: Option, + + /// The initial control of whether the user is allowed to open a liquidity + /// position or not. Defaults to [`false`] if not specified. + pub initial_is_open_position_enabled: Option, + + /// The initial control of whether the user is allowed to close a liquidity + /// position or not. Defaults to [`false`] if not specified. + pub initial_is_close_position_enabled: Option, +} diff --git a/packages/ignition/src/errors.rs b/packages/ignition/src/errors.rs new file mode 100644 index 00000000..8d424313 --- /dev/null +++ b/packages/ignition/src/errors.rs @@ -0,0 +1,57 @@ +macro_rules! define_error { + ( + $( + $name: ident => $item: expr; + )* + ) => { + $( + pub const $name: &'static str = concat!("[Ignition]", " ", $item); + )* + }; +} + +define_error! { + NO_ADAPTER_FOUND_FOR_POOL_ERROR + => "No adapter found for liquidity pool."; + NEITHER_POOL_RESOURCE_IS_PROTOCOL_RESOURCE_ERROR + => "Neither pool resource is the protocol resource."; + NEITHER_POOL_RESOURCE_IS_USER_RESOURCE_ERROR + => "Neither pool resource is the user resource."; + NO_ASSOCIATED_VAULT_ERROR + => "The resource has no associated vault in the protocol."; + NO_ASSOCIATED_LIQUIDITY_RECEIPT_VAULT_ERROR + => "The liquidity receipt has no associated vault in the protocol."; + NOT_AN_IGNITION_ADDRESS_ERROR + => "The passed allocated address is not an ignition address."; + OPENING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR + => "Opening liquidity positions is disabled."; + CLOSING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR + => "Closing liquidity positions is disabled."; + NO_REWARDS_RATE_ASSOCIATED_WITH_LOCKUP_PERIOD_ERROR + => "No rewards rate associated with lockup period."; + POOL_IS_NOT_IN_ALLOW_LIST_ERROR + => "Pool is not in allow list."; + ORACLE_REPORTED_PRICE_IS_STALE_ERROR + => "Oracle reported price is stale."; + LOCKUP_PERIOD_HAS_NO_ASSOCIATED_REWARDS_RATE_ERROR + => "Lockup period has no associated rewards rate."; + UNEXPECTED_ERROR + => "Unexpected error."; + RELATIVE_PRICE_DIFFERENCE_LARGER_THAN_ALLOWED_ERROR + => "Relative price difference between oracle and pool exceeds allowed."; + USER_ASSET_DOES_NOT_BELONG_TO_POOL_ERROR + => "The asset of the user does not belong to the pool."; + MORE_THAN_ONE_LIQUIDITY_RECEIPT_NFTS_ERROR + => "More than one liquidity receipt non-fungibles were provided."; + NOT_A_VALID_LIQUIDITY_RECEIPT_ERROR + => "Not a valid liquidity receipt resource."; + LIQUIDITY_POSITION_HAS_NOT_MATURED_ERROR + => "Can't close a liquidity position before it has matured."; + USER_MUST_NOT_PROVIDE_PROTOCOL_ASSET_ERROR + => "The user has provided the protocol asset, which is not allowed"; + USER_RESOURCES_VOLATILITY_UNKNOWN_ERROR + => "A user resource with no registered volatility status was interacted with."; + BOTH_POOL_ASSETS_ARE_THE_PROTOCOL_RESOURCE + => "The user resource can not be the protocol resource."; + OVERFLOW_ERROR => "Overflow error"; +} diff --git a/packages/ignition/src/lib.rs b/packages/ignition/src/lib.rs new file mode 100644 index 00000000..d0501ea6 --- /dev/null +++ b/packages/ignition/src/lib.rs @@ -0,0 +1,7 @@ +#![allow(clippy::too_many_arguments)] + +mod blueprint; +mod errors; + +pub use blueprint::*; +pub use errors::*; diff --git a/packages/ociswap-v1-adapter-v1/Cargo.toml b/packages/ociswap-v1-adapter-v1/Cargo.toml new file mode 100644 index 00000000..1c6ceaa9 --- /dev/null +++ b/packages/ociswap-v1-adapter-v1/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "ociswap-v1-adapter-v1" +version.workspace = true +edition.workspace = true +description = "Defines the adapter for Ociswap" + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +radix-engine-interface = { workspace = true } +transaction = { workspace = true, optional = true } + +scrypto-interface = { path = "../../libraries/scrypto-interface" } +ports-interface = { path = "../../libraries/ports-interface" } +common = { path = "../../libraries/common" } + +[features] +default = [] +test = [] + +manifest-builder-stubs = ["dep:transaction"] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/packages/ociswap-v1-adapter-v1/src/blueprint_interface.rs b/packages/ociswap-v1-adapter-v1/src/blueprint_interface.rs new file mode 100644 index 00000000..66f323b5 --- /dev/null +++ b/packages/ociswap-v1-adapter-v1/src/blueprint_interface.rs @@ -0,0 +1,77 @@ +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + BasicPool as OciswapV1Pool impl [ + ScryptoStub, + ScryptoTestStub, + #[cfg(feature = "manifest-builder-stubs")] + ManifestBuilderStub + ] { + fn instantiate( + a_address: ResourceAddress, + b_address: ResourceAddress, + input_fee_rate: Decimal, + dapp_definition: ComponentAddress, + ) -> Self; + fn instantiate_with_liquidity( + #[manifest_type = "ManifestBucket"] + a_bucket: Bucket, + #[manifest_type = "ManifestBucket"] + b_bucket: Bucket, + input_fee_rate: Decimal, + dapp_definition: ComponentAddress, + ) -> (Self, Bucket, Option); + fn add_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + a_bucket: Bucket, + #[manifest_type = "ManifestBucket"] + b_bucket: Bucket + ) -> (Bucket, Option); + fn remove_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + lp_token: Bucket + ) -> (Bucket, Bucket); + fn swap( + &mut self, + #[manifest_type = "ManifestBucket"] + input_bucket: Bucket + ) -> Bucket; + fn price_sqrt(&mut self) -> Option; + fn liquidity_pool(&self) -> ComponentAddress; + fn set_liquidity_pool_meta( + &self, + pool_address: ComponentAddress, + lp_address: ResourceAddress, + dapp_definition: ComponentAddress, + ); + fn increase_observation_capacity(&mut self, new_capacity: u16); + } +} + +define_interface! { + TwoResourcePool impl [ScryptoStub, ScryptoTestStub] { + fn instantiate( + owner_role: OwnerRole, + pool_manager_rule: AccessRule, + resource_addresses: (ResourceAddress, ResourceAddress), + address_reservation: Option, + ) -> Self; + fn contribute(&mut self, buckets: (Bucket, Bucket)) -> (Bucket, Option); + fn redeem(&mut self, bucket: Bucket) -> (Bucket, Bucket); + fn protected_deposit(&mut self, bucket: Bucket); + fn protected_withdraw( + &mut self, + resource_address: ResourceAddress, + amount: Decimal, + withdraw_strategy: WithdrawStrategy, + ) -> Bucket; + fn get_redemption_value( + &self, + amount_of_pool_units: Decimal, + ) -> IndexMap; + fn get_vault_amounts(&self) -> IndexMap; + } +} diff --git a/packages/ociswap-v1-adapter-v1/src/lib.rs b/packages/ociswap-v1-adapter-v1/src/lib.rs new file mode 100644 index 00000000..b0c59102 --- /dev/null +++ b/packages/ociswap-v1-adapter-v1/src/lib.rs @@ -0,0 +1,329 @@ +mod blueprint_interface; +pub use blueprint_interface::*; + +use std::cmp::*; + +use common::prelude::*; +use ports_interface::prelude::*; +use scrypto::prelude::*; +use scrypto_interface::*; + +macro_rules! define_error { + ( + $( + $name: ident => $item: expr; + )* + ) => { + $( + pub const $name: &'static str = concat!("[Ociswap v1 Adapter v1]", " ", $item); + )* + }; +} + +define_error! { + FAILED_TO_GET_RESOURCE_ADDRESSES_ERROR + => "Failed to get resource addresses - unexpected error."; + FAILED_TO_GET_VAULT_ERROR + => "Failed to get vault - unexpected error."; + PRICE_IS_UNDEFINED + => "Price is undefined."; + FAILED_TO_CALCULATE_K_VALUE_OF_POOL_ERROR + => "Failed to calculate the K value of the pool."; + OVERFLOW_ERROR => "Calculation overflowed."; +} + +macro_rules! pool { + ($address: expr) => { + $crate::blueprint_interface::OciswapV1PoolInterfaceScryptoStub::from( + $address, + ) + }; +} + +#[blueprint_with_traits] +pub mod adapter { + struct OciswapV1Adapter; + + impl OciswapV1Adapter { + pub fn instantiate( + metadata_init: MetadataInit, + owner_role: OwnerRole, + address_reservation: Option, + ) -> Global { + let address_reservation = + address_reservation.unwrap_or_else(|| { + Runtime::allocate_component_address(BlueprintId { + package_address: Runtime::package_address(), + blueprint_name: Runtime::blueprint_name(), + }) + .0 + }); + + Self {} + .instantiate() + .prepare_to_globalize(owner_role) + .metadata(ModuleConfig { + init: metadata_init, + roles: Default::default(), + }) + .with_address(address_reservation) + .globalize() + } + + pub fn liquidity_receipt_data( + // Does not depend on state, this is kept in case this is required + // in the future for whatever reason. + &self, + global_id: NonFungibleGlobalId, + ) -> LiquidityReceipt { + // Read the non-fungible data. + let LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } = ResourceManager::from_address(global_id.resource_address()) + .get_non_fungible_data::>( + global_id.local_id(), + ); + let adapter_specific_information = adapter_specific_information + .as_typed::() + .unwrap(); + + LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } + } + } + + impl PoolAdapterInterfaceTrait for OciswapV1Adapter { + fn open_liquidity_position( + &mut self, + pool_address: ComponentAddress, + buckets: (Bucket, Bucket), + ) -> OpenLiquidityPositionOutput { + let mut pool = pool!(pool_address); + + let (pool_units, change) = pool.add_liquidity(buckets.0, buckets.1); + + let user_share = pool_units + .amount() + .checked_div( + pool_units.resource_manager().total_supply().unwrap(), + ) + .expect(OVERFLOW_ERROR); + + let pool_k = Global::::from(pool.liquidity_pool()) + .get_vault_amounts() + .values() + .map(|item| PreciseDecimal::from(*item)) + .reduce(|acc, item| { + acc.checked_mul(item).expect(OVERFLOW_ERROR) + }) + .expect(FAILED_TO_CALCULATE_K_VALUE_OF_POOL_ERROR); + + OpenLiquidityPositionOutput { + pool_units, + change: change + .map(|bucket| { + indexmap! { + bucket.resource_address() => bucket + } + }) + .unwrap_or_default(), + others: Default::default(), + adapter_specific_information: + OciswapV1AdapterSpecificInformation { + user_share_in_pool_when_position_opened: user_share, + pool_k_when_position_opened: pool_k, + } + .into(), + } + } + + /// Closes the liquidity position and calculates the amount of fees + /// earned on the position while it was opened. + /// + /// On the fees calculation, this method is incapable of finding the + /// exact amount of fees earned, just an approximation of how much the + /// fees could be. The basis of this calculation is that by finding the + /// amount of X and Y assets we expect to get at some desired price (the + /// output amount due to price action) we can deduce the fees by + /// subtracting the actual amount from the expected amount. + /// + /// For an xy = k AMM we have the following equations: + /// + /// (1) xy = k + /// (2) y/x = p + /// + /// From (2) y can be represented in terms of p and x where it becomes + /// y = px. Plugging that into (1) we get that: + /// + /// (3) xpx = k + /// x^2 = k/p + /// x = sqrt(k/p) + /// + /// Once X is found we can find y by plugging in the equation of x. + /// + /// (4) y = px + /// y = p * sqrt(k / p) + /// + /// With equations (3) and (4), we now have a way to calculate the + /// amount of x and y resources in the pool at some price _p_ and some + /// pool coefficient value _k_. The amount that the user gets back when + /// they close their liquidity position is the multiplication of the + /// above by the user share _s_ which is 0 <= s <= 1. + /// + /// Therefore, the amount that the user is owed is equal to: + /// + /// (6) x_owed = s * sqrt(k/p) + /// (7) y_owed = s * p * sqrt(k/p) + /// + /// To find the amount of x and y we expect to get back due to price + /// action alone we use: + /// + /// 1. `s` the share of the user in the pool when the position was first + /// opened. + /// 2. `p` the final price. + /// 3. `k` the pool coffieicnet when the position was first opened. + fn close_liquidity_position( + &mut self, + pool_address: ComponentAddress, + pool_units: Bucket, + adapter_specific_information: AnyValue, + ) -> CloseLiquidityPositionOutput { + let mut pool = pool!(pool_address); + + let (bucket1, bucket2) = pool.remove_liquidity(pool_units); + + // Calculating the fees. + let fees = { + let indexed_buckets = [&bucket1, &bucket2] + .into_iter() + .map(|bucket| Bucket(bucket.0)) + .map(|bucket| (bucket.resource_address(), bucket)) + .collect::>(); + + let OciswapV1AdapterSpecificInformation { + pool_k_when_position_opened, + user_share_in_pool_when_position_opened, + } = adapter_specific_information + .as_typed::() + .unwrap(); + + let price = self.price(pool_address); + + let sqrt_k_div_p = pool_k_when_position_opened + .checked_div(price.price) + .and_then(|value| value.checked_sqrt()) + .expect(OVERFLOW_ERROR); + + let predicted_amount_x = sqrt_k_div_p + .checked_mul(user_share_in_pool_when_position_opened) + .and_then(|value| Decimal::try_from(value).ok()) + .expect(OVERFLOW_ERROR); + let predicted_amount_y = predicted_amount_x + .checked_mul(price.price) + .expect(OVERFLOW_ERROR); + + let fees_x = max( + indexed_buckets + .get(&price.base) + .map(|bucket| bucket.amount()) + .unwrap_or(Decimal::ZERO) + .checked_sub(predicted_amount_x) + .unwrap_or(Decimal::ZERO), + Decimal::ZERO, + ); + let fees_y = max( + indexed_buckets + .get(&price.quote) + .map(|bucket| bucket.amount()) + .unwrap_or(Decimal::ZERO) + .checked_sub(predicted_amount_y) + .unwrap_or(Decimal::ZERO), + Decimal::ZERO, + ); + + indexmap! { + price.base => fees_x, + price.quote => fees_y + } + }; + + CloseLiquidityPositionOutput { + resources: indexmap! { + bucket1.resource_address() => bucket1, + bucket2.resource_address() => bucket2, + }, + others: Default::default(), + fees, + } + } + + fn price(&mut self, pool_address: ComponentAddress) -> Price { + let pool = pool!(pool_address); + let pool = Global::::from(pool.liquidity_pool()); + let vault_amounts = pool.get_vault_amounts(); + + let (resource_address1, resource_address2) = + self.resource_addresses(pool_address); + let amount1 = *vault_amounts + .get(&resource_address1) + .expect(FAILED_TO_GET_VAULT_ERROR); + let amount2 = *vault_amounts + .get(&resource_address2) + .expect(FAILED_TO_GET_VAULT_ERROR); + + Price { + base: resource_address1, + quote: resource_address2, + price: amount2.checked_div(amount1).expect(PRICE_IS_UNDEFINED), + } + } + + fn resource_addresses( + &mut self, + pool_address: ComponentAddress, + ) -> (ResourceAddress, ResourceAddress) { + let pool = pool!(pool_address); + let pool = Global::::from(pool.liquidity_pool()); + let mut keys = pool.get_vault_amounts().into_keys(); + + let resource_address1 = + keys.next().expect(FAILED_TO_GET_RESOURCE_ADDRESSES_ERROR); + let resource_address2 = + keys.next().expect(FAILED_TO_GET_RESOURCE_ADDRESSES_ERROR); + + (resource_address1, resource_address2) + } + } +} + +#[derive(ScryptoSbor, Debug, Clone)] +pub struct OciswapV1AdapterSpecificInformation { + /// The share of the user in the pool when the position was opened. + pub user_share_in_pool_when_position_opened: Decimal, + + /// The value of the K of the pool when the position was opened. + pub pool_k_when_position_opened: PreciseDecimal, +} + +impl From for AnyValue { + fn from(value: OciswapV1AdapterSpecificInformation) -> Self { + AnyValue::from_typed(&value).unwrap() + } +} diff --git a/packages/ociswap-v2-adapter-v1/Cargo.toml b/packages/ociswap-v2-adapter-v1/Cargo.toml new file mode 100644 index 00000000..d5cd2b2c --- /dev/null +++ b/packages/ociswap-v2-adapter-v1/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ociswap-v2-adapter-v1" +version.workspace = true +edition.workspace = true +description = "Defines the adapter for Ociswap" + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +radix-engine-interface = { workspace = true } +transaction = { workspace = true, optional = true } + +common = { path = "../../libraries/common" } +scrypto-math = { path = "../../libraries/scrypto-math" } +scrypto-interface = { path = "../../libraries/scrypto-interface" } +ports-interface = { path = "../../libraries/ports-interface" } + + +[features] +default = [] +test = [] + +manifest-builder-stubs = ["dep:transaction"] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/packages/ociswap-v2-adapter-v1/src/blueprint_interface.rs b/packages/ociswap-v2-adapter-v1/src/blueprint_interface.rs new file mode 100644 index 00000000..348d4211 --- /dev/null +++ b/packages/ociswap-v2-adapter-v1/src/blueprint_interface.rs @@ -0,0 +1,110 @@ +use scrypto::prelude::*; +use scrypto_interface::*; + +define_interface! { + LiquidityPool as OciswapV2Pool impl [ + ScryptoStub, + ScryptoTestStub, + #[cfg(feature = "manifest-builder-stubs")] + ManifestBuilderStub + ] { + fn instantiate( + x_address: ResourceAddress, + y_address: ResourceAddress, + price_sqrt: PreciseDecimal, + input_fee_rate: Decimal, + flash_loan_fee_rate: Decimal, + registry_address: ComponentAddress, + #[manifest_type = "Vec<(ComponentAddress, ManifestBucket)>"] + hook_badges: Vec<(ComponentAddress, Bucket)>, + dapp_definition: ComponentAddress + ) -> (Self, ResourceAddress); + fn instantiate_with_liquidity( + #[manifest_type = "ManifestBucket"] + x_bucket: Bucket, + #[manifest_type = "ManifestBucket"] + y_bucket: Bucket, + price_sqrt: PreciseDecimal, + input_fee_rate: Decimal, + flash_loan_fee_rate: Decimal, + registry_address: ComponentAddress, + #[manifest_type = "Vec<(ComponentAddress, ManifestBucket)>"] + hook_badges: Vec<(ComponentAddress, Bucket)>, + dapp_definition: ComponentAddress, + left_bound: i32, + right_bound: i32 + ) -> (Self, ResourceAddress, Bucket, Bucket, Bucket); + fn add_liquidity( + &mut self, + left_bound: i32, + right_bound: i32, + #[manifest_type = "ManifestBucket"] + x_bucket: Bucket, + #[manifest_type = "ManifestBucket"] + y_bucket: Bucket + ) -> (Bucket, Bucket, Bucket); + fn add_liquidity_shape( + &mut self, + #[manifest_type = "Vec<(i32, i32, ManifestBucket, ManifestBucket)>"] + positions: Vec<(i32, i32, Bucket, Bucket)> + ) -> (Bucket, Bucket, Bucket); + fn remove_liquidity( + &mut self, + #[manifest_type = "ManifestBucket"] + lp_positions: NonFungibleBucket + ) -> (Bucket, Bucket); + fn swap( + &mut self, + #[manifest_type = "ManifestBucket"] + input_bucket: Bucket + ) -> (Bucket, Bucket); + fn sync_registry(&mut self); + fn claim_fees( + &mut self, + #[manifest_type = "ManifestProof"] + lp_proofs: NonFungibleProof + ) -> (Bucket, Bucket); + fn flash_loan( + &mut self, + loan_address: ResourceAddress, + loan_amount: Decimal + ) -> (Bucket, Bucket); + fn fee_outside( + &self, + swap_type: SwapType + ) -> (PreciseDecimal, PreciseDecimal); + fn update_fee_outside( + &mut self, + fee_x_global: PreciseDecimal, + fee_y_global: PreciseDecimal + ); + fn x_address(&self) -> ResourceAddress; + fn y_address(&self) -> ResourceAddress; + fn registry(&self) -> ComponentAddress; + fn next_sync_time(&self) -> u64; + fn price_sqrt(&self) -> PreciseDecimal; + fn total_fees(&self, position_id: NonFungibleLocalId) -> (Decimal, Decimal); + } +} + +define_interface! { + Registry as OciswapV2Registry impl [ + ScryptoStub, + ScryptoTestStub, + #[cfg(feature = "manifest-builder-stubs")] + ManifestBuilderStub + ] { + fn instantiate( + owner_badge_address: ResourceAddress, + fee_protocol_share: Decimal, + sync_period: u64, + sync_slots: u64 + ) -> Self; + } +} + +#[derive(ScryptoSbor, ManifestSbor, Clone, Copy, Debug, PartialEq)] +pub enum SwapType { + BuyX, + SellX, +} diff --git a/packages/ociswap-v2-adapter-v1/src/lib.rs b/packages/ociswap-v2-adapter-v1/src/lib.rs new file mode 100644 index 00000000..6bf03e0f --- /dev/null +++ b/packages/ociswap-v2-adapter-v1/src/lib.rs @@ -0,0 +1,248 @@ +mod blueprint_interface; +pub use blueprint_interface::*; + +use common::prelude::*; +use ports_interface::prelude::*; +use scrypto::prelude::*; +use scrypto_interface::*; +use scrypto_math::*; + +macro_rules! define_error { + ( + $( + $name: ident => $item: expr; + )* + ) => { + $( + pub const $name: &'static str = concat!("[Ociswap v2 Adapter v1]", " ", $item); + )* + }; +} + +define_error! { + RESOURCE_DOES_NOT_BELONG_ERROR + => "One or more of the resources do not belong to pool."; + OVERFLOW_ERROR => "Calculation overflowed."; + UNEXPECTED_ERROR => "Unexpected error."; +} + +macro_rules! pool { + ($address: expr) => { + $crate::blueprint_interface::OciswapV2PoolInterfaceScryptoStub::from( + $address, + ) + }; +} + +#[blueprint_with_traits] +pub mod adapter { + struct OciswapV2Adapter; + + impl OciswapV2Adapter { + pub fn instantiate( + metadata_init: MetadataInit, + owner_role: OwnerRole, + address_reservation: Option, + ) -> Global { + let address_reservation = + address_reservation.unwrap_or_else(|| { + Runtime::allocate_component_address(BlueprintId { + package_address: Runtime::package_address(), + blueprint_name: Runtime::blueprint_name(), + }) + .0 + }); + + Self {} + .instantiate() + .prepare_to_globalize(owner_role) + .metadata(ModuleConfig { + init: metadata_init, + roles: Default::default(), + }) + .with_address(address_reservation) + .globalize() + } + + pub fn liquidity_receipt_data( + // Does not depend on state, this is kept in case this is required + // in the future for whatever reason. + &self, + global_id: NonFungibleGlobalId, + ) -> LiquidityReceipt { + // Read the non-fungible data. + let LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } = ResourceManager::from_address(global_id.resource_address()) + .get_non_fungible_data::>( + global_id.local_id(), + ); + let adapter_specific_information = adapter_specific_information + .as_typed::() + .unwrap(); + + LiquidityReceipt { + name, + lockup_period, + pool_address, + user_resource_address, + user_contribution_amount, + user_resource_volatility_classification, + protocol_contribution_amount, + maturity_date, + adapter_specific_information, + } + } + } + + impl PoolAdapterInterfaceTrait for OciswapV2Adapter { + fn open_liquidity_position( + &mut self, + pool_address: ComponentAddress, + buckets: (Bucket, Bucket), + ) -> OpenLiquidityPositionOutput { + let mut pool = pool!(pool_address); + + // Sorting the buckets according to the ordering of the pool itself. + let (bucket_x, bucket_y) = { + let resource_x = pool.x_address(); + let resource_y = pool.y_address(); + + if buckets.0.resource_address() == resource_x + && buckets.1.resource_address() == resource_y + { + (buckets.0, buckets.1) + } else if buckets.1.resource_address() == resource_x + && buckets.0.resource_address() == resource_y + { + (buckets.1, buckets.0) + } else { + panic!("{}", RESOURCE_DOES_NOT_BELONG_ERROR) + } + }; + + // Contributing liquidity to the pool - the offset that is defined + // here is the amount of ticks that we need to contribute to get to + // a 20x upside and downside. We calculate this through a function + // provided by Ociswap: offset = ln(multiplier) / ln(1.0001) and + // then round up. + // + // In Ociswap v2, prices can be calculated from ticks by using the + // equation p(t) = 1.0001^t. The currently active tick can be found + // from the current price by ln(price) / ln(1.0001). + // + // The following calculation finds the currently active tick based + // on the equation above which all happens using the PreciseDecimal + // type. To use the active tick we must convert it to an i32 which + // is expected by the Ociswap interface so the I256 of the computed + // active tick is divided by PreciseDecimal::ONE.0 to remove all of + // the decimal places and just have the integral part which we then + // call i32::try_from on. + let active_tick = pool + .price_sqrt() + .checked_powi(2) + .and_then(|value| value.ln()) + .and_then(|ln_price| { + dec!(1.0001) + .ln() + .and_then(|ln_base| ln_price.checked_div(ln_base)) + }) + .and_then(|value| value.0.checked_div(PreciseDecimal::ONE.0)) + .and_then(|value| i32::try_from(value).ok()) + .expect(OVERFLOW_ERROR); + let offset = 29959; + + let lower_tick = + active_tick.checked_sub(offset).expect(OVERFLOW_ERROR); + let upper_tick = + active_tick.checked_add(offset).expect(OVERFLOW_ERROR); + + let (receipt, change_x, change_y) = + pool.add_liquidity(lower_tick, upper_tick, bucket_x, bucket_y); + + OpenLiquidityPositionOutput { + pool_units: receipt, + change: indexmap! { + change_x.resource_address() => change_x, + change_y.resource_address() => change_y, + }, + others: Default::default(), + adapter_specific_information: AnyValue::from_typed(&()) + .expect(UNEXPECTED_ERROR), + } + } + + fn close_liquidity_position( + &mut self, + pool_address: ComponentAddress, + pool_units: Bucket, + _: AnyValue, + ) -> CloseLiquidityPositionOutput { + let mut pool = pool!(pool_address); + + // Calculate how much fees were earned on the position while it was + // opened. + let resource_address_x = pool.x_address(); + let resource_address_y = pool.y_address(); + let (fees_x, fees_y) = pool.total_fees( + pool_units.as_non_fungible().non_fungible_local_id(), + ); + + // Close the liquidity position + let (resource_x, resource_y) = + pool.remove_liquidity(pool_units.as_non_fungible()); + + CloseLiquidityPositionOutput { + resources: indexmap! { + resource_x.resource_address() => resource_x, + resource_y.resource_address() => resource_y, + }, + others: vec![], + fees: indexmap! { + resource_address_x => fees_x, + resource_address_y => fees_y, + }, + } + } + + fn price(&mut self, pool_address: ComponentAddress) -> Price { + let pool = pool!(pool_address); + let price_sqrt = pool.price_sqrt(); + let price = price_sqrt + .checked_powi(2) + .and_then(|value| Decimal::try_from(value).ok()) + .expect(OVERFLOW_ERROR); + let (resource_x, resource_y) = (pool.x_address(), pool.y_address()); + Price { + base: resource_x, + quote: resource_y, + price, + } + } + + fn resource_addresses( + &mut self, + pool_address: ComponentAddress, + ) -> (ResourceAddress, ResourceAddress) { + let pool = pool!(pool_address); + (pool.x_address(), pool.y_address()) + } + } +} + +#[derive(ScryptoSbor, Debug, Clone)] +pub struct OciswapV2AdapterSpecificInformation {} + +impl From for AnyValue { + fn from(value: OciswapV2AdapterSpecificInformation) -> Self { + AnyValue::from_typed(&value).unwrap() + } +} diff --git a/packages/simple-oracle/Cargo.toml b/packages/simple-oracle/Cargo.toml new file mode 100644 index 00000000..1347516f --- /dev/null +++ b/packages/simple-oracle/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "simple-oracle" +version = { workspace = true } +edition = { workspace = true } +description = "A simple oracle used in tests." + +[dependencies] +sbor = { workspace = true } +scrypto = { workspace = true } +radix-engine-derive = { workspace = true } + +scrypto-interface = { path = "../../libraries/scrypto-interface" } +ports-interface = { path = "../../libraries/ports-interface" } +common = { path = "../../libraries/common" } + +humantime = { version = "2.1.0" } + +[features] +default = [] +test = [] + +[lib] +crate-type = ["cdylib", "lib"] + +[lints] +workspace = true \ No newline at end of file diff --git a/packages/simple-oracle/src/lib.rs b/packages/simple-oracle/src/lib.rs new file mode 100644 index 00000000..edd76264 --- /dev/null +++ b/packages/simple-oracle/src/lib.rs @@ -0,0 +1,122 @@ +use ports_interface::prelude::*; +use scrypto::prelude::*; +use scrypto_interface::*; + +#[derive( + Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, ScryptoSbor, +)] +pub struct Pair { + pub base: ResourceAddress, + pub quote: ResourceAddress, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, ScryptoSbor)] +pub struct PairPriceEntry { + pub price: Decimal, + /// This is an instant of when did the component observe the submitted + /// prices and not when they were actually observed by the oracle + /// off-ledger software. + pub observed_by_component_at: Instant, +} + +#[blueprint_with_traits] +#[types(Pair, PairPriceEntry)] +mod simple_oracle { + enable_method_auth! { + roles { + oracle_manager => updatable_by: [oracle_manager]; + }, + methods { + set_price => restrict_to: [oracle_manager]; + set_price_batch => restrict_to: [oracle_manager]; + get_price => PUBLIC; + } + } + + pub struct SimpleOracle { + /// Maps the (base, quote) to the (price, updated_at). + prices: KeyValueStore, + } + + impl SimpleOracle { + pub fn instantiate( + oracle_manager: AccessRule, + metadata_init: MetadataInit, + owner_role: OwnerRole, + address_reservation: Option, + ) -> Global { + let address_reservation = + address_reservation.unwrap_or_else(|| { + Runtime::allocate_component_address(BlueprintId { + package_address: Runtime::package_address(), + blueprint_name: Runtime::blueprint_name(), + }) + .0 + }); + + Self { + prices: KeyValueStore::new_with_registered_type(), + } + .instantiate() + .prepare_to_globalize(owner_role) + .roles(roles! { + oracle_manager => oracle_manager; + }) + .metadata(ModuleConfig { + init: metadata_init, + roles: Default::default(), + }) + .with_address(address_reservation) + .globalize() + } + + pub fn set_price( + &mut self, + base: ResourceAddress, + quote: ResourceAddress, + price: Decimal, + ) { + self.prices.insert( + Pair { base, quote }, + PairPriceEntry { + price, + observed_by_component_at: + Clock::current_time_rounded_to_minutes(), + }, + ) + } + + pub fn set_price_batch( + &mut self, + prices: IndexMap<(ResourceAddress, ResourceAddress), Decimal>, + ) { + let time = Clock::current_time_rounded_to_minutes(); + for ((base, quote), price) in prices.into_iter() { + self.prices.insert( + Pair { base, quote }, + PairPriceEntry { + price, + observed_by_component_at: time, + }, + ) + } + } + } + + impl OracleAdapterInterfaceTrait for SimpleOracle { + fn get_price( + &self, + base: ResourceAddress, + quote: ResourceAddress, + ) -> (Decimal, Instant) { + let PairPriceEntry { + price, + observed_by_component_at, + } = *self + .prices + .get(&Pair { base, quote }) + .expect("Price not found for this resource"); + (price, observed_by_component_at) + } + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..31578d3b --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..5c8d9318 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 \ No newline at end of file diff --git a/tests/Cargo.toml b/tests/Cargo.toml new file mode 100644 index 00000000..024ebdc7 --- /dev/null +++ b/tests/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "tests" +version.workspace = true +edition.workspace = true +description.workspace = true +build = "build.rs" + +[dependencies] +sbor = { workspace = true } +transaction = { workspace = true } +scrypto-test = { workspace = true } +scrypto-unit = { workspace = true } +radix-engine = { workspace = true } +radix-engine-common = { workspace = true } +radix-engine-interface = { workspace = true } + +common = { path = "../libraries/common" } +ignition = { path = "../packages/ignition", features = ["test"] } +simple-oracle = { path = "../packages/simple-oracle", features = ["test"] } +ports-interface = { path = "../libraries/ports-interface" } +ociswap-v1-adapter-v1 = { path = "../packages/ociswap-v1-adapter-v1", features = [ + "test", + "manifest-builder-stubs" +] } +ociswap-v2-adapter-v1 = { path = "../packages/ociswap-v2-adapter-v1", features = [ + "test", + "manifest-builder-stubs" +] } +caviarnine-v1-adapter-v1 = { path = "../packages/caviarnine-v1-adapter-v1", features = [ + "test", + "manifest-builder-stubs" +] } + +package-loader = { path = "../libraries/package-loader" } +gateway-client = { path = "../libraries/gateway-client" } + +paste = { version = "1.0.14" } +extend = { version = "1.2.0" } +lazy_static = "1.4.0" + +[build-dependencies] +flate2 = { version = "1.0.28" } + +[lints] +workspace = true \ No newline at end of file diff --git a/tests/assets/ociswap_v2_pool.rpd b/tests/assets/ociswap_v2_pool.rpd new file mode 100644 index 00000000..def6307d Binary files /dev/null and b/tests/assets/ociswap_v2_pool.rpd differ diff --git a/tests/assets/ociswap_v2_pool.wasm b/tests/assets/ociswap_v2_pool.wasm new file mode 100755 index 00000000..2f8d9644 Binary files /dev/null and b/tests/assets/ociswap_v2_pool.wasm differ diff --git a/tests/assets/ociswap_v2_registry.rpd b/tests/assets/ociswap_v2_registry.rpd new file mode 100644 index 00000000..1816d600 Binary files /dev/null and b/tests/assets/ociswap_v2_registry.rpd differ diff --git a/tests/assets/ociswap_v2_registry.wasm b/tests/assets/ociswap_v2_registry.wasm new file mode 100755 index 00000000..3e53f905 Binary files /dev/null and b/tests/assets/ociswap_v2_registry.wasm differ diff --git a/tests/assets/state b/tests/assets/state new file mode 100644 index 00000000..3f20811d Binary files /dev/null and b/tests/assets/state differ diff --git a/tests/build.rs b/tests/build.rs new file mode 100644 index 00000000..aa07e283 --- /dev/null +++ b/tests/build.rs @@ -0,0 +1,25 @@ +fn main() { + decompress_state(); +} + +fn decompress_state() { + use flate2::read::*; + + use std::env; + use std::io::prelude::*; + use std::path::*; + use std::str::FromStr; + + println!("cargo:rerun-if-changed=\"./assets/state\""); + let compressed = include_bytes!("./assets/state"); + let mut decoder = GzDecoder::new(&compressed[..]); + let mut uncompressed = Vec::new(); + decoder + .read_to_end(&mut uncompressed) + .expect("Failed to decompress!"); + + let path = PathBuf::from_str(env::var("OUT_DIR").unwrap().as_str()) + .unwrap() + .join("uncompressed_state.bin"); + std::fs::write(path, uncompressed).unwrap(); +} diff --git a/tests/src/environment.rs b/tests/src/environment.rs new file mode 100644 index 00000000..6debe76d --- /dev/null +++ b/tests/src/environment.rs @@ -0,0 +1,1338 @@ +use crate::prelude::*; + +pub type ScryptoTestEnv = Environment; +pub type ScryptoUnitEnv = Environment; + +pub trait EnvironmentSpecifier { + // Environment + type Environment; + + // Components + type Ignition; + type SimpleOracle; + type OciswapV1Pool; + type OciswapV2Pool; + type CaviarnineV1Pool; + + type OciswapV1Adapter; + type OciswapV2Adapter; + type CaviarnineV1Adapter; + + // Badges + type Badge; +} + +pub struct ScryptoTestEnvironmentSpecifier; + +impl EnvironmentSpecifier for ScryptoTestEnvironmentSpecifier { + // Environment + type Environment = TestEnvironment; + + // Components + type Ignition = Ignition; + type SimpleOracle = SimpleOracle; + type OciswapV1Pool = OciswapV1PoolInterfaceScryptoTestStub; + type OciswapV2Pool = OciswapV2PoolInterfaceScryptoTestStub; + type CaviarnineV1Pool = CaviarnineV1PoolInterfaceScryptoTestStub; + + type OciswapV1Adapter = OciswapV1Adapter; + type OciswapV2Adapter = OciswapV2Adapter; + type CaviarnineV1Adapter = CaviarnineV1Adapter; + + // Badges + type Badge = Bucket; +} + +pub struct ScryptoUnitEnvironmentSpecifier; + +impl EnvironmentSpecifier for ScryptoUnitEnvironmentSpecifier { + // Environment + type Environment = DefaultTestRunner; + + // Components + type Ignition = ComponentAddress; + type SimpleOracle = ComponentAddress; + type OciswapV1Pool = ComponentAddress; + type OciswapV2Pool = ComponentAddress; + type CaviarnineV1Pool = ComponentAddress; + + type OciswapV1Adapter = ComponentAddress; + type OciswapV2Adapter = ComponentAddress; + type CaviarnineV1Adapter = ComponentAddress; + + // Badges + type Badge = (PublicKey, PrivateKey, ComponentAddress, ResourceAddress); +} + +/// The environment that Ignition is tested in. +/// +/// This offers a set of convince methods for creating and initializing the +/// environment such that it is in a state that can easily be tested. First, +/// the appropriate package's substates are loaded and then flashed to the +/// environment making them available for use there, these substates come from +/// the mainnet state tree. Additionally, the needed resources are created, +/// and an oracle is created and registered in Ignition. +/// +/// Ignition will be initialized with a protocol owner and a protocol manager +/// whose badges will be created in the initialization of the environment and +/// returned back to the caller. Additionally, the auth module will be disabled +/// by default for the created test environment. If it needs to be enabled then +/// that must happen after the creation of the environment. +pub struct Environment +where + S: EnvironmentSpecifier, +{ + /* Test Environment */ + pub environment: S::Environment, + /* Various entities */ + pub resources: ResourceInformation, + pub protocol: ProtocolEntities, + /* Supported Dexes */ + pub ociswap_v1: DexEntities, + pub ociswap_v2: DexEntities, + pub caviarnine_v1: DexEntities, +} + +impl Environment +where + S: EnvironmentSpecifier, +{ + const PACKAGES_BINARY: &'static [u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/uncompressed_state.bin")); + + const PACKAGE_NAMES: [&'static str; 4] = [ + "ignition", + "simple-oracle", + "ociswap-v1-adapter-v1", + "caviarnine-v1-adapter-v1", + ]; + + const RESOURCE_DIVISIBILITIES: ResourceInformation = + ResourceInformation:: { + bitcoin: 8, + ethereum: 18, + usdc: 6, + usdt: 6, + }; +} + +impl ScryptoTestEnv { + pub fn new() -> Result { + Self::new_with_configuration(Configuration::default()) + } + + pub fn new_with_configuration( + configuration: Configuration, + ) -> Result { + // Flash the substates to the ledger so that they can be used in tests. + let (addresses, db_flash) = + scrypto_decode::<(Vec, DbFlash)>(Self::PACKAGES_BINARY) + .expect("Can't fail!"); + + let caviarnine_v1_package = + PackageAddress::try_from(addresses[0]).unwrap(); + let ociswap_v1_package = + PackageAddress::try_from(addresses[1]).unwrap(); + + let mut env = TestEnvironmentBuilder::new().flash(db_flash).build(); + + // This environment instantiation function assumes that we do not want + // to have the auth module enabled and that we are more interested in + // just testing the behavior. So, the auth module is disabled in the + // environment. If somebody want it, they can enable it after they + // instantiate the environment. + env.disable_auth_module(); + + // Creating the badges and their access rules + let protocol_manager_badge = + ResourceBuilder::new_fungible(OwnerRole::None) + .divisibility(0) + .mint_initial_supply(1, &mut env)?; + let protocol_owner_badge = + ResourceBuilder::new_fungible(OwnerRole::None) + .divisibility(0) + .mint_initial_supply(1, &mut env)?; + + let protocol_manager_rule = protocol_manager_badge + .resource_address(&mut env) + .map(|address| rule!(require(address)))?; + let protocol_owner_rule = protocol_owner_badge + .resource_address(&mut env) + .map(|address| rule!(require(address)))?; + + // Publishing the various packages to the testing environment + let [ignition_package, simple_oracle_package, ociswap_v1_adapter_v1_package, caviarnine_v1_adapter_v1_package] = + Self::PACKAGE_NAMES + .map(|name| Self::publish_package(name, &mut env).unwrap()); + + // Creating the various resources and their associated pools. + let resource_addresses = + Self::RESOURCE_DIVISIBILITIES.try_map(|divisibility| { + ResourceBuilder::new_fungible(OwnerRole::Fixed(rule!( + allow_all + ))) + .divisibility(*divisibility) + .mint_roles(mint_roles! { + minter => rule!(allow_all); + minter_updater => rule!(allow_all); + }) + .burn_roles(burn_roles! { + burner => rule!(allow_all); + burner_updater => rule!(allow_all); + }) + .mint_initial_supply(dec!(0), &mut env) + .and_then(|bucket| bucket.resource_address(&mut env)) + })?; + + // Creating the liquidity receipt resource that each of the exchanges + // will use. + let [ociswap_v1_liquidity_receipt_resource, ociswap_v2_liquidity_receipt_resource, caviarnine_v1_liquidity_receipt_resource] = + std::array::from_fn(|_| { + ResourceBuilder::new_ruid_non_fungible::< + LiquidityReceipt, + >(OwnerRole::None) + .mint_roles(mint_roles! { + minter => rule!(allow_all); + minter_updater => rule!(allow_all); + }) + .burn_roles(burn_roles! { + burner => rule!(allow_all); + burner_updater => rule!(allow_all); + }) + .mint_initial_supply([], &mut env) + .expect("Must succeed!") + .resource_address(&mut env) + .expect("Must succeed!") + }); + + // Creating the Ociswap pools of the resources. + let ociswap_v1_pools = + resource_addresses.try_map(|resource_address| { + let mut ociswap_pool = + OciswapV1PoolInterfaceScryptoTestStub::instantiate( + *resource_address, + XRD, + configuration.fees, + FAUCET, + ociswap_v1_package, + &mut env, + )?; + + let resource_x = ResourceManager(*resource_address) + .mint_fungible(dec!(100_000_000), &mut env)?; + let resource_y = ResourceManager(XRD) + .mint_fungible(dec!(100_000_000), &mut env)?; + let _ = ociswap_pool + .add_liquidity(resource_x, resource_y, &mut env)?; + + Ok::<_, RuntimeError>(ociswap_pool) + })?; + + // Creating the Caviarnine pools of the resources. + let bin_span = 100; + let caviarnine_v1_pools = + resource_addresses.try_map(|resource_address| { + let mut caviarnine_pool = + CaviarnineV1PoolInterfaceScryptoTestStub::new( + rule!(allow_all), + rule!(allow_all), + *resource_address, + XRD, + bin_span, + None, + caviarnine_v1_package, + &mut env, + )?; + + let resource_x = ResourceManager(*resource_address) + .mint_fungible(dec!(2_000_000_000), &mut env)?; + let resource_y = ResourceManager(XRD) + .mint_fungible(dec!(2_000_000_000), &mut env)?; + let _ = caviarnine_pool.add_liquidity( + resource_x, + resource_y, + (0..10) + .flat_map(|offset| { + [ + ( + 27000 - offset * bin_span, + dec!(100_000_000), + dec!(100_000_000), + ), + ( + 27000 + offset * bin_span, + dec!(100_000_000), + dec!(100_000_000), + ), + ] + }) + .chain([(27000, dec!(100_000_000), dec!(100_000_000))]) + .rev() + .collect(), + &mut env, + )?; + + Ok::<_, RuntimeError>(caviarnine_pool) + })?; + + let ( + ociswap_v2_package, + ociswap_v2_adapter_v1_package, + ociswap_v2_pools, + ) = { + let ociswap_v2_pool_package = { + let ociswap_v2_package_wasm = + include_bytes!("../assets/ociswap_v2_pool.wasm"); + let ociswap_v2_package_rpd = + include_bytes!("../assets/ociswap_v2_pool.rpd"); + let ociswap_v2_package_definition = + manifest_decode::( + ociswap_v2_package_rpd, + ) + .unwrap(); + + env.call_function_typed::<_, PackagePublishWasmOutput>( + PACKAGE_PACKAGE, + PACKAGE_BLUEPRINT, + PACKAGE_PUBLISH_WASM_IDENT, + &PackagePublishWasmInput { + code: ociswap_v2_package_wasm.to_vec(), + definition: ociswap_v2_package_definition, + metadata: Default::default(), + }, + )? + .0 + }; + let ociswap_v2_registry_package = { + let ociswap_v2_package_wasm = + include_bytes!("../assets/ociswap_v2_registry.wasm"); + let ociswap_v2_package_rpd = + include_bytes!("../assets/ociswap_v2_registry.rpd"); + let ociswap_v2_package_definition = + manifest_decode::( + ociswap_v2_package_rpd, + ) + .unwrap(); + + env.call_function_typed::<_, PackagePublishWasmOutput>( + PACKAGE_PACKAGE, + PACKAGE_BLUEPRINT, + PACKAGE_PUBLISH_WASM_IDENT, + &PackagePublishWasmInput { + code: ociswap_v2_package_wasm.to_vec(), + definition: ociswap_v2_package_definition, + metadata: Default::default(), + }, + )? + .0 + }; + + let ociswap_v2_adapter_v1_package = + Self::publish_package("ociswap-v2-adapter-v1", &mut env)?; + + let registry = + OciswapV2RegistryInterfaceScryptoTestStub::instantiate( + GLOBAL_CALLER_VIRTUAL_BADGE, + dec!(0.03), + 10080, + 20, + ociswap_v2_registry_package, + &mut env, + )?; + + let ociswap_v2_pools = + resource_addresses.try_map(|resource_address| { + let (resource_x, resource_y) = if XRD < *resource_address { + (XRD, *resource_address) + } else { + (*resource_address, XRD) + }; + + let (mut ociswap_pool, ..) = + OciswapV2PoolInterfaceScryptoTestStub::instantiate( + resource_x, + resource_y, + pdec!(1), + dec!(0.03), + dec!(0.03), + registry.try_into().unwrap(), + vec![], + FAUCET, + ociswap_v2_pool_package, + &mut env, + )?; + + let resource_x = ResourceManager(resource_x) + .mint_fungible(dec!(100_000_000), &mut env)?; + let resource_y = ResourceManager(resource_y) + .mint_fungible(dec!(100_000_000), &mut env)?; + + let _ = ociswap_pool.add_liquidity( + -10_000, 10_000, resource_x, resource_y, &mut env, + )?; + + Ok::<_, RuntimeError>(ociswap_pool) + })?; + + ( + ociswap_v2_pool_package, + ociswap_v2_adapter_v1_package, + ociswap_v2_pools, + ) + }; + + // Instantiating the components. + let mut simple_oracle = SimpleOracle::instantiate( + protocol_manager_rule.clone(), + Default::default(), + OwnerRole::None, + None, + simple_oracle_package, + &mut env, + )?; + let mut ignition = Ignition::instantiate( + Default::default(), + OwnerRole::None, + protocol_owner_rule, + protocol_manager_rule, + XRD.into(), + simple_oracle.try_into().unwrap(), + configuration.maximum_allowed_price_staleness_seconds, + configuration.maximum_allowed_relative_price_difference, + InitializationParameters::default(), + None, + ignition_package, + &mut env, + )?; + let ociswap_v1_adapter_v1 = OciswapV1Adapter::instantiate( + Default::default(), + OwnerRole::None, + None, + ociswap_v1_adapter_v1_package, + &mut env, + )?; + let ociswap_v2_adapter_v1 = OciswapV2Adapter::instantiate( + Default::default(), + OwnerRole::None, + None, + ociswap_v2_adapter_v1_package, + &mut env, + )?; + let caviarnine_v1_adapter_v1 = CaviarnineV1Adapter::instantiate( + Default::default(), + OwnerRole::None, + None, + caviarnine_v1_adapter_v1_package, + &mut env, + )?; + + // Submitting some dummy prices to the oracle to get things going. + resource_addresses.try_map(|resource_address| { + simple_oracle.set_price(*resource_address, XRD, dec!(1), &mut env) + })?; + + // Initializing ignition with information + { + ignition.set_is_open_position_enabled(true, &mut env)?; + ignition.set_is_close_position_enabled(true, &mut env)?; + + ignition.add_reward_rate( + LockupPeriod::from_months(6).unwrap(), + dec!(0.2), + &mut env, + )?; + ignition.add_reward_rate( + LockupPeriod::from_months(12).unwrap(), + dec!(0.4), + &mut env, + )?; + + let xrd_bucket = ResourceManager(XRD) + .mint_fungible(dec!(100_000_000_000_000), &mut env)?; + ignition.deposit_protocol_resources( + FungibleBucket(xrd_bucket), + Volatility::Volatile, + &mut env, + )?; + let xrd_bucket = ResourceManager(XRD) + .mint_fungible(dec!(100_000_000_000_000), &mut env)?; + ignition.deposit_protocol_resources( + FungibleBucket(xrd_bucket), + Volatility::NonVolatile, + &mut env, + )?; + + { + let ResourceInformation { + bitcoin, + ethereum, + usdc, + usdt, + } = resource_addresses; + ignition.insert_user_resource_volatility( + bitcoin, + Volatility::Volatile, + &mut env, + )?; + ignition.insert_user_resource_volatility( + ethereum, + Volatility::Volatile, + &mut env, + )?; + + ignition.insert_user_resource_volatility( + usdc, + Volatility::NonVolatile, + &mut env, + )?; + ignition.insert_user_resource_volatility( + usdt, + Volatility::NonVolatile, + &mut env, + )?; + } + + ignition.insert_pool_information( + OciswapV1PoolInterfaceScryptoTestStub::blueprint_id( + ociswap_v1_package, + ), + PoolBlueprintInformation { + adapter: ociswap_v1_adapter_v1.try_into().unwrap(), + allowed_pools: ociswap_v1_pools + .iter() + .map(|pool| pool.try_into().unwrap()) + .collect(), + liquidity_receipt: ociswap_v1_liquidity_receipt_resource, + }, + &mut env, + )?; + + ignition.insert_pool_information( + OciswapV2PoolInterfaceScryptoTestStub::blueprint_id( + ociswap_v2_package, + ), + PoolBlueprintInformation { + adapter: ociswap_v2_adapter_v1.try_into().unwrap(), + allowed_pools: ociswap_v2_pools + .iter() + .map(|pool| pool.try_into().unwrap()) + .collect(), + liquidity_receipt: ociswap_v2_liquidity_receipt_resource, + }, + &mut env, + )?; + + ignition.insert_pool_information( + CaviarnineV1PoolInterfaceScryptoTestStub::blueprint_id( + caviarnine_v1_package, + ), + PoolBlueprintInformation { + adapter: caviarnine_v1_adapter_v1.try_into().unwrap(), + allowed_pools: caviarnine_v1_pools + .iter() + .map(|pool| pool.try_into().unwrap()) + .collect(), + liquidity_receipt: caviarnine_v1_liquidity_receipt_resource, + }, + &mut env, + )?; + } + + Ok(Self { + environment: env, + resources: resource_addresses, + protocol: ProtocolEntities { + ignition_package_address: ignition_package, + ignition, + oracle_package_address: simple_oracle_package, + oracle: simple_oracle, + protocol_owner_badge, + protocol_manager_badge, + }, + ociswap_v1: DexEntities { + package: ociswap_v1_package, + pools: ociswap_v1_pools, + adapter_package: ociswap_v1_adapter_v1_package, + adapter: ociswap_v1_adapter_v1, + liquidity_receipt: ociswap_v1_liquidity_receipt_resource, + }, + ociswap_v2: DexEntities { + package: ociswap_v2_package, + pools: ociswap_v2_pools, + adapter_package: ociswap_v2_adapter_v1_package, + adapter: ociswap_v2_adapter_v1, + liquidity_receipt: ociswap_v2_liquidity_receipt_resource, + }, + caviarnine_v1: DexEntities { + package: caviarnine_v1_package, + pools: caviarnine_v1_pools, + adapter_package: caviarnine_v1_adapter_v1_package, + adapter: caviarnine_v1_adapter_v1, + liquidity_receipt: caviarnine_v1_liquidity_receipt_resource, + }, + }) + } + + fn publish_package( + name: &str, + env: &mut TestEnvironment, + ) -> Result { + let (code, definition) = package_loader::PackageLoader::get(name); + Package::publish(code, definition, Default::default(), env) + .map(|item| item.0) + } +} + +impl ScryptoUnitEnv { + pub fn new() -> Self { + Self::new_with_configuration(Configuration::default()) + } + + pub fn new_with_configuration(configuration: Configuration) -> Self { + // Flash the substates to the ledger so that they can be used in tests. + let (addresses, db_flash) = + scrypto_decode::<(Vec, DbFlash)>(Self::PACKAGES_BINARY) + .expect("Can't fail!"); + + let caviarnine_v1_package = + PackageAddress::try_from(addresses[0]).unwrap(); + let ociswap_v1_package = + PackageAddress::try_from(addresses[1]).unwrap(); + + let mut test_runner = { + let mut in_memory_substate_database = + InMemorySubstateDatabase::standard(); + in_memory_substate_database.commit(&DatabaseUpdates { + node_updates: db_flash + .into_iter() + .map(|(db_node_key, partition_num_to_updates_mapping)| { + ( + db_node_key, + NodeDatabaseUpdates { + partition_updates: partition_num_to_updates_mapping + .into_iter() + .map(|(partition_num, substates)| { + ( + partition_num, + PartitionDatabaseUpdates::Delta { + substate_updates: substates + .into_iter() + .map(|(db_sort_key, value)| { + (db_sort_key, DatabaseUpdate::Set(value)) + }) + .collect(), + }, + ) + }) + .collect(), + }, + ) + }) + .collect(), + }); + TestRunnerBuilder::new() + .with_custom_database(in_memory_substate_database) + .without_trace() + .build() + }; + + // The account that everything gets deposited into throughout the tests. + let (public_key, private_key, account) = test_runner.new_account(false); + + let protocol_manager_badge = + test_runner.create_fungible_resource(dec!(1), 0, account); + let protocol_owner_badge = + test_runner.create_fungible_resource(dec!(1), 0, account); + + let protocol_manager_rule = rule!(require(protocol_manager_badge)); + let protocol_owner_rule = rule!(require(protocol_owner_badge)); + + let [ignition_package, simple_oracle_package, ociswap_v1_adapter_v1_package, caviarnine_v1_adapter_v1_package] = + Self::PACKAGE_NAMES.map(|package_name| { + let (code, definition) = + package_loader::PackageLoader::get(package_name); + test_runner.publish_package( + (code, definition), + Default::default(), + OwnerRole::None, + ) + }); + + let resource_addresses = + Self::RESOURCE_DIVISIBILITIES.map(|divisibility| { + test_runner.create_freely_mintable_fungible_resource( + OwnerRole::None, + None, + *divisibility, + account, + ) + }); + + let [ociswap_v1_liquidity_receipt_resource, ociswap_v2_liquidity_receipt_resource, caviarnine_v1_liquidity_receipt_resource] = + std::array::from_fn(|_| { + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_function( + RESOURCE_PACKAGE, + NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, + NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT, + NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput { + owner_role: OwnerRole::None, + track_total_supply: true, + non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::>(), + entries: vec![], + resource_roles: NonFungibleResourceRoles { + mint_roles: mint_roles! { + minter => rule!(allow_all); + minter_updater => rule!(allow_all); + }, + burn_roles: burn_roles! { + burner => rule!(allow_all); + burner_updater => rule!(allow_all); + }, + ..Default::default() + }, + metadata: Default::default(), + address_reservation: Default::default(), + }, + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_resource_addresses() + .first() + .copied() + .unwrap() + }); + + let ociswap_v1_pools = resource_addresses.map(|resource_address| { + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .ociswap_v1_pool_instantiate( + ociswap_v1_package, + *resource_address, + XRD, + configuration.fees, + FAUCET, + ) + .build(); + let component_address = *test_runner + .execute_manifest(manifest, vec![]) + .expect_commit_success() + .new_component_addresses() + .first() + .unwrap(); + + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(XRD, dec!(100_000_000)) + .mint_fungible(*resource_address, dec!(100_000_000)) + .take_all_from_worktop(XRD, "xrd_bucket") + .take_all_from_worktop(*resource_address, "other_bucket") + .with_name_lookup(|builder, _| { + let xrd_bucket = builder.bucket("xrd_bucket"); + let other_bucket = builder.bucket("other_bucket"); + builder.ociswap_v1_pool_add_liquidity( + component_address, + xrd_bucket, + other_bucket, + ) + }) + .try_deposit_entire_worktop_or_abort(account, None) + .build(); + test_runner + .execute_manifest_without_auth(manifest) + .expect_commit_success(); + + component_address + }); + + let caviarnine_v1_pools = resource_addresses.map(|resource_address| { + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .allocate_global_address( + caviarnine_v1_package, + "QuantaSwap", + "reservation", + "address", + ) + .mint_fungible(XRD, dec!(100_000_000)) + .mint_fungible(*resource_address, dec!(100_000_000)) + .take_all_from_worktop(XRD, "xrd_bucket") + .take_all_from_worktop(*resource_address, "other_bucket") + .with_name_lookup(|builder, _| { + let reservation = + builder.address_reservation("reservation"); + let address = builder.named_address("address"); + + let xrd_bucket = builder.bucket("xrd_bucket"); + let other_bucket = builder.bucket("other_bucket"); + + builder + .caviarnine_v1_pool_new( + caviarnine_v1_package, + rule!(allow_all), + rule!(allow_all), + *resource_address, + XRD, + 50, + Some(reservation), + ) + .caviarnine_v1_pool_add_liquidity( + address, + other_bucket, + xrd_bucket, + vec![(27000, dec!(100_000_000), dec!(100_000_000))], + ) + }) + .try_deposit_entire_worktop_or_abort(account, None) + .build(); + *test_runner + .execute_manifest_without_auth(manifest) + .expect_commit_success() + .new_component_addresses() + .first() + .unwrap() + }); + + let ( + ociswap_v2_package, + ociswap_v2_adapter_v1_package, + ociswap_v2_pools, + ) = { + let ociswap_v2_pool_package = { + let ociswap_v2_package_wasm = + include_bytes!("../assets/ociswap_v2_pool.wasm"); + let ociswap_v2_package_rpd = + include_bytes!("../assets/ociswap_v2_pool.rpd"); + let ociswap_v2_package_definition = + manifest_decode::( + ociswap_v2_package_rpd, + ) + .unwrap(); + + test_runner.publish_package( + ( + ociswap_v2_package_wasm.to_vec(), + ociswap_v2_package_definition, + ), + Default::default(), + Default::default(), + ) + }; + let ociswap_v2_registry_package = { + let ociswap_v2_package_wasm = + include_bytes!("../assets/ociswap_v2_registry.wasm"); + let ociswap_v2_package_rpd = + include_bytes!("../assets/ociswap_v2_registry.rpd"); + let ociswap_v2_package_definition = + manifest_decode::( + ociswap_v2_package_rpd, + ) + .unwrap(); + + test_runner.publish_package( + ( + ociswap_v2_package_wasm.to_vec(), + ociswap_v2_package_definition, + ), + Default::default(), + Default::default(), + ) + }; + + let registry = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .ociswap_v2_registry_instantiate( + ociswap_v2_registry_package, + GLOBAL_CALLER_VIRTUAL_BADGE, + dec!(0.03), + 10080, + 20, + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + let (code, definition) = + package_loader::PackageLoader::get("ociswap-v2-adapter-v1"); + let ociswap_v2_adapter_v1_package = test_runner.publish_package( + (code, definition), + Default::default(), + OwnerRole::None, + ); + + let ociswap_v2_pools = resource_addresses.map(|resource_address| { + let (resource_x, resource_y) = if XRD < *resource_address { + (XRD, *resource_address) + } else { + (*resource_address, XRD) + }; + + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .ociswap_v2_pool_instantiate( + ociswap_v2_pool_package, + resource_x, + resource_y, + pdec!(1), + dec!(0.03), + dec!(0.03), + registry, + vec![], + FAUCET, + ) + .build(); + let component_address = *test_runner + .execute_manifest(manifest, vec![]) + .expect_commit_success() + .new_component_addresses() + .first() + .unwrap(); + + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(XRD, dec!(100_000_000)) + .mint_fungible(*resource_address, dec!(100_000_000)) + .take_all_from_worktop(resource_x, "resource_x_bucket") + .take_all_from_worktop(resource_y, "resource_y_bucket") + .with_name_lookup(|builder, _| { + let resource_x_bucket = + builder.bucket("resource_x_bucket"); + let resource_y_bucket = + builder.bucket("resource_y_bucket"); + builder.ociswap_v2_pool_add_liquidity( + component_address, + -10_000, + 10_000, + resource_x_bucket, + resource_y_bucket, + ) + }) + .try_deposit_entire_worktop_or_abort(account, None) + .build(); + test_runner + .execute_manifest_without_auth(manifest) + .expect_commit_success(); + + component_address + }); + + ( + ociswap_v2_pool_package, + ociswap_v2_adapter_v1_package, + ociswap_v2_pools, + ) + }; + + let simple_oracle = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_function( + simple_oracle_package, + "SimpleOracle", + "instantiate", + ( + protocol_manager_rule.clone(), + MetadataInit::default(), + OwnerRole::None, + None::, + ), + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + // Submitting some dummy prices to the oracle to get things going. + resource_addresses.map(|resource_address| { + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + simple_oracle, + "set_price", + (*resource_address, XRD, dec!(1)), + ) + .build(), + ) + .expect_commit_success(); + }); + + // Initializing ignition with information + let ignition = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_function( + ignition_package, + "Ignition", + "instantiate", + ( + MetadataInit::default(), + OwnerRole::None, + protocol_owner_rule, + protocol_manager_rule, + XRD, + simple_oracle, + configuration + .maximum_allowed_price_staleness_seconds, + configuration + .maximum_allowed_relative_price_difference, + InitializationParametersManifest::default(), + None::, + ), + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + let [ociswap_v1_adapter_v1, ociswap_v2_adapter_v1, caviarnine_v1_adapter_v1] = + [ + (ociswap_v1_adapter_v1_package, "OciswapV1Adapter"), + (ociswap_v2_adapter_v1_package, "OciswapV2Adapter"), + (caviarnine_v1_adapter_v1_package, "CaviarnineV1Adapter"), + ] + .map(|(package_address, blueprint_name)| { + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_function( + package_address, + blueprint_name, + "instantiate", + ( + MetadataInit::default(), + OwnerRole::None, + None::, + ), + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap() + }); + + // Cache the addresses of the various Caviarnine pools. + test_runner + .execute_manifest_ignoring_fee( + TransactionManifestV1 { + instructions: caviarnine_v1_pools + .iter() + .map(|address| InstructionV1::CallMethod { + address: caviarnine_v1_adapter_v1.into(), + method_name: "preload_pool_information".to_owned(), + args: manifest_args!(address).into(), + }) + .collect(), + blobs: Default::default(), + }, + vec![], + ) + .expect_commit_success(); + + { + let manifest = ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method(ignition, "set_is_open_position_enabled", (true,)) + .call_method(ignition, "set_is_close_position_enabled", (true,)) + .call_method( + ignition, + "add_reward_rate", + (LockupPeriod::from_months(6).unwrap(), dec!(0.2)), + ) + .call_method( + ignition, + "add_reward_rate", + (LockupPeriod::from_months(12).unwrap(), dec!(0.4)), + ) + .mint_fungible(XRD, dec!(200_000_000_000_000)) + .take_from_worktop(XRD, dec!(100_000_000_000_000), "volatile") + .take_from_worktop( + XRD, + dec!(100_000_000_000_000), + "non_volatile", + ) + .with_name_lookup(|builder, _| { + let volatile = builder.bucket("volatile"); + let non_volatile = builder.bucket("non_volatile"); + + builder + .call_method( + ignition, + "deposit_protocol_resources", + (volatile, Volatility::Volatile), + ) + .call_method( + ignition, + "deposit_protocol_resources", + (non_volatile, Volatility::NonVolatile), + ) + }) + .with_name_lookup(|mut builder, _| { + let ResourceInformation { + bitcoin, + ethereum, + usdc, + usdt, + } = resource_addresses; + + for instruction in [ + (bitcoin, Volatility::Volatile), + (ethereum, Volatility::Volatile), + (usdc, Volatility::NonVolatile), + (usdt, Volatility::NonVolatile), + ] + .map(|(address, volatility)| InstructionV1::CallMethod { + address: ignition.into(), + method_name: "insert_user_resource_volatility" + .to_owned(), + args: manifest_args!(address, volatility).into(), + }) { + builder = + builder.add_instruction_advanced(instruction).0; + } + + for ( + adapter_address, + pools, + liquidity_receipt, + package_address, + blueprint_name, + ) in [ + ( + ociswap_v1_adapter_v1, + ociswap_v1_pools, + ociswap_v1_liquidity_receipt_resource, + ociswap_v1_package, + "BasicPool", + ), + ( + ociswap_v2_adapter_v1, + ociswap_v2_pools, + ociswap_v2_liquidity_receipt_resource, + ociswap_v2_package, + "LiquidityPool", + ), + ( + caviarnine_v1_adapter_v1, + caviarnine_v1_pools, + caviarnine_v1_liquidity_receipt_resource, + caviarnine_v1_package, + "QuantaSwap", + ), + ] { + builder = builder.call_method( + ignition, + "insert_pool_information", + ( + BlueprintId { + package_address, + blueprint_name: blueprint_name.to_owned(), + }, + ( + adapter_address, + pools.iter().collect::>(), + liquidity_receipt, + ), + ), + ); + } + + builder + }) + .build(); + test_runner + .execute_manifest_with_enabled_modules( + manifest, + EnabledModules::for_test_transaction() + & !EnabledModules::AUTH + & !EnabledModules::COSTING, + ) + .expect_commit_success(); + } + + Self { + environment: test_runner, + resources: resource_addresses, + protocol: ProtocolEntities { + ignition_package_address: ignition_package, + ignition, + oracle_package_address: simple_oracle_package, + oracle: simple_oracle, + protocol_owner_badge: ( + public_key.into(), + Secp256k1PrivateKey::from_bytes(&private_key.to_bytes()) + .unwrap() + .into(), + account, + protocol_owner_badge, + ), + protocol_manager_badge: ( + public_key.into(), + private_key.into(), + account, + protocol_manager_badge, + ), + }, + ociswap_v1: DexEntities { + package: ociswap_v1_package, + pools: ociswap_v1_pools, + adapter_package: ociswap_v1_adapter_v1_package, + adapter: ociswap_v1_adapter_v1, + liquidity_receipt: ociswap_v1_liquidity_receipt_resource, + }, + ociswap_v2: DexEntities { + package: ociswap_v2_package, + pools: ociswap_v2_pools, + adapter_package: ociswap_v2_adapter_v1_package, + adapter: ociswap_v2_adapter_v1, + liquidity_receipt: ociswap_v2_liquidity_receipt_resource, + }, + caviarnine_v1: DexEntities { + package: caviarnine_v1_package, + pools: caviarnine_v1_pools, + adapter_package: caviarnine_v1_adapter_v1_package, + adapter: caviarnine_v1_adapter_v1, + liquidity_receipt: caviarnine_v1_liquidity_receipt_resource, + }, + } + } +} + +impl Default for ScryptoUnitEnv { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug)] +pub struct ProtocolEntities +where + S: EnvironmentSpecifier, +{ + /* Ignition */ + pub ignition_package_address: PackageAddress, + pub ignition: S::Ignition, + /* Oracle */ + pub oracle_package_address: PackageAddress, + pub oracle: S::SimpleOracle, + /* Badges */ + pub protocol_owner_badge: S::Badge, + pub protocol_manager_badge: S::Badge, +} + +/// A struct that defines the entities that belong to a Decentralized Exchange. +/// it contains the package address as well as generic items [`T`] which are +/// the stubs used to call the pools. +#[derive(Copy, Clone, Debug)] +pub struct DexEntities { + /* Packages */ + pub package: PackageAddress, + /* Pools */ + pub pools: ResourceInformation

, + /* Adapter */ + pub adapter_package: PackageAddress, + pub adapter: A, + /* Receipt */ + pub liquidity_receipt: ResourceAddress, +} + +#[derive(Clone, Debug, Copy)] +pub struct ResourceInformation { + pub bitcoin: T, + pub ethereum: T, + pub usdc: T, + pub usdt: T, +} + +impl ResourceInformation { + pub fn map(&self, mut map: F) -> ResourceInformation + where + F: FnMut(&T) -> O, + { + ResourceInformation:: { + bitcoin: map(&self.bitcoin), + ethereum: map(&self.ethereum), + usdc: map(&self.usdc), + usdt: map(&self.usdt), + } + } + + pub fn try_map( + &self, + mut map: F, + ) -> Result, E> + where + F: FnMut(&T) -> Result, + { + Ok(ResourceInformation:: { + bitcoin: map(&self.bitcoin)?, + ethereum: map(&self.ethereum)?, + usdc: map(&self.usdc)?, + usdt: map(&self.usdt)?, + }) + } + + pub fn iter(self) -> impl Iterator { + [self.bitcoin, self.ethereum, self.usdc, self.usdt].into_iter() + } + + pub fn zip( + self, + other: ResourceInformation, + ) -> ResourceInformation<(T, O)> { + ResourceInformation { + bitcoin: (self.bitcoin, other.bitcoin), + ethereum: (self.ethereum, other.ethereum), + usdc: (self.usdc, other.usdc), + usdt: (self.usdt, other.usdt), + } + } +} + +#[derive(Clone, Debug)] +pub struct Configuration { + pub fees: Decimal, + pub maximum_allowed_price_staleness_seconds: i64, + pub maximum_allowed_relative_price_difference: Decimal, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + // 1% + fees: dec!(0.01), + // 5 Minutes + maximum_allowed_price_staleness_seconds: 300i64, + // 1% + maximum_allowed_relative_price_difference: dec!(0.01), + } + } +} diff --git a/tests/src/errors.rs b/tests/src/errors.rs new file mode 100644 index 00000000..7ec32ccf --- /dev/null +++ b/tests/src/errors.rs @@ -0,0 +1,75 @@ +use crate::prelude::*; + +macro_rules! define_error_checking_functions { + ( + $( + $prefix: ident => [ + $( + $error: ident + ),* $(,)? + ] + ),* $(,)? + ) => { + paste::paste! { + $( + $( + #[must_use] + pub fn [< is_ $prefix:snake _ $error:lower:camel:snake >]( + error: &Result + ) -> bool { + matches!( + error, + Err(::scrypto_test::prelude::RuntimeError::ApplicationError( + ::scrypto_test::prelude::ApplicationError::PanicMessage(error) + )) + if error.contains($error) + ) + } + + pub fn [< assert_is_ $prefix:snake _ $error:lower:camel:snake >]( + error: &Result + ) + where + T: Debug + { + assert!( + [< is_ $prefix:snake _ $error:lower:camel:snake >](error), + "Running \"{}\" against {:?} failed", + stringify!([< assert_is_ $prefix:snake _ $error:lower:camel:snake >]), + error + ) + } + )* + )* + } + }; +} + +define_error_checking_functions! { + ignition => [ + NO_ADAPTER_FOUND_FOR_POOL_ERROR, + NEITHER_POOL_RESOURCE_IS_PROTOCOL_RESOURCE_ERROR, + NO_ASSOCIATED_VAULT_ERROR, + NO_ASSOCIATED_LIQUIDITY_RECEIPT_VAULT_ERROR, + NOT_AN_IGNITION_ADDRESS_ERROR, + OPENING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR, + CLOSING_LIQUIDITY_POSITIONS_IS_CLOSED_ERROR, + NO_REWARDS_RATE_ASSOCIATED_WITH_LOCKUP_PERIOD_ERROR, + POOL_IS_NOT_IN_ALLOW_LIST_ERROR, + ORACLE_REPORTED_PRICE_IS_STALE_ERROR, + LOCKUP_PERIOD_HAS_NO_ASSOCIATED_REWARDS_RATE_ERROR, + UNEXPECTED_ERROR, + RELATIVE_PRICE_DIFFERENCE_LARGER_THAN_ALLOWED_ERROR, + USER_ASSET_DOES_NOT_BELONG_TO_POOL_ERROR, + MORE_THAN_ONE_LIQUIDITY_RECEIPT_NFTS_ERROR, + NOT_A_VALID_LIQUIDITY_RECEIPT_ERROR, + LIQUIDITY_POSITION_HAS_NOT_MATURED_ERROR, + USER_MUST_NOT_PROVIDE_PROTOCOL_ASSET_ERROR, + USER_RESOURCES_VOLATILITY_UNKNOWN_ERROR, + ], + ociswap_adapter => [ + FAILED_TO_GET_RESOURCE_ADDRESSES_ERROR, + FAILED_TO_GET_VAULT_ERROR, + PRICE_IS_UNDEFINED + ] +} diff --git a/tests/src/extensions.rs b/tests/src/extensions.rs new file mode 100644 index 00000000..24d3eaf6 --- /dev/null +++ b/tests/src/extensions.rs @@ -0,0 +1,64 @@ +use crate::prelude::*; +use extend::ext; + +#[ext] +pub impl DefaultTestRunner { + fn execute_manifest_without_auth( + &mut self, + manifest: TransactionManifestV1, + ) -> TransactionReceiptV1 { + self.execute_manifest_with_enabled_modules( + manifest, + EnabledModules::for_test_transaction() & !EnabledModules::AUTH, + ) + } + + fn execute_manifest_with_enabled_modules( + &mut self, + manifest: TransactionManifestV1, + enabled_modules: EnabledModules, + ) -> TransactionReceiptV1 { + let mut execution_config = ExecutionConfig::for_test_transaction(); + execution_config.enabled_modules = enabled_modules; + + let nonce = self.next_transaction_nonce(); + let test_transaction = TestTransaction::new_from_nonce(manifest, nonce); + let prepared_transaction = test_transaction.prepare().unwrap(); + let executable = + prepared_transaction.get_executable(Default::default()); + self.execute_transaction( + executable, + Default::default(), + execution_config, + ) + } + + /// Constructs a notarized transaction and executes it. This is primarily + /// used in the testing of fees to make sure that they're approximated in + /// the best way. + fn construct_and_execute_notarized_transaction( + &mut self, + manifest: TransactionManifestV1, + notary_private_key: &PrivateKey, + ) -> TransactionReceiptV1 { + let network_definition = NetworkDefinition::simulator(); + let current_epoch = self.get_current_epoch(); + let transaction = TransactionBuilder::new() + .header(TransactionHeaderV1 { + network_id: network_definition.id, + start_epoch_inclusive: current_epoch, + end_epoch_exclusive: current_epoch.after(10).unwrap(), + nonce: self.next_transaction_nonce(), + notary_public_key: notary_private_key.public_key(), + notary_is_signatory: true, + tip_percentage: 0, + }) + .manifest(manifest) + .notarize(notary_private_key) + .build(); + self.execute_raw_transaction( + &network_definition, + &transaction.to_raw().unwrap(), + ) + } +} diff --git a/tests/src/indexed_buckets.rs b/tests/src/indexed_buckets.rs new file mode 100644 index 00000000..1fcc90ff --- /dev/null +++ b/tests/src/indexed_buckets.rs @@ -0,0 +1,96 @@ +use crate::prelude::*; + +/// Buckets indexed and aggregated by the resource address. +pub struct IndexedBuckets(IndexMap); + +impl IndexedBuckets { + pub fn new() -> Self { + Self(Default::default()) + } + + pub fn from_bucket( + bucket: impl Into, + api: &mut Y, + ) -> Result + where + Y: ClientApi, + E: Debug + ScryptoCategorize + ScryptoDecode, + { + let mut this = Self::new(); + this.insert(bucket, api)?; + Ok(this) + } + + pub fn from_buckets( + buckets: impl IntoIterator>, + api: &mut Y, + ) -> Result + where + Y: ClientApi, + E: Debug + ScryptoCategorize + ScryptoDecode, + { + let mut this = Self::new(); + + for bucket in buckets.into_iter() { + this.insert(bucket, api)?; + } + + Ok(this) + } + + pub fn get(&self, resource_address: &ResourceAddress) -> Option<&Bucket> { + self.0.get(resource_address) + } + + pub fn get_mut( + &mut self, + resource_address: &ResourceAddress, + ) -> Option<&mut Bucket> { + self.0.get_mut(resource_address) + } + + pub fn insert( + &mut self, + bucket: impl Into, + api: &mut Y, + ) -> Result<(), E> + where + Y: ClientApi, + E: Debug + ScryptoCategorize + ScryptoDecode, + { + let bucket = bucket.into(); + let resource_address = bucket.resource_address(api)?; + if let Some(existing_bucket) = self.0.get_mut(&resource_address) { + existing_bucket.put(bucket, api)?; + } else { + self.0.insert(resource_address, bucket); + }; + Ok(()) + } + + pub fn keys(&self) -> impl Iterator { + self.0.keys() + } + + pub fn values(&self) -> impl Iterator { + self.0.values() + } + + pub fn values_mut(&mut self) -> impl Iterator { + self.0.values_mut() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len(&self) -> usize { + self.0.len() + } +} + +impl Default for IndexedBuckets { + fn default() -> Self { + Self::new() + } +} diff --git a/tests/src/lib.rs b/tests/src/lib.rs new file mode 100644 index 00000000..17aae498 --- /dev/null +++ b/tests/src/lib.rs @@ -0,0 +1,9 @@ +//! The test files only contain tests while any functionality that they all need +//! to have in common is implemented in this library. + +mod environment; +mod errors; +mod extensions; +mod indexed_buckets; + +pub mod prelude; diff --git a/tests/src/prelude.rs b/tests/src/prelude.rs new file mode 100644 index 00000000..ad9a7ab7 --- /dev/null +++ b/tests/src/prelude.rs @@ -0,0 +1,29 @@ +#![allow(ambiguous_glob_reexports, ambiguous_glob_imports)] + +pub use crate::environment::*; +pub use crate::errors::*; +pub use crate::extensions::*; +pub use crate::indexed_buckets::*; + +pub use radix_engine::system::system_db_reader::*; +pub use radix_engine_common::prelude::*; +pub use radix_engine_interface::api::node_modules::auth::*; +pub use radix_engine_interface::prelude::*; +pub use scrypto_test::prelude::*; +pub use scrypto_unit::*; + +pub use ::caviarnine_v1_adapter_v1::test_bindings::*; +pub use ::ignition::test_bindings::*; +pub use ::ignition::*; +pub use ::ociswap_v1_adapter_v1::test_bindings::*; +pub use ::ociswap_v2_adapter_v1::test_bindings::*; +pub use ::simple_oracle::test_bindings::*; + +pub use ::caviarnine_v1_adapter_v1::*; +pub use ::ociswap_v1_adapter_v1::*; +pub use ::ociswap_v2_adapter_v1::*; + +pub use ::common::prelude::*; +pub use ::ports_interface::prelude::*; + +pub use ::sbor; diff --git a/tests/tests/caviarnine_v1.rs b/tests/tests/caviarnine_v1.rs new file mode 100644 index 00000000..d11f1a27 --- /dev/null +++ b/tests/tests/caviarnine_v1.rs @@ -0,0 +1,1220 @@ +use tests::prelude::*; + +#[test] +pub fn can_open_a_simple_position_against_a_caviarnine_pool( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + caviarnine_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + protocol + .ignition + .set_maximum_allowed_price_difference_percentage(dec!(0.50), env)?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +pub fn liquidity_receipt_information_can_be_read_through_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + mut caviarnine_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + protocol + .ignition + .set_maximum_allowed_price_difference_percentage(dec!(0.50), env)?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + // Act + let data = caviarnine_v1.adapter.liquidity_receipt_data( + NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ), + env, + )?; + + // Assert + assert_eq!( + data.adapter_specific_information.bin_contributions.len(), + 61 + ); + + Ok(()) +} + +#[test] +fn can_open_a_liquidity_position_in_caviarnine_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + caviarnine_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + test_runner + .execute_manifest_with_enabled_modules( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + caviarnine_v1.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + EnabledModules::for_test_transaction() + & !EnabledModules::AUTH + & !EnabledModules::COSTING, + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + caviarnine_v1.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + .. + } = receipt.fee_summary; + println!( + "Execution cost to open a position: {} XRD", + total_execution_cost_in_xrd + ); + + assert!(total_execution_cost_in_xrd <= dec!(4.8)) +} + +#[test] +fn can_close_a_liquidity_position_in_caviarnine_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + caviarnine_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + for _ in 0..2 { + test_runner + .execute_manifest_with_enabled_modules( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + caviarnine_v1.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + EnabledModules::for_test_transaction() + & !EnabledModules::AUTH + & !EnabledModules::COSTING, + ) + .expect_commit_success(); + } + + let current_time = test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(); + { + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000 } + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from(maturity_instant.seconds_since_unix_epoch / 60).unwrap(), + } + ), + ) + .unwrap(); + } + + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resources.bitcoin, XRD, dec!(1)), + ) + .build(), + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + caviarnine_v1.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(caviarnine_v1.liquidity_receipt, "receipt") + .with_bucket("receipt", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + .. + } = receipt.fee_summary; + println!( + "Execution cost to close a position: {} XRD", + total_execution_cost_in_xrd + ); + + assert!(total_execution_cost_in_xrd <= dec!(4.8)) +} + +#[test] +fn contributions_directly_to_caviarnine_could_fail_due_to_bucket_order( +) -> Result<(), RuntimeError> { + // Arrange + let mut results = Vec::::new(); + for order in [true, false] { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut caviarnine_v1, + .. + } = ScryptoTestEnv::new()?; + + let xrd_bucket = ResourceManager(XRD).mint_fungible(dec!(1), env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(1), env)?; + let buckets = if order { + (xrd_bucket, bitcoin_bucket) + } else { + (bitcoin_bucket, xrd_bucket) + }; + + // Act + let result = caviarnine_v1.pools.bitcoin.add_liquidity( + buckets.0, + buckets.1, + vec![(27000, dec!(1), dec!(1))], + env, + ); + results.push(result.is_ok()); + } + + // Assert + assert_eq!(results.len(), 2); + assert_eq!(results.iter().filter(|item| **item).count(), 1); + assert_eq!(results.iter().filter(|item| !**item).count(), 1); + + Ok(()) +} + +#[test] +fn contributions_to_caviarnine_through_adapter_dont_fail_due_to_bucket_ordering( +) -> Result<(), RuntimeError> { + // Arrange + let mut results = Vec::::new(); + for order in [true, false] { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut caviarnine_v1, + .. + } = ScryptoTestEnv::new()?; + + let xrd_bucket = ResourceManager(XRD).mint_fungible(dec!(1), env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(1), env)?; + let buckets = if order { + (xrd_bucket, bitcoin_bucket) + } else { + (bitcoin_bucket, xrd_bucket) + }; + + // Act + let result = caviarnine_v1.adapter.open_liquidity_position( + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + buckets, + env, + ); + results.push(result.is_ok()); + } + + // Assert + assert_eq!(results.len(), 2); + assert_eq!(results.iter().filter(|item| **item).count(), 2); + + Ok(()) +} + +#[test] +fn liquidity_receipt_includes_the_amount_of_liquidity_positions_we_expect_to_see( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + caviarnine_v1, + .. + } = ScryptoTestEnv::new()?; + protocol + .ignition + .set_maximum_allowed_price_difference_percentage(dec!(0.50), env)?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let (liquidity_receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + // Act + let liquidity_receipt_data = + ResourceManager(caviarnine_v1.liquidity_receipt) + .get_non_fungible_data::<_, _, LiquidityReceipt>( + liquidity_receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + env, + )?; + + // Assert + let adapter_information = liquidity_receipt_data + .adapter_specific_information + .as_typed::() + .unwrap(); + assert_eq!( + adapter_information.bin_contributions.len(), + (PREFERRED_TOTAL_NUMBER_OF_HIGHER_AND_LOWER_BINS + 1) as usize + ); + + Ok(()) +} + +#[test] +pub fn contribution_amount_reported_in_receipt_nft_matches_caviarnine_state( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + caviarnine_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + protocol + .ignition + .set_maximum_allowed_price_difference_percentage(dec!(0.50), env)?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let (ignition_receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + // Assert + let ignition_receipt_global_id = { + let local_id = ignition_receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(); + NonFungibleGlobalId::new(caviarnine_v1.liquidity_receipt, local_id) + }; + let ignition_receipt_data = + ResourceManager(caviarnine_v1.liquidity_receipt) + .get_non_fungible_data::<_, _, LiquidityReceipt>( + ignition_receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + env, + )?; + + let caviarnine_receipt = protocol + .ignition + .withdraw_pool_units(ignition_receipt_global_id, env)?; + + let mut caviarnine_reported_contributions = + caviarnine_v1.pools.bitcoin.get_redemption_bin_values( + caviarnine_receipt + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + env, + )?; + caviarnine_reported_contributions.sort_by(|a, b| a.0.cmp(&b.0)); + + let adapter_reported_contributions = ignition_receipt_data + .adapter_specific_information + .as_typed::() + .unwrap() + .contributions(); + + assert_eq!( + adapter_reported_contributions.len(), + caviarnine_reported_contributions.len() + ); + for (x, y) in adapter_reported_contributions + .into_iter() + .zip(caviarnine_reported_contributions) + { + assert_eq!(x.0, y.0); + assert!(approximately_equals(x.1, y.1)); + assert!(approximately_equals(x.2, y.2)); + } + + Ok(()) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_stays_the_same_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_down_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_up_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_stays_the_same_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_down_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_up_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_stays_the_same_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_down_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_up_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +fn non_strict_testing_of_fees( + protocol_coefficient: Movement, + price_of_user_asset: Movement, + result: CloseLiquidityResult, +) -> Result<(), RuntimeError> { + let Environment { + environment: ref mut env, + mut protocol, + mut caviarnine_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let pool_reported_price = caviarnine_v1 + .adapter + .price(caviarnine_v1.pools.bitcoin.try_into().unwrap(), env)?; + protocol.oracle.set_price( + pool_reported_price.base, + pool_reported_price.quote, + pool_reported_price.price, + env, + )?; + + let bitcoin_amount_in = dec!(100); + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(bitcoin_amount_in, env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let pool_units = caviarnine_v1 + .adapter + .open_liquidity_position( + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + ( + ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000), env)?, + ResourceManager(XRD).mint_fungible(dec!(100_000), env)?, + ), + env, + )? + .pool_units; + + match price_of_user_asset { + // User asset price goes down - i.e., we inject it into the pool. + Movement::Down => { + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(450_000_000), env)?; + let _ = caviarnine_v1.pools.bitcoin.swap(bitcoin_bucket, env)?; + } + // The user asset price stays the same. We do not do anything. + Movement::Same => {} + // User asset price goes up - i.e., we reduce it in the pool. + Movement::Up => { + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(450_000_000), env)?; + let _ = caviarnine_v1.pools.bitcoin.swap(xrd_bucket, env)?; + } + } + + match protocol_coefficient { + // Somebody claimed some portion of the pool + Movement::Down => { + let _ = caviarnine_v1 + .pools + .bitcoin + .remove_liquidity(pool_units, env)?; + } + // Nothing + Movement::Same => {} + // Somebody contributed to the pool some amount + Movement::Up => { + let _ = caviarnine_v1 + .adapter + .open_liquidity_position( + caviarnine_v1.pools.bitcoin.try_into().unwrap(), + ( + ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000), env)?, + ResourceManager(XRD) + .mint_fungible(dec!(100_000), env)?, + ), + env, + )? + .pool_units; + } + } + + env.set_current_time(Instant::new( + *LockupPeriod::from_months(12).unwrap().seconds() as i64, + )); + let pool_reported_price = caviarnine_v1 + .adapter + .price(caviarnine_v1.pools.bitcoin.try_into().unwrap(), env)?; + protocol.oracle.set_price( + pool_reported_price.base, + pool_reported_price.quote, + pool_reported_price.price, + env, + )?; + + let buckets = IndexedBuckets::from_buckets( + protocol.ignition.close_liquidity_position(receipt, env)?, + env, + )?; + + let bitcoin_amount_out = buckets + .get(&resources.bitcoin) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToPositiveInfinity) + .unwrap(); + let xrd_amount_out = buckets + .get(&XRD) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToZero) + .unwrap(); + + match result { + CloseLiquidityResult::GetFees => { + // Bitcoin we get back must be strictly greater than what we put in. + assert!(bitcoin_amount_out > bitcoin_amount_in); + // When we get back fees we MUST not get back any XRD + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::SameAmount => { + // Bitcoin we get back must be strictly equal to what we put in. + assert_eq!(bitcoin_amount_out, bitcoin_amount_in); + // If we get back the same amount then we must NOT get back any XRD. + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::Reimbursement => { + // Bitcoin we get back must be less than what we put in. + assert!(bitcoin_amount_out < bitcoin_amount_in); + // We must get back SOME xrd. + assert_ne!(xrd_amount_out, Decimal::ZERO); + } + } + + Ok(()) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Movement { + Down, + Same, + Up, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum CloseLiquidityResult { + GetFees, + SameAmount, + Reimbursement, +} + +#[allow(clippy::arithmetic_side_effects)] +fn approximately_equals(a: Decimal, b: Decimal) -> bool { + let difference = match (a == Decimal::ZERO, b == Decimal::ZERO) { + (true, true) => dec!(0), + (true, false) => (b - a).checked_abs().unwrap() / b, + (false, true) => (b - a).checked_abs().unwrap() / a, + (false, false) => (b - a).checked_abs().unwrap() / b, + }; + difference <= dec!(0.000001) +} + +#[test] +pub fn price_and_active_tick_reported_by_adapter_must_match_whats_reported_by_pool( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut caviarnine_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + env.disable_limits_module(); + + let bin_span = 100u32; + for bin in (0u32..=54000u32).step_by(bin_span as usize) { + let mut pool = CaviarnineV1PoolInterfaceScryptoTestStub::new( + rule!(allow_all), + rule!(allow_all), + XRD, + resources.bitcoin, + bin_span, + None, + caviarnine_v1.package, + env, + )?; + + let bucket_x = ResourceManager(XRD).mint_fungible(dec!(100), env)?; + let bucket_y = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let _ = pool.add_liquidity( + bucket_x, + bucket_y, + vec![(bin, dec!(100), dec!(100))], + env, + )?; + + // Act + let (adapter_reported_price, adapter_reported_active_tick) = + caviarnine_v1 + .adapter + .price_and_active_tick( + pool.try_into().unwrap(), + Some(PoolInformation { + bin_span, + resources: ResourceIndexedData { + resource_x: XRD, + resource_y: resources.bitcoin, + }, + }), + env, + )? + .unwrap(); + + // Assert + let pool_reported_price = pool.get_price(env)?.unwrap(); + let pool_reported_active_tick = pool.get_active_tick(env)?.unwrap(); + assert_eq!(adapter_reported_price, pool_reported_price); + assert_eq!(adapter_reported_active_tick, pool_reported_active_tick); + } + + Ok(()) +} + +#[test] +fn positions_can_be_opened_at_current_price_and_closed_at_a_100x_price_decrease_on_100_bps_pools( +) { + test_effect_of_price_action_on_fees(-100, 100) +} + +fn test_effect_of_price_action_on_fees(multiplier: i32, bin_span: u32) { + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + caviarnine_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + let resource_x = XRD; + let resource_y = resources.bitcoin; + + let pool_address = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .caviarnine_v1_pool_new( + caviarnine_v1.package, + rule!(allow_all), + rule!(allow_all), + resource_x, + resource_y, + bin_span, + None, + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + // We're allowed to contribute to 200 bins. So, we will contribute to all of + // them. This ensures that the maximum amount of price range is covered by + // our liquidity. + { + let positions = vec![(27000u32, dec!(100_000_000), dec!(100_000_000))] + .into_iter() + .chain((1..=99).flat_map(|i| { + vec![ + ( + 27000 - i * bin_span, + dec!(0), + dec!(100_000_000) - Decimal::from(i), + ), + ( + 27000 + i * bin_span, + dec!(100_000_000) + Decimal::from(i), + dec!(0), + ), + ] + })) + .collect::>(); + let x_amount_required = positions + .iter() + .map(|v| v.1) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + let y_amount_required = positions + .iter() + .map(|v| v.2) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + + test_runner + .execute_manifest_with_enabled_modules( + ManifestBuilder::new() + .mint_fungible(resource_x, x_amount_required) + .mint_fungible(resource_y, y_amount_required) + .take_all_from_worktop(resource_x, "resources_x") + .take_all_from_worktop(resource_y, "resources_y") + .with_name_lookup(|builder, namer| { + let resources_x = namer.bucket("resources_x"); + let resources_y = namer.bucket("resources_y"); + + builder.caviarnine_v1_pool_add_liquidity( + pool_address, + resources_x, + resources_y, + positions, + ) + }) + .deposit_batch(account_address) + .build(), + EnabledModules::for_notarized_transaction() + & !EnabledModules::AUTH + & !EnabledModules::COSTING, + ) + .expect_commit_success(); + } + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Updating the price in the Oracle component. + let price = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .caviarnine_v1_pool_get_price(pool_address) + .build(), + vec![], + ) + .expect_commit_success() + .output::>(1) + .unwrap(); + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / price), + ) + .build(), + ) + .expect_commit_success(); + + // Minting some of the resource and depositing them into the user's + // account. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_y, dec!(100_000)) + .deposit_batch(account_address) + .build(), + ) + .expect_commit_success(); + + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account(account_address, resource_y, dec!(1000)) + .take_all_from_worktop(resource_y, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + pool_address, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Open - Multiplier = {}x, Bin Span = {}, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + bin_span, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); + + // Set the current time to be 6 months from now. + { + let current_time = + test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = + current_time + .add_seconds( + *LockupPeriod::from_months(6).unwrap().seconds() as i64 + ) + .unwrap(); + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { + epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000, + }, + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from( + maturity_instant.seconds_since_unix_epoch / 60, + ) + .unwrap(), + }, + ), + ) + .unwrap(); + } + + // Move the price according to the specified multiplier + let new_price = if multiplier.is_positive() { + let target_price = price * multiplier; + let input_resource = resource_y; + let amount_in_each_swap = dec!(100_000_000); + + let mut new_price = price; + while new_price < target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder + .caviarnine_v1_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(5) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + } else { + let target_price = price / multiplier * dec!(-1); + let input_resource = resource_x; + let amount_in_each_swap = dec!(1_000_000_000); + + let mut new_price = price; + while new_price > target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder + .caviarnine_v1_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(5) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + }; + + // Submit the new price to the oracle + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, new_price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / new_price), + ) + .build(), + ) + .expect_commit_success(); + + // Close the position + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account( + account_address, + caviarnine_v1.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(caviarnine_v1.liquidity_receipt, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Close - Multiplier = {}x, Bin Span = {}, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + bin_span, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); +} diff --git a/tests/tests/caviarnine_v1_simulation.rs b/tests/tests/caviarnine_v1_simulation.rs new file mode 100644 index 00000000..36accb9a --- /dev/null +++ b/tests/tests/caviarnine_v1_simulation.rs @@ -0,0 +1,1130 @@ +//! This test module's purpose is to test Ignition's ability to open liquidity +//! positions in Caviarnine's pools that are already on mainnet and especially +//! if we can do so within the fee limit. Therefore, this test module creates +//! pools in the local test environment that are identical or close as possible +//! to the mainnet pools with the same amount of liquidity on both sides and +//! attempts to open positions against them. The information on how much is +//! current in the pool is obtained from the gateway. Therefore, this module +//! relies on the current state and can very much not be deterministic in some +//! cases on how much fees are required. However, it is the best way we have +//! found to test the C9 pools in a "real environment" and ensuring that what +//! we have works with C9. + +use gateway_client::apis::configuration::Configuration as GatewayConfig; +use gateway_client::apis::transaction_api::*; +use gateway_client::models::*; +use tests::prelude::*; + +#[test] +fn can_open_and_close_positions_to_all_mainnet_caviarnine_pools() { + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + caviarnine_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + + let (public_key, private_key, account) = test_runner.new_account(false); + + let pool_information = mainnet_state::pool_information(&resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + + for ( + mainnet_state::PoolInformation { + resource_x, + resource_y, + active_tick, + bin_span, + bins_below, + bins_above, + price, + }, + divisibility, + ) in pool_information.iter() + { + let resource_address = if resource_x == XRD { + resource_y + } else { + resource_x + }; + + let mut amount_in_bins = { + let mut amount = indexmap! {}; + + for (tick, amount_x) in bins_above { + let (x, _) = amount.entry(tick).or_insert((dec!(0), dec!(0))); + *x = amount_x + *x; + } + + for (tick, amount_y) in bins_below { + let (_, y) = amount.entry(tick).or_insert((dec!(0), dec!(0))); + *y = amount_y + *y; + } + + amount + }; + + // Creating a new pool with the same information as this provided pool. + let pool_address = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .caviarnine_v1_pool_new( + caviarnine_v1.package, + rule!(deny_all), + rule!(allow_all), + resource_x, + resource_y, + bin_span, + None, + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + // Providing the liquidity to the pools. + let (divisibility_x, divisibility_y) = if resource_x == XRD { + (18, divisibility) + } else { + (divisibility, 18) + }; + + let amount_x = amount_in_bins + .values() + .map(|x| x.0) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + let amount_y = amount_in_bins + .values() + .map(|x| x.1) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + + let amount_x = amount_x + .checked_round(divisibility_x, RoundingMode::ToPositiveInfinity) + .unwrap(); + let amount_y = amount_y + .checked_round(divisibility_y, RoundingMode::ToPositiveInfinity) + .unwrap(); + + let active_amounts = + amount_in_bins.remove(&active_tick.unwrap()).unwrap(); + let positions = + vec![(active_tick.unwrap(), active_amounts.0, active_amounts.1)] + .into_iter() + .chain(amount_in_bins.into_iter().map(|(k, v)| { + ( + k, + v.0.checked_round(divisibility_x, RoundingMode::ToZero) + .unwrap(), + v.1.checked_round(divisibility_y, RoundingMode::ToZero) + .unwrap(), + ) + })) + .collect::>(); + + let price_in_simulated_pool = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_x, amount_x) + .mint_fungible(resource_y, amount_y) + .take_all_from_worktop(resource_x, "resource_x") + .take_all_from_worktop(resource_y, "resource_y") + .with_bucket("resource_x", |builder, bucket_x| { + builder.with_bucket( + "resource_y", + |builder, bucket_y| { + builder.caviarnine_v1_pool_add_liquidity( + pool_address, + bucket_x, + bucket_y, + positions, + ) + }, + ) + }) + .deposit_batch(account) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(7) + .unwrap(); + + // If this assertion passes, then the pool we've created should be in + // the same state as the mainnet one. + assert_eq!(price_in_simulated_pool, price.unwrap()); + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Updating the oracle price + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, price_in_simulated_pool), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / price_in_simulated_pool), + ) + .build(), + ) + .expect_commit_success(); + + // Minting some of the resource and depositing them into the user's + // account. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_address, dec!(1000)) + .deposit_batch(account) + .build(), + ) + .expect_commit_success(); + + // Cache the pool information - Note on this, the Caviarnine pools + // literally require this and if the information is not cached we can + // sometimes run out of cost units in the execution. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + caviarnine_v1.adapter, + "preload_pool_information", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Constructing a transaction that is as close as possible to a real one + // to open a liquidity position and ensure that we can open one with the + // fee limit that we currently have. + let current_epoch = test_runner.get_current_epoch(); + let transaction = TransactionBuilder::new() + .header(TransactionHeaderV1 { + network_id: 0xf2, + start_epoch_inclusive: current_epoch, + end_epoch_exclusive: current_epoch.after(10).unwrap(), + nonce: test_runner.next_transaction_nonce(), + notary_public_key: public_key.into(), + notary_is_signatory: true, + tip_percentage: 0, + }) + .manifest( + ManifestBuilder::new() + .lock_fee(account, dec!(10)) + .withdraw_from_account( + account, + resource_address, + dec!(1000), + ) + .take_all_from_worktop(resource_address, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + pool_address, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .deposit_batch(account) + .build(), + ) + .notarize(&private_key) + .build(); + let receipt = test_runner.execute_raw_transaction( + &NetworkDefinition::simulator(), + &transaction.to_raw().unwrap(), + ); + receipt.expect_commit_success(); + println!( + "Opening a position costs {} XRD in total with {} XRD in execution", + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); + + // Set the current time to be 6 months from now. + { + let current_time = + test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = current_time + .add_seconds( + *LockupPeriod::from_months(6).unwrap().seconds() as i64 + ) + .unwrap(); + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { + epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000, + }, + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from( + maturity_instant.seconds_since_unix_epoch / 60, + ) + .unwrap(), + }, + ), + ) + .unwrap(); + } + + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, price_in_simulated_pool), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / price_in_simulated_pool), + ) + .build(), + ) + .expect_commit_success(); + + // Close the liquidity position. + let current_epoch = test_runner.get_current_epoch(); + let transaction = TransactionBuilder::new() + .header(TransactionHeaderV1 { + network_id: 0xf2, + start_epoch_inclusive: current_epoch, + end_epoch_exclusive: current_epoch.after(10).unwrap(), + nonce: test_runner.next_transaction_nonce(), + notary_public_key: public_key.into(), + notary_is_signatory: true, + tip_percentage: 0, + }) + .manifest( + ManifestBuilder::new() + .lock_fee(account, dec!(10)) + .withdraw_from_account( + account, + caviarnine_v1.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop( + caviarnine_v1.liquidity_receipt, + "bucket", + ) + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .deposit_batch(account) + .build(), + ) + .notarize(&private_key) + .build(); + let receipt = test_runner.execute_raw_transaction( + &NetworkDefinition::simulator(), + &transaction.to_raw().unwrap(), + ); + receipt.expect_commit_success(); + println!( + "Closing a position costs {} XRD in total with {} XRD in execution", + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); + } +} + +macro_rules! define_price_test { + ( + $($multiplier: expr),* $(,)? + ) => { + paste::paste! { + $( + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees(- $multiplier, env, pool_information.bitcoin.0, pool_information.bitcoin.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees(- $multiplier, env, pool_information.ethereum.0, pool_information.ethereum.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees(- $multiplier, env, pool_information.usdc.0, pool_information.usdc.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees(- $multiplier, env, pool_information.usdt.0, pool_information.usdt.1 ) + } + )* + $( + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees($multiplier, env, pool_information.bitcoin.0, pool_information.bitcoin.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees($multiplier, env, pool_information.ethereum.0, pool_information.ethereum.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees($multiplier, env, pool_information.usdc.0, pool_information.usdc.1 ) + } + #[test] + fn []( + ) { + let env = ScryptoUnitEnv::new(); + let pool_information = mainnet_state::pool_information(&env.resources); + let pool_information = ResourceInformation { + bitcoin: (pool_information.bitcoin, 8), + ethereum: (pool_information.ethereum, 18), + usdc: (pool_information.usdc, 6), + usdt: (pool_information.usdt, 6), + }; + test_effect_of_price_action_on_fees($multiplier, env, pool_information.usdt.0, pool_information.usdt.1 ) + } + )* + } + }; +} + +define_price_test! { + 100, + 90, + 80, + 70, + 60, + 50, + 40, + 30, + 20, + 10, +} + +fn test_effect_of_price_action_on_fees( + multiplier: i32, + env: ScryptoUnitEnv, + pool_information: mainnet_state::PoolInformation, + divisibility: u8, +) { + let ScryptoUnitEnv { + environment: mut test_runner, + protocol, + caviarnine_v1, + .. + } = env; + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + let mainnet_state::PoolInformation { + resource_x, + resource_y, + active_tick, + bin_span, + bins_below, + bins_above, + price, + } = pool_information; + + let user_resource_address = if resource_x == XRD { + resource_y + } else { + resource_x + }; + + let pool_address = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .caviarnine_v1_pool_new( + caviarnine_v1.package, + rule!(allow_all), + rule!(allow_all), + resource_x, + resource_y, + bin_span, + None, + ) + .build(), + vec![], + ) + .expect_commit_success() + .new_component_addresses() + .first() + .copied() + .unwrap(); + + // Providing liquidity identical to the mainnet pool + { + // Providing the liquidity to the pools. + let (divisibility_x, divisibility_y) = if resource_x == XRD { + (18, divisibility) + } else { + (divisibility, 18) + }; + + let mut amount_in_bins = { + let mut amount = indexmap! {}; + + for (tick, amount_x) in bins_above { + let (x, _) = amount.entry(tick).or_insert((dec!(0), dec!(0))); + *x = amount_x + *x; + } + + for (tick, amount_y) in bins_below { + let (_, y) = amount.entry(tick).or_insert((dec!(0), dec!(0))); + *y = amount_y + *y; + } + + amount + }; + + let amount_x = amount_in_bins + .values() + .map(|x| x.0) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + let amount_y = amount_in_bins + .values() + .map(|x| x.1) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + + let amount_x = amount_x + .checked_round(divisibility_x, RoundingMode::ToPositiveInfinity) + .unwrap(); + let amount_y = amount_y + .checked_round(divisibility_y, RoundingMode::ToPositiveInfinity) + .unwrap(); + + let active_amounts = + amount_in_bins.remove(&active_tick.unwrap()).unwrap(); + let positions = + vec![(active_tick.unwrap(), active_amounts.0, active_amounts.1)] + .into_iter() + .chain(amount_in_bins.into_iter().map(|(k, v)| { + ( + k, + v.0.checked_round(divisibility_x, RoundingMode::ToZero) + .unwrap(), + v.1.checked_round(divisibility_y, RoundingMode::ToZero) + .unwrap(), + ) + })) + .collect::>(); + + let price_in_simulated_pool = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_x, amount_x) + .mint_fungible(resource_y, amount_y) + .take_all_from_worktop(resource_x, "resource_x") + .take_all_from_worktop(resource_y, "resource_y") + .with_bucket("resource_x", |builder, bucket_x| { + builder.with_bucket( + "resource_y", + |builder, bucket_y| { + builder.caviarnine_v1_pool_add_liquidity( + pool_address, + bucket_x, + bucket_y, + positions, + ) + }, + ) + }) + .deposit_batch(account_address) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(7) + .unwrap(); + + // If this assertion passes, then the pool we've created should be in + // the same state as the mainnet one. + assert_eq!(price_in_simulated_pool, price.unwrap()); + } + + // We're allowed to contribute to 200 bins. So, we will contribute to all of + // them. This ensures that the maximum amount of price range is covered by + // our liquidity. + { + let positions = vec![(27000u32, dec!(100_000_000), dec!(100_000_000))] + .into_iter() + .chain((1..=99).flat_map(|i| { + vec![ + ( + 27000 - i * bin_span, + dec!(0), + dec!(100_000_000) - Decimal::from(i), + ), + ( + 27000 + i * bin_span, + dec!(100_000_000) + Decimal::from(i), + dec!(0), + ), + ] + })) + .collect::>(); + let x_amount_required = positions + .iter() + .map(|v| v.1) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + let y_amount_required = positions + .iter() + .map(|v| v.2) + .reduce(|acc, item| acc + item) + .unwrap_or_default(); + + test_runner + .execute_manifest_with_enabled_modules( + ManifestBuilder::new() + .mint_fungible(resource_x, x_amount_required) + .mint_fungible(resource_y, y_amount_required) + .take_all_from_worktop(resource_x, "resources_x") + .take_all_from_worktop(resource_y, "resources_y") + .with_name_lookup(|builder, namer| { + let resources_x = namer.bucket("resources_x"); + let resources_y = namer.bucket("resources_y"); + + builder.caviarnine_v1_pool_add_liquidity( + pool_address, + resources_x, + resources_y, + positions, + ) + }) + .deposit_batch(account_address) + .build(), + EnabledModules::for_notarized_transaction() + & !EnabledModules::AUTH + & !EnabledModules::COSTING, + ) + .expect_commit_success(); + } + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Updating the price in the Oracle component. + let price = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .caviarnine_v1_pool_get_price(pool_address) + .build(), + vec![], + ) + .expect_commit_success() + .output::>(1) + .unwrap(); + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / price), + ) + .build(), + ) + .expect_commit_success(); + + // Minting some of the resource and depositing them into the user's + // account. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_y, dec!(100_000)) + .deposit_batch(account_address) + .build(), + ) + .expect_commit_success(); + + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account( + account_address, + user_resource_address, + dec!(1000), + ) + .take_all_from_worktop(user_resource_address, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + pool_address, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Open - Multiplier = {}x, Bin Span = {}, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + bin_span, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); + + // Set the current time to be 6 months from now. + { + let current_time = + test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = + current_time + .add_seconds( + *LockupPeriod::from_months(6).unwrap().seconds() as i64 + ) + .unwrap(); + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { + epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000, + }, + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from( + maturity_instant.seconds_since_unix_epoch / 60, + ) + .unwrap(), + }, + ), + ) + .unwrap(); + } + + // Move the price according to the specified multiplier + let new_price = if multiplier.is_positive() { + let target_price = price * multiplier; + let input_resource = resource_y; + let amount_in_each_swap = dec!(100_000_000); + + let mut new_price = price; + while new_price < target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder + .caviarnine_v1_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(5) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + } else { + let target_price = price / multiplier * dec!(-1); + let input_resource = resource_x; + let amount_in_each_swap = dec!(1_000_000_000); + + let mut new_price = price; + while new_price > target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder + .caviarnine_v1_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .caviarnine_v1_pool_get_price(pool_address) + .build(), + ) + .expect_commit_success() + .output::>(5) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + }; + + // Submit the new price to the oracle + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, new_price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / new_price), + ) + .build(), + ) + .expect_commit_success(); + + // Close the position + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account( + account_address, + caviarnine_v1.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(caviarnine_v1.liquidity_receipt, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Close - Multiplier = {}x, Bin Span = {}, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + bin_span, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); +} + +mod mainnet_state { + use super::*; + use std::sync::*; + + static POOL_INFORMATION: Mutex< + OnceCell>, + > = Mutex::new(OnceCell::new()); + + /// The function that users call to get the pool information. This hides the + /// details of the mutex, once cell, and all of this information. + pub fn pool_information( + resources_addresses: &ResourceInformation, + ) -> ResourceInformation { + POOL_INFORMATION + .lock() + .unwrap() + .get_or_init(|| init_pool_information(resources_addresses)) + .clone() + } + + /// Calls the gateway getting the information of the pools of interest. + fn init_pool_information( + resources_addresses: &ResourceInformation, + ) -> ResourceInformation { + let gateway_configuration = GatewayConfig { + base_path: "https://mainnet.radixdlt.com/".to_owned(), + ..Default::default() + }; + + let network_definition = NetworkDefinition::mainnet(); + let decoder = AddressBech32Decoder::new(&network_definition); + + let pools = ResourceInformation { + bitcoin: "component_rdx1cr4nrgchhqe9etjmyl6cvefc9mjpyxlu72xt0l0hdfjw3tm4z8esln", + ethereum: "component_rdx1crennqxtn9axwfj4juccy9le0jw6m0fuyzdfu7vs5834f9nwtk5352", + usdc: "component_rdx1czg0xynqq0kgfh9n4lpjtw2dtjxczdregez8vtwht6x3h0v9jzxg70", + usdt: "component_rdx1czaa66y5nal99hsqwj3vkcvdv00q8g8dtrxjy82rfcj9g4pffxc4r4", + }; + let pools = pools.map(|item| { + ComponentAddress::try_from_bech32(&decoder, item).unwrap() + }); + + pools.zip(*resources_addresses).map( + |(component_address, resource_address)| { + // Doing a preview to get the information we need about the pool + // like the amounts, the bin span, etc... + let manifest = ManifestBuilder::new() + .caviarnine_v1_pool_get_token_x_address(*component_address) + .caviarnine_v1_pool_get_token_y_address(*component_address) + .caviarnine_v1_pool_get_active_tick(*component_address) + .caviarnine_v1_pool_get_bin_span(*component_address) + .caviarnine_v1_pool_get_bins_below( + *component_address, + None, + None, + None, + ) + .caviarnine_v1_pool_get_bins_above( + *component_address, + None, + None, + None, + ) + .caviarnine_v1_pool_get_price(*component_address) + .build(); + + let preview_response = transaction_preview( + &gateway_configuration, + TransactionPreviewRequest { + manifest: transaction::manifest::decompile( + &manifest.instructions, + &network_definition, + ) + .unwrap(), + blobs_hex: None, + start_epoch_inclusive: 200, + end_epoch_exclusive: 300, + notary_public_key: None, + notary_is_signatory: None, + tip_percentage: 0, + nonce: 12, + signer_public_keys: vec![], + flags: Box::new(TransactionPreviewRequestFlags { + assume_all_signature_proofs: true, + skip_epoch_check: true, + use_free_credit: true, + }), + }, + ) + .unwrap(); + + let receipt = scrypto_decode::( + &preview_response.encoded_receipt, + ) + .unwrap() + .into_latest(); + + let commit_result = receipt.expect_commit_success(); + + let resource_x = commit_result.output::(0); + let _ = commit_result.output::(1); + let active_tick = commit_result.output::>(2); + let bin_span = commit_result.output::(3); + let bins_below = commit_result.output::>(4); + let bins_above = commit_result.output::>(5); + let price = commit_result.output::>(6); + + // It is guaranteed that one of the resources is XRD and the + // other is the other resource. So, we change them here. + let (resource_x, resource_y) = if resource_x == XRD { + (XRD, *resource_address) + } else { + (*resource_address, XRD) + }; + + PoolInformation { + resource_x, + resource_y, + active_tick, + bin_span, + bins_below, + bins_above, + price, + } + }, + ) + } + + #[derive(Clone, ScryptoSbor, Debug)] + pub struct PoolInformation { + pub resource_x: ResourceAddress, + pub resource_y: ResourceAddress, + pub active_tick: Option, + pub bin_span: u32, + pub bins_below: Vec<(u32, Decimal)>, + pub bins_above: Vec<(u32, Decimal)>, + pub price: Option, + } +} diff --git a/tests/tests/ociswap_v1.rs b/tests/tests/ociswap_v1.rs new file mode 100644 index 00000000..5923493b --- /dev/null +++ b/tests/tests/ociswap_v1.rs @@ -0,0 +1,610 @@ +use tests::prelude::*; + +#[test] +pub fn can_open_a_simple_position_against_an_ociswap_pool( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +pub fn price_reported_by_pool_is_equal_to_price_reported_by_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(10_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(bitcoin_bucket, env)?; + + // Act + let pool_reported_price = ociswap_v1 + .pools + .bitcoin + .price_sqrt(env)? + .unwrap() + .checked_powi(2) + .unwrap() + .checked_truncate(RoundingMode::ToZero) + .unwrap(); + let adapter_reported_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)? + .price; + + // Assert + assert_eq!(pool_reported_price, adapter_reported_price); + + Ok(()) +} + +#[test] +fn can_open_a_liquidity_position_in_ociswap_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + ociswap_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + ociswap_v1.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + total_finalization_cost_in_xrd, + total_tipping_cost_in_xrd, + total_storage_cost_in_xrd, + total_royalty_cost_in_xrd, + .. + } = receipt.fee_summary; + + assert!( + dbg!( + total_execution_cost_in_xrd + + total_finalization_cost_in_xrd + + total_tipping_cost_in_xrd + + total_storage_cost_in_xrd + + total_royalty_cost_in_xrd + ) <= dec!(7) + ); + assert!(total_execution_cost_in_xrd <= dec!(4.5)) +} + +#[test] +fn can_close_a_liquidity_position_in_ociswap_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + ociswap_v1, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (public_key, private_key, account_address, _) = + protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + ociswap_v1.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![NonFungibleGlobalId::from_public_key(&public_key)], + ) + .expect_commit_success(); + + let current_time = test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(); + { + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000 } + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from(maturity_instant.seconds_since_unix_epoch / 60).unwrap(), + } + ), + ) + .unwrap(); + } + + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resources.bitcoin, XRD, dec!(1)), + ) + .build(), + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + ociswap_v1.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(ociswap_v1.liquidity_receipt, "receipt") + .with_bucket("receipt", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + total_finalization_cost_in_xrd, + total_tipping_cost_in_xrd, + total_storage_cost_in_xrd, + total_royalty_cost_in_xrd, + .. + } = receipt.fee_summary; + + assert!( + dbg!( + total_execution_cost_in_xrd + + total_finalization_cost_in_xrd + + total_tipping_cost_in_xrd + + total_storage_cost_in_xrd + + total_royalty_cost_in_xrd + ) <= dec!(7) + ); + assert!(total_execution_cost_in_xrd <= dec!(4.5)) +} + +#[test] +fn contributions_directly_to_ociswap_dont_fail_due_to_bucket_order( +) -> Result<(), RuntimeError> { + // Arrange + let mut results = Vec::::new(); + for order in [true, false] { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let xrd_bucket = ResourceManager(XRD).mint_fungible(dec!(1), env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(1), env)?; + let buckets = if order { + (xrd_bucket, bitcoin_bucket) + } else { + (bitcoin_bucket, xrd_bucket) + }; + + // Act + let result = ociswap_v1 + .pools + .bitcoin + .add_liquidity(buckets.0, buckets.1, env); + results.push(result.is_ok()); + } + + // Assert + assert_eq!(results.len(), 2); + assert_eq!(results.iter().filter(|item| **item).count(), 2); + + Ok(()) +} + +#[test] +fn contributions_to_ociswap_through_adapter_dont_fail_due_to_bucket_ordering( +) -> Result<(), RuntimeError> { + // Arrange + let mut results = Vec::::new(); + for order in [true, false] { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let xrd_bucket = ResourceManager(XRD).mint_fungible(dec!(1), env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(1), env)?; + let buckets = if order { + (xrd_bucket, bitcoin_bucket) + } else { + (bitcoin_bucket, xrd_bucket) + }; + + // Act + let result = ociswap_v1.adapter.open_liquidity_position( + ociswap_v1.pools.bitcoin.try_into().unwrap(), + buckets, + env, + ); + results.push(result.is_ok()); + } + + // Assert + assert_eq!(results.len(), 2); + assert_eq!(results.iter().filter(|item| **item).count(), 2); + + Ok(()) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_stays_the_same_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_down_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_up_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_stays_the_same_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_down_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_up_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_stays_the_same_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_down_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_up_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +fn non_strict_testing_of_fees( + protocol_coefficient: Movement, + price_of_user_asset: Movement, + result: CloseLiquidityResult, +) -> Result<(), RuntimeError> { + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_amount_in = dec!(100); + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(bitcoin_amount_in, env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + match price_of_user_asset { + // User asset price goes down - i.e., we inject it into the pool. + Movement::Down => { + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(bitcoin_bucket, env)?; + } + // The user asset price stays the same. We do not do anything. + Movement::Same => {} + // User asset price goes up - i.e., we reduce it in the pool. + Movement::Up => { + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(100_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(xrd_bucket, env)?; + } + } + + let pool_unit = { + let pool = ociswap_v1.pools.bitcoin.liquidity_pool(env)?; + let output = env + .call_module_method_typed::<_, _, MetadataGetOutput>( + pool, + AttachedModuleId::Metadata, + METADATA_GET_IDENT, + &MetadataGetInput { + key: "pool_unit".to_owned(), + }, + )? + .unwrap(); + + let GenericMetadataValue::GlobalAddress(pool_unit) = output else { + panic!() + }; + ResourceAddress::try_from(pool_unit).unwrap() + }; + + match protocol_coefficient { + // Somebody claims some portion of the pool + Movement::Down => { + // Claim 10% of the pool. + let total_supply = + ResourceManager(pool_unit).total_supply(env)?.unwrap(); + let ten_percent_of_total_supply = total_supply * dec!(0.1); + let pool_units = BucketFactory::create_fungible_bucket( + pool_unit, + ten_percent_of_total_supply, + CreationStrategy::Mock, + env, + )?; + let _ = + ociswap_v1.pools.bitcoin.remove_liquidity(pool_units, env)?; + } + // Nothing + Movement::Same => {} + // Somebody contributed to the pool some amount + Movement::Up => { + let xrd = ResourceManager(XRD).mint_fungible(dec!(10_000), env)?; + let bitcoin = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(10_000), env)?; + let _ = + ociswap_v1.pools.bitcoin.add_liquidity(xrd, bitcoin, env)?; + } + } + + env.set_current_time(Instant::new( + *LockupPeriod::from_months(12).unwrap().seconds() as i64, + )); + let pool_reported_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)?; + protocol.oracle.set_price( + pool_reported_price.base, + pool_reported_price.quote, + pool_reported_price.price, + env, + )?; + + let buckets = IndexedBuckets::from_buckets( + protocol.ignition.close_liquidity_position(receipt, env)?, + env, + )?; + + let bitcoin_amount_out = buckets + .get(&resources.bitcoin) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToPositiveInfinity) + .unwrap(); + let xrd_amount_out = buckets + .get(&XRD) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToZero) + .unwrap(); + + match result { + CloseLiquidityResult::GetFees => { + // Bitcoin we get back must be strictly greater than what we put in. + assert!(bitcoin_amount_out > bitcoin_amount_in); + // When we get back fees we MUST not get back any XRD + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::SameAmount => { + // Bitcoin we get back must be strictly equal to what we put in. + assert_eq!(bitcoin_amount_out, bitcoin_amount_in); + // If we get back the same amount then we must NOT get back any XRD. + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::Reimbursement => { + // Bitcoin we get back must be less than what we put in. + assert!(bitcoin_amount_out < bitcoin_amount_in); + // We must get back SOME xrd. + assert_ne!(xrd_amount_out, Decimal::ZERO); + } + } + + Ok(()) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Movement { + Down, + Same, + Up, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum CloseLiquidityResult { + GetFees, + SameAmount, + Reimbursement, +} diff --git a/tests/tests/ociswap_v2.rs b/tests/tests/ociswap_v2.rs new file mode 100644 index 00000000..5c515809 --- /dev/null +++ b/tests/tests/ociswap_v2.rs @@ -0,0 +1,929 @@ +#![allow(clippy::arithmetic_side_effects)] + +use tests::prelude::*; + +#[test] +pub fn can_open_a_simple_position_against_an_ociswap_pool( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v2, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v2.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +pub fn price_reported_by_pool_is_equal_to_price_reported_by_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut ociswap_v2, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(10_000_000), env)?; + let _ = ociswap_v2.pools.bitcoin.swap(bitcoin_bucket, env)?; + + // Act + let pool_reported_price = ociswap_v2 + .pools + .bitcoin + .price_sqrt(env)? + .checked_powi(2) + .unwrap() + .checked_truncate(RoundingMode::ToZero) + .unwrap(); + let adapter_reported_price = ociswap_v2 + .adapter + .price(ociswap_v2.pools.bitcoin.try_into().unwrap(), env)? + .price; + + // Assert + assert_eq!(pool_reported_price, adapter_reported_price); + + Ok(()) +} + +#[test] +fn can_open_a_liquidity_position_in_ociswap_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + ociswap_v2, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + ociswap_v2.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + total_finalization_cost_in_xrd, + total_tipping_cost_in_xrd, + total_storage_cost_in_xrd, + total_royalty_cost_in_xrd, + .. + } = receipt.fee_summary; + + assert!( + dbg!( + total_execution_cost_in_xrd + + total_finalization_cost_in_xrd + + total_tipping_cost_in_xrd + + total_storage_cost_in_xrd + + total_royalty_cost_in_xrd + ) <= dec!(7) + ); + assert!(total_execution_cost_in_xrd <= dec!(4.5)) +} + +#[test] +fn can_close_a_liquidity_position_in_ociswap_that_fits_into_fee_limits() { + // Arrange + let ScryptoUnitEnv { + environment: mut test_runner, + resources, + protocol, + ociswap_v2, + .. + } = ScryptoUnitEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.03), + ..Default::default() + }); + let (public_key, private_key, account_address, _) = + protocol.protocol_owner_badge; + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resources.bitcoin, dec!(100_000_000_000_000)) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![], + ) + .expect_commit_success(); + + test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + resources.bitcoin, + dec!(100_000), + ) + .take_all_from_worktop(resources.bitcoin, "bitcoin") + .with_bucket("bitcoin", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + ociswap_v2.pools.bitcoin, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + vec![NonFungibleGlobalId::from_public_key(&public_key)], + ) + .expect_commit_success(); + + let current_time = test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(); + { + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000 } + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from(maturity_instant.seconds_since_unix_epoch / 60).unwrap(), + } + ), + ) + .unwrap(); + } + + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resources.bitcoin, XRD, dec!(1)), + ) + .build(), + ) + .expect_commit_success(); + + // Act + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee_from_faucet() + .withdraw_from_account( + account_address, + ociswap_v2.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(ociswap_v2.liquidity_receipt, "receipt") + .with_bucket("receipt", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .try_deposit_entire_worktop_or_abort(account_address, None) + .build(), + &private_key, + ); + + // Assert + receipt.expect_commit_success(); + let TransactionFeeSummary { + total_execution_cost_in_xrd, + total_finalization_cost_in_xrd, + total_tipping_cost_in_xrd, + total_storage_cost_in_xrd, + total_royalty_cost_in_xrd, + .. + } = receipt.fee_summary; + + assert!( + dbg!( + total_execution_cost_in_xrd + + total_finalization_cost_in_xrd + + total_tipping_cost_in_xrd + + total_storage_cost_in_xrd + + total_royalty_cost_in_xrd + ) <= dec!(7) + ); + assert!(total_execution_cost_in_xrd <= dec!(4.5)) +} + +#[test] +fn contributions_to_ociswap_through_adapter_dont_fail_due_to_bucket_ordering( +) -> Result<(), RuntimeError> { + // Arrange + let mut results = Vec::::new(); + for order in [true, false] { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut ociswap_v2, + .. + } = ScryptoTestEnv::new()?; + + let xrd_bucket = ResourceManager(XRD).mint_fungible(dec!(1), env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(1), env)?; + let buckets = if order { + (xrd_bucket, bitcoin_bucket) + } else { + (bitcoin_bucket, xrd_bucket) + }; + + // Act + let result = ociswap_v2.adapter.open_liquidity_position( + ociswap_v2.pools.bitcoin.try_into().unwrap(), + buckets, + env, + ); + results.push(result.is_ok()); + } + + // Assert + assert_eq!(results.len(), 2); + assert_eq!(results.iter().filter(|item| **item).count(), 2); + + Ok(()) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_stays_the_same_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_down_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_stays_the_same_and_k_goes_up_the_output_is_the_same_amount_as_the_input( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Same, + CloseLiquidityResult::SameAmount, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_stays_the_same_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_down_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_down_and_k_goes_up_the_user_gets_fees( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Down, + CloseLiquidityResult::GetFees, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_stays_the_same_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Same, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_down_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Down, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +#[test] +fn when_price_of_user_asset_goes_up_and_k_goes_up_the_user_gets_reimbursed( +) -> Result<(), RuntimeError> { + non_strict_testing_of_fees( + Movement::Up, + Movement::Up, + CloseLiquidityResult::Reimbursement, + ) +} + +fn non_strict_testing_of_fees( + protocol_coefficient: Movement, + price_of_user_asset: Movement, + result: CloseLiquidityResult, +) -> Result<(), RuntimeError> { + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v2, + resources, + .. + } = ScryptoTestEnv::new()?; + + let pool_reported_price = ociswap_v2 + .adapter + .price(ociswap_v2.pools.bitcoin.try_into().unwrap(), env)?; + protocol.oracle.set_price( + pool_reported_price.base, + pool_reported_price.quote, + pool_reported_price.price, + env, + )?; + + let bitcoin_amount_in = dec!(100); + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(bitcoin_amount_in, env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v2.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let pool_units = ociswap_v2 + .adapter + .open_liquidity_position( + ociswap_v2.pools.bitcoin.try_into().unwrap(), + ( + ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000), env)?, + ResourceManager(XRD).mint_fungible(dec!(100_000), env)?, + ), + env, + )? + .pool_units; + + match price_of_user_asset { + // User asset price goes down - i.e., we inject it into the pool. + Movement::Down => { + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(450_000_000), env)?; + let _ = ociswap_v2.pools.bitcoin.swap(bitcoin_bucket, env)?; + } + // The user asset price stays the same. We do not do anything. + Movement::Same => {} + // User asset price goes up - i.e., we reduce it in the pool. + Movement::Up => { + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(450_000_000), env)?; + let _ = ociswap_v2.pools.bitcoin.swap(xrd_bucket, env)?; + } + } + + match protocol_coefficient { + // Somebody claimed some portion of the pool + Movement::Down => { + let _ = ociswap_v2 + .pools + .bitcoin + .remove_liquidity(NonFungibleBucket(pool_units), env)?; + } + // Nothing + Movement::Same => {} + // Somebody contributed to the pool some amount + Movement::Up => { + let _ = ociswap_v2 + .adapter + .open_liquidity_position( + ociswap_v2.pools.bitcoin.try_into().unwrap(), + ( + ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000), env)?, + ResourceManager(XRD) + .mint_fungible(dec!(100_000), env)?, + ), + env, + )? + .pool_units; + } + } + + env.set_current_time(Instant::new( + *LockupPeriod::from_months(12).unwrap().seconds() as i64, + )); + let pool_reported_price = ociswap_v2 + .adapter + .price(ociswap_v2.pools.bitcoin.try_into().unwrap(), env)?; + protocol.oracle.set_price( + pool_reported_price.base, + pool_reported_price.quote, + pool_reported_price.price, + env, + )?; + + let buckets = IndexedBuckets::from_buckets( + protocol.ignition.close_liquidity_position(receipt, env)?, + env, + )?; + + let bitcoin_amount_out = buckets + .get(&resources.bitcoin) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToPositiveInfinity) + .unwrap(); + let xrd_amount_out = buckets + .get(&XRD) + .map(|bucket| bucket.amount(env).unwrap()) + .unwrap_or_default() + .checked_round(5, RoundingMode::ToZero) + .unwrap(); + + match result { + CloseLiquidityResult::GetFees => { + // Bitcoin we get back must be strictly greater than what we put in. + assert!(bitcoin_amount_out > bitcoin_amount_in); + // When we get back fees we MUST not get back any XRD + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::SameAmount => { + // Bitcoin we get back must be strictly equal to what we put in. + assert_eq!(bitcoin_amount_out, bitcoin_amount_in); + // If we get back the same amount then we must NOT get back any XRD. + assert_eq!(xrd_amount_out, Decimal::ZERO) + } + CloseLiquidityResult::Reimbursement => { + // Bitcoin we get back must be less than what we put in. + assert!(bitcoin_amount_out < bitcoin_amount_in); + // We must get back SOME xrd. + assert_ne!(xrd_amount_out, Decimal::ZERO); + } + } + + Ok(()) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Movement { + Down, + Same, + Up, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum CloseLiquidityResult { + GetFees, + SameAmount, + Reimbursement, +} + +macro_rules! define_price_test { + ( + $($multiplier: expr),* $(,)? + ) => { + paste::paste! { + $( + #[test] + fn []( + ) { + test_effect_of_price_action_on_fees(- $multiplier ) + } + + #[test] + fn []( + ) { + test_effect_of_price_action_on_fees($multiplier ) + } + )* + } + }; +} + +define_price_test! { + 100, + 90, + 80, + 70, + 60, + 50, + 40, + 30, + 20, + 10, +} + +fn test_effect_of_price_action_on_fees(multiplier: i32) { + let ScryptoUnitEnv { + environment: mut test_runner, + protocol, + ociswap_v2, + resources, + .. + } = ScryptoUnitEnv::new(); + let (_, private_key, account_address, _) = protocol.protocol_owner_badge; + + // We will be using the bitcoin pool for this test and the bitcoin resource. + let pool_address = ociswap_v2.pools.bitcoin; + let pool_resource = resources.bitcoin; + + // Getting the address of the x and y asset to differentiate them from one + // another + let (resource_x, resource_y) = { + let commit_result = test_runner + .execute_manifest( + ManifestBuilder::new() + .lock_fee_from_faucet() + .ociswap_v2_pool_x_address(pool_address) + .ociswap_v2_pool_y_address(pool_address) + .build(), + vec![], + ) + .expect_commit_success() + .clone(); + + ( + commit_result.output::(1), + commit_result.output::(2), + ) + }; + + // Adding liquidity between the smallest and largest ticks possible. + let price = test_runner + .execute_manifest_with_enabled_modules( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(resource_x, dec!(1_000_000_000_000)) + .mint_fungible(resource_y, dec!(1_000_000_000_000)) + .take_all_from_worktop(resource_x, "resource_x") + .take_all_from_worktop(resource_y, "resource_y") + .with_name_lookup(|builder, namer| { + let resource_x = namer.bucket("resource_x"); + let resource_y = namer.bucket("resource_y"); + + builder.ociswap_v2_pool_add_liquidity( + pool_address, + -887272, + 887272, + resource_x, + resource_y, + ) + }) + .ociswap_v2_pool_price_sqrt(pool_address) + .deposit_batch(account_address) + .build(), + EnabledModules::for_notarized_transaction() & !EnabledModules::AUTH, + ) + .expect_commit_success() + .output::(6) + .checked_powi(2) + .and_then(|value| Decimal::try_from(value).ok()) + .unwrap(); + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Adding this pool to Ignition. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.ignition, + "add_allowed_pool", + (pool_address,), + ) + .build(), + ) + .expect_commit_success(); + + // Updating the price in the Oracle component. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / price), + ) + .build(), + ) + .expect_commit_success(); + + // Minting some of the resource and depositing them into the user's + // account. + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(pool_resource, dec!(100_000)) + .deposit_batch(account_address) + .build(), + ) + .expect_commit_success(); + + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account(account_address, pool_resource, dec!(1000)) + .take_all_from_worktop(pool_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "open_liquidity_position", + ( + bucket, + pool_address, + LockupPeriod::from_months(6).unwrap(), + ), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Open - Multiplier = {}x, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); + + // Set the current time to be 6 months from now. + { + let current_time = + test_runner.get_current_time(TimePrecisionV2::Minute); + let maturity_instant = + current_time + .add_seconds( + *LockupPeriod::from_months(6).unwrap().seconds() as i64 + ) + .unwrap(); + let db = test_runner.substate_db_mut(); + let mut writer = SystemDatabaseWriter::new(db); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMilliTimestamp.field_index(), + ConsensusManagerProposerMilliTimestampFieldPayload::from_content_source( + ProposerMilliTimestampSubstate { + epoch_milli: maturity_instant.seconds_since_unix_epoch * 1000, + }, + ), + ) + .unwrap(); + + writer + .write_typed_object_field( + CONSENSUS_MANAGER.as_node_id(), + ModuleId::Main, + ConsensusManagerField::ProposerMinuteTimestamp.field_index(), + ConsensusManagerProposerMinuteTimestampFieldPayload::from_content_source( + ProposerMinuteTimestampSubstate { + epoch_minute: i32::try_from( + maturity_instant.seconds_since_unix_epoch / 60, + ) + .unwrap(), + }, + ), + ) + .unwrap(); + } + + // Move the price according to the specified multiplier + let new_price = if multiplier.is_positive() { + let target_price = price * multiplier; + let input_resource = resource_y; + let amount_in_each_swap = dec!(100_000_000_000); + + let mut new_price = price; + while new_price < target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.ociswap_v2_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .ociswap_v2_pool_price_sqrt(pool_address) + .build(), + ) + .expect_commit_success() + .output::(5) + .checked_powi(2) + .and_then(|value| Decimal::try_from(value).ok()) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + } else { + let target_price = price / multiplier * dec!(-1); + let input_resource = resource_x; + let amount_in_each_swap = dec!(100_000_000_000); + + let mut new_price = price; + while new_price > target_price { + let reported_price = test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .mint_fungible(input_resource, amount_in_each_swap) + .take_all_from_worktop(input_resource, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.ociswap_v2_pool_swap(pool_address, bucket) + }) + .deposit_batch(account_address) + .ociswap_v2_pool_price_sqrt(pool_address) + .build(), + ) + .expect_commit_success() + .output::(5) + .checked_powi(2) + .and_then(|value| Decimal::try_from(value).ok()) + .unwrap(); + + if reported_price == new_price { + break; + } else { + new_price = reported_price + } + } + + new_price + }; + + // Submit the new price to the oracle + test_runner + .execute_manifest_without_auth( + ManifestBuilder::new() + .lock_fee_from_faucet() + .call_method( + protocol.oracle, + "set_price", + (resource_x, resource_y, new_price), + ) + .call_method( + protocol.oracle, + "set_price", + (resource_y, resource_x, 1 / new_price), + ) + .build(), + ) + .expect_commit_success(); + + // Close the position + let receipt = test_runner.construct_and_execute_notarized_transaction( + ManifestBuilder::new() + .lock_fee(account_address, dec!(10)) + .withdraw_from_account( + account_address, + ociswap_v2.liquidity_receipt, + dec!(1), + ) + .take_all_from_worktop(ociswap_v2.liquidity_receipt, "bucket") + .with_bucket("bucket", |builder, bucket| { + builder.call_method( + protocol.ignition, + "close_liquidity_position", + (bucket,), + ) + }) + .deposit_batch(account_address) + .build(), + &private_key, + ); + receipt.expect_commit_success(); + println!( + "Close - Multiplier = {}x, Cost = {} XRD, Execution Cost = {} XRD", + multiplier, + receipt.fee_summary.total_cost(), + receipt.fee_summary.total_execution_cost_in_xrd + ); +} diff --git a/tests/tests/protocol.rs b/tests/tests/protocol.rs new file mode 100644 index 00000000..c1fa8591 --- /dev/null +++ b/tests/tests/protocol.rs @@ -0,0 +1,1863 @@ +use tests::prelude::*; +use Volatility::*; + +#[test] +fn simple_testing_environment_can_be_created() { + ScryptoTestEnv::new().expect("Must succeed!"); +} + +#[test] +fn cant_open_a_liquidity_position_when_opening_is_disabled( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + protocol.ignition.set_is_open_position_enabled(false, env)?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_opening_liquidity_positions_is_closed_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_on_a_pool_that_has_no_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut protocol, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + FAUCET, + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_liquidity_position_against_a_pool_outside_of_the_allow_list( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let new_pool = OciswapV1PoolInterfaceScryptoTestStub::instantiate( + resources.bitcoin, + XRD, + dec!(0), + FAUCET, + ociswap_v1.package, + env, + )?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + new_pool.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_pool_is_not_in_allow_list_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_in_a_pool_after_it_has_been_removed_from_allowed_list( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + resources, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + protocol.ignition.remove_allowed_pool( + ociswap_v1.pools.bitcoin.try_into().unwrap(), + env, + )?; + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_pool_is_not_in_allow_list_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_with_some_random_resource( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let random_resource = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(random_resource), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_user_resources_volatility_unknown_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_by_providing_the_protocol_resource( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let protocol_resource = + ResourceManager(XRD).mint_fungible(dec!(100), env)?; + protocol.ignition.insert_user_resource_volatility( + XRD, + Volatility::NonVolatile, + env, + )?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(protocol_resource), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_user_must_not_provide_protocol_asset_error(&rtn); + + Ok(()) +} + +#[test] +pub fn can_open_a_liquidity_position_before_the_price_is_stale( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: 5 * 60, + ..Default::default() + })?; + + // Act + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +pub fn can_open_a_liquidity_position_right_before_price_goes_stale( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: 5 * 60, + ..Default::default() + })?; + + // Act + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_minutes(5).unwrap()); + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +pub fn cant_open_a_liquidity_position_right_after_price_goes_stale( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: 5 * 60, + ..Default::default() + })?; + + // Act + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_minutes(6).unwrap()); + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_oracle_reported_price_is_stale_error(&rtn); + + Ok(()) +} + +#[test] +pub fn can_open_liquidity_position_when_oracle_price_is_lower_than_pool_but_within_allowed_relative_difference( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: dec!(0.01), + ..Default::default() + })?; + + // Act + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_minutes(6).unwrap()); + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert_is_ignition_oracle_reported_price_is_stale_error(&rtn); + + Ok(()) +} + +#[test] +#[allow(unused_must_use)] +fn oracle_price_cutoffs_for_opening_liquidity_positions_are_implemented_correctly( +) { + const SMALL_DECIMAL: Decimal = dec!(0.000000000000000010); + + test_open_position_oracle_price_cutoffs(dec!(1) / dec!(1.01), dec!(0.01)) + .expect("Should succeed!"); + test_open_position_oracle_price_cutoffs(dec!(1) / dec!(0.99), dec!(0.01)) + .expect("Should succeed!"); + test_open_position_oracle_price_cutoffs( + dec!(1) / dec!(0.99) - SMALL_DECIMAL, + dec!(0.01), + ) + .expect("Should succeed!"); + test_open_position_oracle_price_cutoffs( + dec!(1) / dec!(1.01) + SMALL_DECIMAL, + dec!(0.01), + ) + .expect("Should succeed!"); + + assert_is_ignition_relative_price_difference_larger_than_allowed_error( + &test_open_position_oracle_price_cutoffs( + dec!(1) / dec!(0.99) + SMALL_DECIMAL, + dec!(0.01), + ), + ); + assert_is_ignition_relative_price_difference_larger_than_allowed_error( + &test_open_position_oracle_price_cutoffs( + dec!(1) / dec!(1.01) - SMALL_DECIMAL, + dec!(0.01), + ), + ); +} + +fn test_open_position_oracle_price_cutoffs( + oracle_price: Decimal, + allowed_price_difference: Decimal, +) -> Result<(NonFungibleBucket, FungibleBucket, Vec), RuntimeError> { + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: allowed_price_difference, + ..Default::default() + })?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + protocol + .oracle + .set_price(resources.bitcoin, XRD, oracle_price, env)?; + + // Act + protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ) +} + +#[test] +#[allow(unused_must_use)] +fn oracle_price_cutoffs_for_closing_liquidity_positions_are_implemented_correctly( +) { + const SMALL_DECIMAL: Decimal = dec!(0.000000000000000010); + + test_close_position_oracle_price_cutoffs(dec!(1) / dec!(1.01), dec!(0.01)) + .expect("Should succeed!"); + test_close_position_oracle_price_cutoffs(dec!(1) / dec!(0.99), dec!(0.01)) + .expect("Should succeed!"); + test_close_position_oracle_price_cutoffs( + dec!(1) / dec!(0.99) - SMALL_DECIMAL, + dec!(0.01), + ) + .expect("Should succeed!"); + test_close_position_oracle_price_cutoffs( + dec!(1) / dec!(1.01) + SMALL_DECIMAL, + dec!(0.01), + ) + .expect("Should succeed!"); + + assert_is_ignition_relative_price_difference_larger_than_allowed_error( + &test_close_position_oracle_price_cutoffs( + dec!(1) / dec!(0.99) + SMALL_DECIMAL, + dec!(0.01), + ), + ); + assert_is_ignition_relative_price_difference_larger_than_allowed_error( + &test_close_position_oracle_price_cutoffs( + dec!(1) / dec!(1.01) - SMALL_DECIMAL, + dec!(0.01), + ), + ); +} + +fn test_close_position_oracle_price_cutoffs( + oracle_price: Decimal, + allowed_price_difference: Decimal, +) -> Result, RuntimeError> { + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_relative_price_difference: allowed_price_difference, + ..Default::default() + })?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_days(12 * 30).unwrap()); + + protocol + .oracle + .set_price(resources.bitcoin, XRD, oracle_price, env)?; + + protocol.ignition.close_liquidity_position(receipt, env) +} + +#[test] +fn cant_open_a_liquidity_position_with_an_invalid_lockup_period( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + // Act + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_seconds(1), + env, + ); + + // Assert + assert_is_ignition_lockup_period_has_no_associated_rewards_rate_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_set_the_adapter_of_a_blueprint_that_is_not_registered( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + .. + } = ScryptoTestEnv::new()?; + + // Act + let rtn = protocol.ignition.set_pool_adapter( + BlueprintId { + package_address: FAUCET_PACKAGE, + blueprint_name: "Faucet".into(), + }, + FAUCET, + env, + ); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_add_allowed_pool_of_a_blueprint_that_is_not_registered( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + .. + } = ScryptoTestEnv::new()?; + + // Act + let rtn = protocol.ignition.add_allowed_pool(FAUCET, env); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_add_an_allowed_pool_where_neither_of_the_resources_is_the_protocol_resource_ociswap_v1( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let fungible1 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let fungible2 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let pool = OciswapV1PoolInterfaceScryptoTestStub::instantiate( + fungible1.resource_address(env)?, + fungible2.resource_address(env)?, + dec!(0), + FAUCET, + ociswap_v1.package, + env, + )?; + + // Act + let rtn = protocol + .ignition + .add_allowed_pool(pool.try_into().unwrap(), env); + + // Assert + assert_is_ignition_neither_pool_resource_is_protocol_resource_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_add_an_allowed_pool_where_neither_of_the_resources_is_the_protocol_resource_ociswap_v2( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v2, + .. + } = ScryptoTestEnv::new()?; + + let fungible1 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let fungible2 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let (pool, ..) = OciswapV2PoolInterfaceScryptoTestStub::instantiate( + fungible2.resource_address(env)?, + fungible1.resource_address(env)?, + pdec!(1), + dec!(0.03), + dec!(0.03), + FAUCET, + vec![], + FAUCET, + ociswap_v2.package, + env, + )?; + + // Act + let rtn = protocol + .ignition + .add_allowed_pool(pool.try_into().unwrap(), env); + + // Assert + assert_is_ignition_neither_pool_resource_is_protocol_resource_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_add_an_allowed_pool_where_neither_of_the_resources_is_the_protocol_resource_caviarnine_v1( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + caviarnine_v1, + .. + } = ScryptoTestEnv::new()?; + + let fungible1 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let fungible2 = ResourceBuilder::new_fungible(OwnerRole::None) + .mint_initial_supply(100, env)?; + let pool = CaviarnineV1PoolInterfaceScryptoTestStub::new( + rule!(allow_all), + rule!(allow_all), + fungible1.resource_address(env)?, + fungible2.resource_address(env)?, + 50, + None, + caviarnine_v1.package, + env, + )?; + + // Act + let rtn = protocol + .ignition + .add_allowed_pool(pool.try_into().unwrap(), env); + + // Assert + assert_is_ignition_neither_pool_resource_is_protocol_resource_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_remove_an_allowed_pool_for_a_blueprint_with_no_registered_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + .. + } = ScryptoTestEnv::new()?; + + // Act + let rtn = protocol.ignition.remove_allowed_pool(FAUCET, env); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_set_liquidity_receipt_of_a_pool_with_no_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + .. + } = ScryptoTestEnv::new()?; + + // Act + let rtn = protocol.ignition.set_liquidity_receipt( + BlueprintId { + package_address: FAUCET_PACKAGE, + blueprint_name: "Faucet".into(), + }, + ACCOUNT_OWNER_BADGE.into(), + env, + ); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_with_volatile_user_resource_when_volatile_vault_is_empty( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let _ = env.with_component_state::( + protocol.ignition, + |state, env| state.protocol_resource_reserves.volatile.0.take_all(env), + )?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert!(rtn.is_err()); + + Ok(()) +} + +#[test] +fn cant_open_a_liquidity_position_with_non_volatile_user_resource_when_non_volatile_vault_is_empty( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let _ = env.with_component_state::( + protocol.ignition, + |state, env| { + state + .protocol_resource_reserves + .non_volatile + .0 + .take_all(env) + }, + )?; + + let usdc_bucket = + ResourceManager(resources.usdc).mint_fungible(dec!(100), env)?; + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(usdc_bucket), + ociswap_v1.pools.usdc.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + assert!(rtn.is_err()); + + Ok(()) +} + +#[test] +fn can_open_a_liquidity_position_with_no_protocol_resources_in_user_resources_vaults( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + assert_eq!( + protocol + .ignition + .get_user_resource_reserves_amount(XRD, env)?, + Decimal::ZERO + ); + + // Act + let rtn = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + ); + + // Assert + let _ = rtn.expect("Should succeed!"); + + Ok(()) +} + +#[test] +fn opening_a_liquidity_position_of_a_volatile_resource_consumes_protocol_assets_from_the_volatile_vault( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + + let initial_volatile_vault_amount = env + .with_component_state::( + protocol.ignition, + |state, env| { + state.protocol_resource_reserves.volatile.0.amount(env) + }, + )??; + let initial_non_volatile_vault_amount = env + .with_component_state::( + protocol.ignition, + |state, env| { + state.protocol_resource_reserves.non_volatile.0.amount(env) + }, + )??; + + // Act + let _ = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + // Assert + let final_volatile_vault_amount = env + .with_component_state::( + protocol.ignition, + |state, env| { + state.protocol_resource_reserves.volatile.0.amount(env) + }, + )??; + let final_non_volatile_vault_amount = env + .with_component_state::( + protocol.ignition, + |state, env| { + state.protocol_resource_reserves.non_volatile.0.amount(env) + }, + )??; + + assert_ne!(initial_volatile_vault_amount, final_volatile_vault_amount); + assert_eq!( + initial_non_volatile_vault_amount, + final_non_volatile_vault_amount + ); + + Ok(()) +} + +#[test] +fn liquidity_receipt_data_matches_component_state() -> Result<(), RuntimeError> +{ + // Arrange + const ORACLE_PRICE: Decimal = dec!(0.85); + const POOL_PRICE: Decimal = dec!(1); + const BITCOIN_CONTRIBUTION: Decimal = dec!(100); + + const LOCKUP_REWARD: Decimal = dec!(0.2); + let lockup_period: LockupPeriod = LockupPeriod::from_months(6).unwrap(); + + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + protocol + .oracle + .set_price(resources.bitcoin, XRD, ORACLE_PRICE, env)?; + protocol + .ignition + .set_maximum_allowed_price_difference_percentage(Decimal::MAX, env)?; + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(BITCOIN_CONTRIBUTION, env)?; + + let initial_bitcoin_reserves = protocol + .ignition + .get_user_resource_reserves_amount(resources.bitcoin, env)?; + let initial_volatile_xrd_reserves = protocol + .ignition + .get_protocol_resource_reserves_amount(Volatile, env); + let initial_non_volatile_xrd_reserves = protocol + .ignition + .get_protocol_resource_reserves_amount(NonVolatile, env); + + // Act + let (receipt, upfront_reward, bitcoin_change) = + protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + lockup_period, + env, + )?; + + // Assert + let final_bitcoin_reserves = protocol + .ignition + .get_user_resource_reserves_amount(resources.bitcoin, env)?; + let final_volatile_xrd_reserves = protocol + .ignition + .get_protocol_resource_reserves_amount(Volatile, env); + let final_non_volatile_xrd_reserves = protocol + .ignition + .get_protocol_resource_reserves_amount(NonVolatile, env); + + assert_eq!(initial_bitcoin_reserves, final_bitcoin_reserves); + assert_ne!(initial_volatile_xrd_reserves, final_volatile_xrd_reserves); + assert_eq!( + initial_non_volatile_xrd_reserves, + final_non_volatile_xrd_reserves + ); + assert!(bitcoin_change.is_empty() || bitcoin_change.len() == 1); + let bitcoin_change = if bitcoin_change.len() == 1 { + let bucket = bitcoin_change.first().unwrap(); + let resource_address = bucket.resource_address(env)?; + assert_eq!(resource_address, resources.bitcoin); + bucket.amount(env)? + } else { + Decimal::ZERO + }; + + let liquidity_receipt_data = ResourceManager(ociswap_v1.liquidity_receipt) + .get_non_fungible_data::<_, _, LiquidityReceipt>( + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + env, + )?; + + assert_eq!( + liquidity_receipt_data.lockup_period, + lockup_period.to_string() + ); + assert_eq!( + liquidity_receipt_data.pool_address, + ComponentAddress::try_from(ociswap_v1.pools.bitcoin).unwrap() + ); + assert_eq!( + liquidity_receipt_data.user_resource_address, + resources.bitcoin + ); + assert_eq!( + liquidity_receipt_data.user_contribution_amount, + BITCOIN_CONTRIBUTION - bitcoin_change + ); + assert_eq!( + liquidity_receipt_data.user_resource_volatility_classification, + Volatile + ); + assert_eq!( + liquidity_receipt_data.protocol_contribution_amount, + (BITCOIN_CONTRIBUTION - bitcoin_change) * POOL_PRICE + ); + assert_eq!( + liquidity_receipt_data.maturity_date, + env.get_current_time() + .add_seconds(*lockup_period.seconds() as i64) + .unwrap() + ); + + let upfront_reward_resource_address = + upfront_reward.0.resource_address(env)?; + let upfront_reward_amount = upfront_reward.0.amount(env)?; + assert_eq!(upfront_reward_resource_address, XRD); + assert_eq!( + upfront_reward_amount, + (BITCOIN_CONTRIBUTION - bitcoin_change) * ORACLE_PRICE * LOCKUP_REWARD + ); + + Ok(()) +} + +#[test] +fn cant_close_a_liquidity_position_using_a_fake_nft() -> Result<(), RuntimeError> +{ + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let fake_liquidity_receipt = + ResourceBuilder::new_ruid_non_fungible(OwnerRole::None) + .mint_roles(mint_roles! { + minter => rule!(allow_all); + minter_updater => rule!(allow_all); + }) + .burn_roles(burn_roles! { + burner => rule!(allow_all); + burner_updater => rule!(allow_all); + }) + .mint_initial_supply( + [utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = + ociswap_v1.pools.bitcoin.try_into().unwrap(); + receipt.user_resource_address = resources.bitcoin + })], + env, + )?; + + // Act + let rtn = protocol.ignition.close_liquidity_position( + NonFungibleBucket(fake_liquidity_receipt), + env, + ); + + // Assert + assert_is_ignition_not_a_valid_liquidity_receipt_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_close_a_liquidity_position_when_closing_is_closed( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + protocol + .ignition + .set_is_close_position_enabled(false, env)?; + + let (bucket, _) = ResourceManager(ociswap_v1.liquidity_receipt) + .mint_non_fungible_single_ruid( + utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = + ociswap_v1.pools.bitcoin.try_into().unwrap(); + receipt.user_resource_address = resources.bitcoin + }), + env, + )?; + + // Act + let rtn = protocol + .ignition + .close_liquidity_position(NonFungibleBucket(bucket), env); + + // Assert + assert_is_ignition_closing_liquidity_positions_is_closed_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_close_a_liquidity_position_with_more_than_one_nft( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + resources, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + + let (bucket1, _) = ResourceManager(ociswap_v1.liquidity_receipt) + .mint_non_fungible_single_ruid( + utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = + ociswap_v1.pools.bitcoin.try_into().unwrap(); + receipt.user_resource_address = resources.bitcoin + }), + env, + )?; + let (bucket2, _) = ResourceManager(ociswap_v1.liquidity_receipt) + .mint_non_fungible_single_ruid( + utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = + ociswap_v1.pools.bitcoin.try_into().unwrap(); + receipt.user_resource_address = resources.bitcoin + }), + env, + )?; + bucket1.put(bucket2, env)?; + + // Act + let rtn = protocol + .ignition + .close_liquidity_position(NonFungibleBucket(bucket1), env); + + // Assert + assert_is_ignition_more_than_one_liquidity_receipt_nfts_error(&rtn); + + Ok(()) +} + +#[test] +fn cant_close_a_liquidity_position_before_its_maturity_date( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let (bucket, _) = ResourceManager(ociswap_v1.liquidity_receipt) + .mint_non_fungible_single_ruid( + utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = + ociswap_v1.pools.bitcoin.try_into().unwrap(); + receipt.user_resource_address = resources.bitcoin; + env.set_current_time(Instant::new(60)); + receipt.maturity_date = Instant::new(120); + }), + env, + )?; + + // Act + let rtn = protocol + .ignition + .close_liquidity_position(NonFungibleBucket(bucket), env); + + // Assert + assert_is_ignition_liquidity_position_has_not_matured_error(&rtn); + + Ok(()) +} + +#[test] +fn can_close_a_liquidity_position_the_minute_it_matures( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (liquidity_receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let liquidity_receipt_data = ResourceManager(ociswap_v1.liquidity_receipt) + .get_non_fungible_data::<_, _, LiquidityReceipt>( + liquidity_receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + env, + )?; + env.set_current_time(liquidity_receipt_data.maturity_date); + protocol + .oracle + .set_price(resources.bitcoin, XRD, dec!(1), env)?; + + // Act + let rtn = protocol + .ignition + .close_liquidity_position(liquidity_receipt, env); + + // Assert + assert!(rtn.is_ok(), "{rtn:#?}"); + + Ok(()) +} + +#[test] +fn cant_close_a_liquidity_position_of_a_pool_with_no_adapter( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + .. + } = ScryptoTestEnv::new()?; + let (bucket, _) = ResourceManager(ociswap_v1.liquidity_receipt) + .mint_non_fungible_single_ruid( + utils::liquidity_receipt_data_with_modifier(|receipt| { + receipt.pool_address = FAUCET; + }), + env, + )?; + + // Act + let rtn = protocol + .ignition + .close_liquidity_position(NonFungibleBucket(bucket), env); + + // Assert + assert_is_ignition_no_adapter_found_for_pool_error(&rtn); + + Ok(()) +} + +#[test] +fn user_gets_back_the_same_amount_they_put_in_when_user_resource_price_goes_down( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let bitcoin_bucket = ResourceManager(resources.bitcoin) + .mint_fungible(dec!(100_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(bitcoin_bucket, env)?; + + let current_time = env.get_current_time(); + env.set_current_time( + current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(), + ); + + let pool_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)?; + assert_eq!(pool_price.base, resources.bitcoin); + assert_eq!(pool_price.quote, XRD); + protocol.oracle.set_price( + pool_price.base, + pool_price.quote, + pool_price.price, + env, + )?; + + // Act + let assets_back = + protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let indexed_buckets = IndexedBuckets::from_buckets(assets_back, env)?; + assert_eq!(indexed_buckets.len(), 2); + + assert_eq!( + indexed_buckets + .get(&resources.bitcoin) + .expect("We expect to get bitcoin back!") + .amount(env)?, + // Og Amount In + Estimated fees + dec!(100) + dec!(0.50062606) + ); + assert_eq!( + indexed_buckets + .get(&XRD) + .expect("We expect to get bitcoin back!") + .amount(env)?, + dec!(0) + ); + + Ok(()) +} + +#[test] +fn user_gets_enough_protocol_resource_to_purchase_back_user_assets_lost_due_to_impermanent_loss( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(10_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(xrd_bucket, env)?; + + let current_time = env.get_current_time(); + env.set_current_time( + current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(), + ); + + let pool_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)?; + let oracle_price = pool_price; + assert_eq!(pool_price.base, resources.bitcoin); + assert_eq!(pool_price.quote, XRD); + protocol.oracle.set_price( + pool_price.base, + pool_price.quote, + oracle_price.price, + env, + )?; + + // Act + let assets_back = + protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let indexed_buckets = IndexedBuckets::from_buckets(assets_back, env)?; + assert_eq!(indexed_buckets.len(), 2); + + assert_eq!( + indexed_buckets + .get(&resources.bitcoin) + .expect("We expect to get bitcoin back!") + .amount(env)?, + dec!(90.99181893) + ); + assert_eq!( + indexed_buckets + .get(&XRD) + .expect("We expect to get bitcoin back!") + .amount(env)?, + (dec!(100) - dec!(90.99181893)) * oracle_price.price + ); + + Ok(()) +} + +#[test] +fn user_gets_enough_protocol_resource_to_purchase_back_user_assets_lost_due_to_impermanent_loss_according_to_oracle_price_not_pool_price( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(10_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(xrd_bucket, env)?; + + let current_time = env.get_current_time(); + env.set_current_time( + current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(), + ); + + let pool_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)?; + let oracle_price = pool_price.price - (dec!(0.005) * pool_price.price); + assert_eq!(pool_price.base, resources.bitcoin); + assert_eq!(pool_price.quote, XRD); + protocol.oracle.set_price( + pool_price.base, + pool_price.quote, + oracle_price, + env, + )?; + + // Act + let assets_back = + protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let indexed_buckets = IndexedBuckets::from_buckets(assets_back, env)?; + assert_eq!(indexed_buckets.len(), 2); + + assert_eq!( + indexed_buckets + .get(&resources.bitcoin) + .expect("We expect to get bitcoin back!") + .amount(env)?, + dec!(90.99181893) + ); + assert_eq!( + indexed_buckets + .get(&XRD) + .expect("We expect to get bitcoin back!") + .amount(env)?, + (dec!(100) - dec!(90.99181893)) * oracle_price + ); + + Ok(()) +} + +#[test] +fn amount_of_protocol_resources_returned_to_user_has_an_upper_bound_of_the_amount_obtained_from_the_pool( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + mut ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, _, _) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + + let xrd_bucket = + ResourceManager(XRD).mint_fungible(dec!(10_000_000_000), env)?; + let _ = ociswap_v1.pools.bitcoin.swap(xrd_bucket, env)?; + + let current_time = env.get_current_time(); + env.set_current_time( + current_time + .add_seconds(*LockupPeriod::from_months(6).unwrap().seconds() as i64) + .unwrap(), + ); + + let pool_price = ociswap_v1 + .adapter + .price(ociswap_v1.pools.bitcoin.try_into().unwrap(), env)?; + let oracle_price = pool_price; + assert_eq!(pool_price.base, resources.bitcoin); + assert_eq!(pool_price.quote, XRD); + protocol.oracle.set_price( + pool_price.base, + pool_price.quote, + oracle_price.price, + env, + )?; + + // Act + let assets_back = + protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let indexed_buckets = IndexedBuckets::from_buckets(assets_back, env)?; + assert_eq!(indexed_buckets.len(), 2); + + assert_eq!( + indexed_buckets + .get(&resources.bitcoin) + .expect("We expect to get bitcoin back!") + .amount(env)?, + dec!(1.00000098) + ); + assert_eq!( + indexed_buckets + .get(&XRD) + .expect("We expect to get bitcoin back!") + .amount(env)?, + dec!(10099.99000000999999) + ); + + Ok(()) +} + +#[test] +fn protocol_manager_cant_perform_forced_liquidation() -> Result<(), RuntimeError> +{ + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new()?; + env.enable_auth_module(); + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + // Act + LocalAuthZone::push( + protocol.protocol_manager_badge.create_proof_of_all(env)?, + env, + )?; + let rtn = protocol + .ignition + .forcefully_liquidate(receipt_global_id, env); + + // Assert + matches!( + rtn, + Err(RuntimeError::SystemModuleError( + SystemModuleError::AuthError(AuthError::Unauthorized(..)) + )) + ); + + Ok(()) +} + +#[test] +fn protocol_owner_can_perform_forced_liquidation() -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: i64::MAX, + ..Default::default() + })?; + env.enable_auth_module(); + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_days(7 * 30).unwrap()); + + // Act + LocalAuthZone::push( + protocol.protocol_owner_badge.create_proof_of_all(env)?, + env, + )?; + let rtn = protocol + .ignition + .forcefully_liquidate(receipt_global_id, env); + + // Assert + assert!(rtn.is_ok()); + Ok(()) +} + +#[test] +fn protocol_owner_can_perform_forced_liquidation_even_when_liquidation_is_closed( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: i64::MAX, + ..Default::default() + })?; + env.enable_auth_module(); + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_days(7 * 30).unwrap()); + + LocalAuthZone::push( + protocol.protocol_owner_badge.create_proof_of_all(env)?, + env, + )?; + protocol + .ignition + .set_is_close_position_enabled(false, env)?; + + // Act + let rtn = protocol + .ignition + .forcefully_liquidate(receipt_global_id, env); + + // Assert + assert!(rtn.is_ok()); + Ok(()) +} + +#[test] +fn protocol_owner_cant_perform_forced_liquidation_before_maturity_date( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: i64::MAX, + ..Default::default() + })?; + env.enable_auth_module(); + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + // Act + LocalAuthZone::push( + protocol.protocol_owner_badge.create_proof_of_all(env)?, + env, + )?; + let rtn = protocol + .ignition + .forcefully_liquidate(receipt_global_id, env); + + // Assert + assert_is_ignition_liquidity_position_has_not_matured_error(&rtn); + Ok(()) +} + +#[test] +fn forcefully_liquidated_resources_can_be_claimed_when_closing_liquidity_position( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: i64::MAX, + ..Default::default() + })?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_days(7 * 30).unwrap()); + + protocol + .ignition + .forcefully_liquidate(receipt_global_id, env)?; + + // Act + let buckets = protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let buckets = IndexedBuckets::from_buckets(buckets, env)?; + let bitcoin_bucket = buckets.get(&resources.bitcoin).unwrap(); + let amount = bitcoin_bucket.amount(env)?; + assert_eq!(amount, dec!(99.99999999)); + Ok(()) +} + +#[test] +fn forcefully_liquidated_resources_can_be_claimed_when_closing_liquidity_position_even_when_closing_is_disabled( +) -> Result<(), RuntimeError> { + // Arrange + let Environment { + environment: ref mut env, + mut protocol, + ociswap_v1, + resources, + .. + } = ScryptoTestEnv::new_with_configuration(Configuration { + maximum_allowed_price_staleness_seconds: i64::MAX, + ..Default::default() + })?; + + let bitcoin_bucket = + ResourceManager(resources.bitcoin).mint_fungible(dec!(100), env)?; + let (receipt, ..) = protocol.ignition.open_liquidity_position( + FungibleBucket(bitcoin_bucket), + ociswap_v1.pools.bitcoin.try_into().unwrap(), + LockupPeriod::from_months(6).unwrap(), + env, + )?; + let receipt_global_id = NonFungibleGlobalId::new( + receipt.0.resource_address(env)?, + receipt + .0 + .non_fungible_local_ids(env)? + .first() + .unwrap() + .clone(), + ); + + let current_time = env.get_current_time(); + env.set_current_time(current_time.add_days(7 * 30).unwrap()); + + protocol + .ignition + .forcefully_liquidate(receipt_global_id, env)?; + + protocol + .ignition + .set_is_close_position_enabled(false, env)?; + + // Act + let buckets = protocol.ignition.close_liquidity_position(receipt, env)?; + + // Assert + let buckets = IndexedBuckets::from_buckets(buckets, env)?; + let bitcoin_bucket = buckets.get(&resources.bitcoin).unwrap(); + let amount = bitcoin_bucket.amount(env)?; + assert_eq!(amount, dec!(99.99999999)); + Ok(()) +} + +mod utils { + use super::*; + + pub fn liquidity_receipt_data() -> LiquidityReceipt { + LiquidityReceipt { + name: "Some name".to_owned(), + lockup_period: "6 months".to_owned(), + pool_address: FAUCET, + user_resource_address: XRD, + user_contribution_amount: dec!(100_000_000_000), + user_resource_volatility_classification: NonVolatile, + protocol_contribution_amount: dec!(1), + maturity_date: Instant::new(1), + adapter_specific_information: OciswapV1AdapterSpecificInformation { + pool_k_when_position_opened: pdec!(100), + user_share_in_pool_when_position_opened: dec!(0.01), + } + .into(), + } + } + + pub fn liquidity_receipt_data_with_modifier( + modifier: impl FnOnce(&mut LiquidityReceipt), + ) -> LiquidityReceipt { + let mut data = liquidity_receipt_data(); + modifier(&mut data); + data + } +} diff --git a/tools/bootstrap/Cargo.toml b/tools/bootstrap/Cargo.toml new file mode 100644 index 00000000..084cc679 --- /dev/null +++ b/tools/bootstrap/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "bootstrap" +description = "A tool used to bootstrap project Ignition on various networks." +version.workspace = true +edition.workspace = true + +[dependencies] +sbor = { workspace = true } +transaction = { workspace = true } +radix-engine = { workspace = true } +radix-engine-interface = { workspace = true } + +common = { path = "../../libraries/common" } +ignition = { path = "../../packages/ignition" } +gateway-client = { path = "../../libraries/gateway-client" } +package-loader = { path = "../../libraries/package-loader", features = [ + "build-time-blueprints", +] } +ociswap-v1-adapter-v1 = { path = "../../packages/ociswap-v1-adapter-v1", features = [ + "manifest-builder-stubs", +] } +caviarnine-v1-adapter-v1 = { path = "../../packages/caviarnine-v1-adapter-v1", features = [ + "manifest-builder-stubs", +] } + +serde = { version = "1.0.196", features = ["derive"] } +serde_json = { version = "1.0.112" } + +hex = { version = "0.4.3", features = ["serde"] } +clap = { version = "4.4.18", features = ["derive"] } +rand = { version = "0.8.5" } + +[lints] +workspace = true \ No newline at end of file diff --git a/tools/bootstrap/src/cli.rs b/tools/bootstrap/src/cli.rs new file mode 100644 index 00000000..839ab556 --- /dev/null +++ b/tools/bootstrap/src/cli.rs @@ -0,0 +1,20 @@ +use crate::error::*; +use crate::mainnet_testing; +use crate::stokenet_production; + +use clap::Parser; + +#[derive(Parser, Debug)] +pub enum Cli { + StokenetProduction(stokenet_production::StokenetProduction), + MainnetTesting(mainnet_testing::MainnetTesting), +} + +impl Cli { + pub fn run(self, out: &mut O) -> Result<(), Error> { + match self { + Self::StokenetProduction(cmd) => cmd.run(out), + Self::MainnetTesting(cmd) => cmd.run(out), + } + } +} diff --git a/tools/bootstrap/src/error.rs b/tools/bootstrap/src/error.rs new file mode 100644 index 00000000..4a80a1d1 --- /dev/null +++ b/tools/bootstrap/src/error.rs @@ -0,0 +1,65 @@ +use radix_engine::transaction::*; +use transaction::manifest::*; + +type TransactionPreviewError = gateway_client::apis::Error< + gateway_client::apis::transaction_api::TransactionPreviewError, +>; +type TransactionCommittedDetailsError = gateway_client::apis::Error< + gateway_client::apis::transaction_api::TransactionCommittedDetailsError, +>; +type TransactionSubmitError = gateway_client::apis::Error< + gateway_client::apis::transaction_api::TransactionSubmitError, +>; +type GatewayStatusError = gateway_client::apis::Error< + gateway_client::apis::status_api::GatewayStatusError, +>; + +#[derive(Debug)] +pub enum Error { + ManifestDecompilation(DecompileError), + TransactionPreviewError(TransactionPreviewError), + TransactionSubmitError(TransactionSubmitError), + TransactionCommittedDetailsError(TransactionCommittedDetailsError), + GatewayStatusError(GatewayStatusError), + PreviewFailed { + manifest: String, + receipt: TransactionReceiptV1, + }, + TransactionPollingYieldedNothing { + intent_hash: String, + }, + TransactionWasNotSuccessful { + intent_hash: String, + }, + FailedToLoadPrivateKey, +} + +impl From for Error { + fn from(value: DecompileError) -> Self { + Self::ManifestDecompilation(value) + } +} + +impl From for Error { + fn from(value: TransactionPreviewError) -> Self { + Self::TransactionPreviewError(value) + } +} + +impl From for Error { + fn from(value: TransactionSubmitError) -> Self { + Self::TransactionSubmitError(value) + } +} + +impl From for Error { + fn from(value: TransactionCommittedDetailsError) -> Self { + Self::TransactionCommittedDetailsError(value) + } +} + +impl From for Error { + fn from(value: GatewayStatusError) -> Self { + Self::GatewayStatusError(value) + } +} diff --git a/tools/bootstrap/src/macros.rs b/tools/bootstrap/src/macros.rs new file mode 100644 index 00000000..d7fd9452 --- /dev/null +++ b/tools/bootstrap/src/macros.rs @@ -0,0 +1,63 @@ +#![allow(unused_macros)] + +#[macro_export] +macro_rules! package_address { + ($address: expr) => { + ::radix_engine_interface::prelude::PackageAddress::try_from( + $crate::decode_to_node_id!($address), + ) + .unwrap() + }; +} + +#[macro_export] +macro_rules! component_address { + ($address: expr) => { + ::radix_engine_interface::prelude::ComponentAddress::try_from( + $crate::decode_to_node_id!($address), + ) + .unwrap() + }; +} + +#[macro_export] +macro_rules! resource_address { + ($address: expr) => { + ::radix_engine_interface::prelude::ResourceAddress::try_from( + $crate::decode_to_node_id!($address), + ) + .unwrap() + }; +} + +#[macro_export] +macro_rules! internal_address { + ($address: expr) => { + ::radix_engine_interface::prelude::InternalAddress::try_from( + $crate::decode_to_node_id!($address), + ) + .unwrap() + }; +} + +#[macro_export] +macro_rules! global_address { + ($address: expr) => { + ::radix_engine_interface::prelude::GlobalAddress::try_from( + $crate::decode_to_node_id!($address), + ) + .unwrap() + }; +} + +#[macro_export] +macro_rules! decode_to_node_id { + ($address: expr) => { + ::radix_engine_interface::prelude::AddressBech32Decoder::validate_and_decode_ignore_hrp($address) + .ok() + .and_then(|(_, _, value)| + value.try_into().map(NodeId).ok() + ) + .unwrap() + }; +} diff --git a/tools/bootstrap/src/main.rs b/tools/bootstrap/src/main.rs new file mode 100644 index 00000000..f4da8342 --- /dev/null +++ b/tools/bootstrap/src/main.rs @@ -0,0 +1,16 @@ +#![allow(dead_code, clippy::enum_variant_names)] + +#[macro_use] +mod macros; +mod cli; +mod error; +mod mainnet_testing; +mod stokenet_production; +mod transaction_service; +mod types; + +fn main() -> Result<(), error::Error> { + let mut out = std::io::stdout(); + let cli = ::parse(); + cli.run(&mut out) +} diff --git a/tools/bootstrap/src/mainnet_testing.rs b/tools/bootstrap/src/mainnet_testing.rs new file mode 100644 index 00000000..50d50445 --- /dev/null +++ b/tools/bootstrap/src/mainnet_testing.rs @@ -0,0 +1,666 @@ +use crate::error::*; +use crate::transaction_service::*; +use crate::types::*; +use crate::*; +use clap::Parser; +use common::prelude::*; +use ignition::{InitializationParametersManifest, PoolBlueprintInformation}; +use package_loader::PackageLoader; +use radix_engine_interface::api::node_modules::auth::*; +use radix_engine_interface::api::node_modules::*; +use radix_engine_interface::blueprints::account::*; +use radix_engine_interface::prelude::*; +use transaction::prelude::*; + +const PRIVATE_KEY_ENVIRONMENT_VARIABLE: &str = "PRIVATE_KEY"; + +#[derive(Parser, Debug)] +pub struct MainnetTesting {} + +impl MainnetTesting { + pub fn run(self, _: &mut O) -> Result<(), Error> { + // Loading the private key that will notarize and pay the fees of the + // transaction. + let notary_private_key = { + std::env::var(PRIVATE_KEY_ENVIRONMENT_VARIABLE) + .map_err(|_| Error::FailedToLoadPrivateKey) + .and_then(|hex| { + hex::decode(hex).map_err(|_| Error::FailedToLoadPrivateKey) + }) + .and_then(|bytes| { + Ed25519PrivateKey::from_bytes(&bytes) + .map_err(|_| Error::FailedToLoadPrivateKey) + }) + .map(PrivateKey::Ed25519) + }?; + let notary_account = ComponentAddress::virtual_account_from_public_key( + ¬ary_private_key.public_key(), + ); + let fee_handling = FeeHandling::EstimateAndLock { + fee_payer_account: notary_account, + fee_payer_private_key: ¬ary_private_key, + }; + + // Initializing all of the data that this command will use. These are + // pretty much constants but we can't make them constants because most + // of the functions are not `const`. There is also not really a point + // in making them a lazy static, let's keep things simple. + + /* cSpell:disable - Sorry for this, I dislike it too. */ + const GATEWAY_API_BASE_URL: &str = "https://mainnet.radixdlt.com/"; + let network_definition = NetworkDefinition::mainnet(); + let bech32m_coders = + Bech32mCoders::from_network_definition(&network_definition); + + // TODO: What do we want these values to be? + const MAXIMUM_ALLOWED_PRICE_STALENESS_IN_SECONDS: i64 = 60; // 60 seconds + const MAXIMUM_ALLOWED_PRICE_DIFFERENCE_PERCENTAGE: Decimal = + Decimal::MAX; // TODO: No oracle is deployed on mainnet for testing yet. + + let protocol_resource = resource_address!("resource_rdx1t4dekrf58h0r28s3c93z92w3jt5ngx87jzd63mgc597zmf3534rxfv"); + let resources = NameIndexedResourceInformation { + bitcoin: resource_address!("resource_rdx1t58dla7ykxzxe5es89wlhgzatqla0gceukg0eeduzvtj4cxd55etn8"), + ethereum: resource_address!("resource_rdx1tkscrlztcyn82ej5z3n232f0qqp0qur69arjf279ppmg5usa3xhnsm"), + usdc: resource_address!("resource_rdx1th7nx2hy0cf6aea6mz7zhkdmy4p45s488xutltnp7296zxj8hwchpf"), + usdt: resource_address!("resource_rdx1tkafx32lu72mcxr85gjx0rh3rx9q89zqffg4phmv5rxdqg5fnd0w7s"), + }; + let exchanges = NameIndexedDexInformation { + caviarnine_v1: DexInformation { + package: package_address!("package_rdx1p4r9rkp0cq67wmlve544zgy0l45mswn6h798qdqm47x4762h383wa3"), + pools: NameIndexedResourceInformation { + bitcoin: component_address!("component_rdx1crzl2c39m83lpe6fv62epgp3phqunxhc264ys23qz8xeemjcu8lln3"), + ethereum: component_address!("component_rdx1cqk2ufmdq6pkcu7ed7r6u9hmdsht9gyd8y8wwtd7w5znefz9k54a7d"), + usdc: component_address!("component_rdx1cq9q8umlpmngff6y4e534htz0n37te4m7vsj50u9zc58ys65zl6jv9"), + usdt: component_address!("component_rdx1cpl0v3lndt9d7g7uuepztxs9m7m24ly0yfhvcum2y7tm0vlzst0l5y") + } + }, + // TODO: Ths following is INCORRECT INFORMATION! There is no Ociswap + // package on mainnet. + ociswap_v1: DexInformation { + package: package_address!("package_rdx1p5l6dp3slnh9ycd7gk700czwlck9tujn0zpdnd0efw09n2zdnn0lzx"), + pools: NameIndexedResourceInformation { + bitcoin: component_address!("component_rdx1cr5uxxjq4a0r3gfn6yd62lk96fqca34tnmyqdxkwefhckcjea4t3am"), + ethereum: component_address!("component_rdx1cqylpcl8p45l2h5ew0qrkwyz23dky3e6ucs7kkhrtm90k9z3kzeztn"), + usdc: component_address!("component_rdx1cq96chge0q6kkk962heg0mgfl82gjw7x25dp9jv80gkx90mc3hk2ua"), + usdt: component_address!("component_rdx1cz3fa8qtfgfwjt3fzrtm544a89p5laerww7590g2tfcradqwdv3laq") + } + }, + }; + // TODO: Numbers here are not real and I have added from just to get + // things going. MUST modify before launch. + let reward_information = indexmap! { + LockupPeriod::from_minutes(0).unwrap() => dec!(0.125), // 12.5% + LockupPeriod::from_minutes(1).unwrap() => dec!(0.15), // 15.0% + }; + + // TODO: MUST determine what those accounts are prior to launch! + // For now, for the TEST deployments these are accounts that I CONTROL! + let protocol_manager_account = component_address!("account_rdx12xvk6x3usuzu7hdc5clc7lpu8e4czze6xa7vrw7vlek0h84j9299na"); + let protocol_owner_account = component_address!("account_rdx12xvk6x3usuzu7hdc5clc7lpu8e4czze6xa7vrw7vlek0h84j9299na"); + + /* cSpell:enable */ + + // An ephemeral private key that we will use the bootstrapping process. + // This key will initially control the dApp definition to allow us to + // easily update the metadata and will later on change the owner role + // of the dApp definition to the protocol owner. + + let ephemeral_private_key = + Ed25519PrivateKey::from_u64(rand::random()).unwrap(); + println!( + "Ephemeral Private Key: {:?}", + ephemeral_private_key.to_bytes() + ); + + let ephemeral_private_key = PrivateKey::Ed25519( + Ed25519PrivateKey::from_u64(rand::random()).unwrap(), + ); + let ephemeral_virtual_signature_badge = + NonFungibleGlobalId::from_public_key( + &ephemeral_private_key.public_key(), + ); + + // This is the transaction service that the submission will happen + // through. It does most of the heavy lifting associated with the + // transaction submission. + let transaction_service = + TransactionService::new(&bech32m_coders, GATEWAY_API_BASE_URL); + + // Creating the dApp definition account. When this account starts it + // its owner will be a virtual signature badge which will change once + // add all of the metadata fields that we want to add. The the manifest + // that involves the dApp definition will set the metadata on it and + // will also change its owner to be the protocol Owner badge. + let dapp_definition_account = { + let manifest = ManifestBuilder::new() + .call_function( + ACCOUNT_PACKAGE, + ACCOUNT_BLUEPRINT, + ACCOUNT_CREATE_ADVANCED_IDENT, + AccountCreateAdvancedManifestInput { + owner_role: OwnerRole::Updatable(rule!(require( + ephemeral_virtual_signature_badge + ))), + address_reservation: None, + }, + ) + .build(); + std::thread::sleep(std::time::Duration::from_secs(5)); + *transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_component_addresses + .first() + .expect("Must succeed!") + }; + + // Creating the protocol owner and the protocol manager badges and + // sending them off to the accounts specified up above. + let (protocol_manager_badge, protocol_owner_badge) = { + let manifest = ManifestBuilder::new() + // The protocol manager badge + .create_fungible_resource( + OwnerRole::None, + true, + 0, + Default::default(), + // TODO: What do we want those to be? Any preference? + metadata! { + init { + "name" => "Ignition Protocol Manager", updatable; + "symbol" => "IGNPM", updatable; + "description" => "A badge that gives the authority to manage the Ignition protocol.", updatable; + "badge" => vec!["badge"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + } + }, + Some(dec!(1)), + ) + .try_deposit_entire_worktop_or_abort(protocol_manager_account, None) + // The protocol owner badge + .create_fungible_resource( + OwnerRole::None, + true, + 0, + Default::default(), + metadata! { + init { + "name" => "Ignition Protocol Owner", updatable; + "symbol" => "IGNPO", updatable; + "description" => "A badge that of the owner of the ignition protocol.", updatable; + "badge" => vec!["badge"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + } + }, + Some(dec!(1)), + ) + .try_deposit_entire_worktop_or_abort(protocol_owner_account, None) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let resource_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_resource_addresses; + ( + *resource_addresses.first().unwrap(), + *resource_addresses.get(1).unwrap(), + ) + }; + + let protocol_manager_rule = rule!(require(protocol_manager_badge)); + let protocol_owner_rule = rule!(require(protocol_owner_badge)); + let owner_role = OwnerRole::Fixed(protocol_owner_rule.clone()); + + // Publishing the packages. + let ( + ignition_package_address, + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) = { + let (ignition_code, ignition_package_definition) = + PackageLoader::get("ignition"); + let (simple_oracle_code, simple_oracle_package_definition) = + PackageLoader::get("simple-oracle"); + let ( + ociswap_v1_adapter_v1_code, + ociswap_v1_adapter_v1_package_definition, + ) = PackageLoader::get("ociswap-v1-adapter-v1"); + let ( + caviarnine_v1_adapter_v1_code, + caviarnine_v1_adapter_v1_package_definition, + ) = PackageLoader::get("caviarnine-v1-adapter-v1"); + + // We can publish the simple oracle, ociswap adapter v1, and + // caviarnine adapter v1 all in a single transaction since they + // are below the size limit. + let manifest = ManifestBuilder::new() + .publish_package_advanced( + None, + simple_oracle_code, + simple_oracle_package_definition, + metadata_init! { + "name" => "Simple Oracle Package", updatable; + "description" => "The implementation of the Oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .publish_package_advanced( + None, + ociswap_v1_adapter_v1_code, + ociswap_v1_adapter_v1_package_definition, + metadata_init! { + "name" => "Ociswap Adapter v1 Package", updatable; + "description" => "The implementation of an adapter for Ociswap for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .publish_package_advanced( + None, + caviarnine_v1_adapter_v1_code, + caviarnine_v1_adapter_v1_package_definition, + metadata_init! { + "name" => "Caviarnine Adapter v1 Package", updatable; + "description" => "The implementation of an adapter for Caviarnine for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ).build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let package_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_package_addresses; + + let ( + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) = ( + *package_addresses.first().unwrap(), + *package_addresses.get(1).unwrap(), + *package_addresses.get(2).unwrap(), + ); + + // Publishing the Ignition package + let manifest = ManifestBuilder::new() + .publish_package_advanced( + None, + ignition_code, + ignition_package_definition, + metadata_init! { + "name" => "Ignition Package", updatable; + "description" => "The implementation of the Ignition protocol.", updatable; + "tags" => Vec::::new(), updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .build(); + std::thread::sleep(std::time::Duration::from_secs(5)); + let ignition_package_address = *transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_package_addresses + .first() + .unwrap(); + + ( + ignition_package_address, + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) + }; + + // Creating the different liquidity receipt resources that the different + // exchanges will use. They will be mintable and burnable through the + // Ignition package caller badge. + let ignition_package_global_caller_rule = + rule!(require(package_of_direct_caller(ignition_package_address))); + let ( + ociswap_v1_liquidity_receipt_resource, + caviarnine_v1_liquidity_receipt_resource, + ) = { + let roles = NonFungibleResourceRoles { + // Mintable and burnable by the Ignition package and + // the protocol owner can update who can do that. + mint_roles: mint_roles! { + minter => ignition_package_global_caller_rule.clone(); + minter_updater => protocol_owner_rule.clone(); + }, + burn_roles: burn_roles! { + burner => ignition_package_global_caller_rule.clone(); + burner_updater => protocol_owner_rule.clone(); + }, + // We reserve the right to change the data of the + // liquidity receipts when we want. + non_fungible_data_update_roles: non_fungible_data_update_roles! { + non_fungible_data_updater => rule!(deny_all); + non_fungible_data_updater_updater => protocol_owner_rule.clone(); + }, + // Everything else is deny all and can't be changed. + recall_roles: recall_roles! { + recaller => rule!(deny_all); + recaller_updater => rule!(deny_all); + }, + freeze_roles: freeze_roles! { + freezer => rule!(deny_all); + freezer_updater => rule!(deny_all); + }, + deposit_roles: deposit_roles! { + depositor => rule!(allow_all); + depositor_updater => rule!(deny_all); + }, + withdraw_roles: withdraw_roles! { + withdrawer => rule!(allow_all); + withdrawer_updater => rule!(deny_all); + }, + }; + + let manifest = ManifestBuilder::new() + // Ociswap liquidity receipt + .call_function( + RESOURCE_PACKAGE, + NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, + NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT, + NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput { + owner_role: owner_role.clone(), + track_total_supply: true, + non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::>(), + entries: Vec::new(), + resource_roles: roles.clone(), + metadata: metadata! { + roles { + metadata_setter => protocol_owner_rule.clone(); + metadata_setter_updater => protocol_owner_rule.clone(); + metadata_locker => protocol_owner_rule.clone(); + metadata_locker_updater => protocol_owner_rule.clone(); + }, + init { + // TODO: Confirm with the exchanges what they + // want their name to be. + "name" => "Ignition LP: Ociswap", updatable; + "description" => "Represents a particular contribution of liquidity to Ociswap through the Ignition liquidity incentives program. See the redeem_url metadata for where to redeem these NFTs.", updatable; + "tags" => vec!["lp token"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + // TODO: Must get this from our design team + "icon_url" => UncheckedUrl::of("https://www.google.com"), updatable; + "DEX" => "Ociswap", updatable; + // TODO: Must get this from Ociswap! + "redeem_url" => UncheckedUrl::of("https://www.google.com"), updatable; + } + }, + address_reservation: None + } + ) + // Caviarnine liquidity receipt + .call_function( + RESOURCE_PACKAGE, + NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, + NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT, + NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput { + owner_role: owner_role.clone(), + track_total_supply: true, + non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::>(), + entries: Vec::new(), + resource_roles: roles.clone(), + metadata: metadata! { + roles { + metadata_setter => protocol_owner_rule.clone(); + metadata_setter_updater => protocol_owner_rule.clone(); + metadata_locker => protocol_owner_rule.clone(); + metadata_locker_updater => protocol_owner_rule.clone(); + }, + init { + // TODO: Confirm with the exchanges what they want + // their name to be. + "name" => "Ignition LP: Caviarnine", updatable; + "description" => "Represents a particular contribution of liquidity to Caviarnine through the Ignition liquidity incentives program. See the redeem_url metadata for where to redeem these NFTs.", updatable; + "tags" => vec!["lp token"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + // TODO: Must get this from our design team + "icon_url" => UncheckedUrl::of("https://www.google.com"), updatable; + "DEX" => "Caviarnine", updatable; + // TODO: Must get this from Caviarnine! + "redeem_url" => UncheckedUrl::of("https://www.google.com"), updatable; + } + }, + address_reservation: None + } + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let resource_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_resource_addresses; + ( + *resource_addresses.first().unwrap(), + *resource_addresses.get(1).unwrap(), + ) + }; + + // Creating the oracle and adapters. + let ( + ignition_component, + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) = { + let manifest = ManifestBuilder::new() + // Creating the oracle component + .call_function( + simple_oracle_package_address, + "SimpleOracle", + "instantiate", + ( + protocol_manager_rule.clone(), + metadata_init! { + "name" => "Ignition Oracle", updatable; + "description" => "The oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + // Creating the ociswap adapter v1 component + .call_function( + ociswap_v1_adapter_v1_package_address, + "OciswapV1Adapter", + "instantiate", + ( + metadata_init! { + "name" => "Ignition Ociswap Adapter", updatable; + "description" => "The adapter used by the Ignition protocol to communicate with Ociswap pools.", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + // Creating the ociswap adapter v1 component + .call_function( + caviarnine_v1_adapter_v1_package_address, + "CaviarnineV1Adapter", + "instantiate", + ( + metadata_init! { + "name" => "Ignition Caviarnine Adapter", updatable; + "description" => "The adapter used by the Ignition protocol to communicate with Caviarnine pools.", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let component_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_component_addresses; + + let ( + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) = ( + *component_addresses.first().unwrap(), + *component_addresses.get(1).unwrap(), + *component_addresses.get(2).unwrap(), + ); + + // Instantiating the Ignition component + let manifest = ManifestBuilder::new() + // Instantiate Ignition. + .call_function( + ignition_package_address, + "Ignition", + "instantiate", + manifest_args!( + metadata_init! { + "name" => "Ignition", updatable; + "description" => "The Ignition protocol component", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + protocol_owner_rule.clone(), + protocol_manager_rule.clone(), + protocol_resource, + simple_oracle_component, + MAXIMUM_ALLOWED_PRICE_STALENESS_IN_SECONDS, + MAXIMUM_ALLOWED_PRICE_DIFFERENCE_PERCENTAGE, + InitializationParametersManifest { + initial_pool_information: Some(indexmap! { + BlueprintId { + package_address: exchanges.caviarnine_v1.package, + blueprint_name: "QuantaSwap".to_owned() + } => PoolBlueprintInformation { + adapter: caviarnine_v1_adapter_v1_component, + allowed_pools: exchanges.caviarnine_v1.pools.into_iter().collect(), + liquidity_receipt: caviarnine_v1_liquidity_receipt_resource + }, + BlueprintId { + package_address: exchanges.ociswap_v1.package, + blueprint_name: "BasicPool".to_owned() + } => PoolBlueprintInformation { + adapter: ociswap_v1_adapter_v1_component, + allowed_pools: exchanges.ociswap_v1.pools.into_iter().collect(), + liquidity_receipt: ociswap_v1_liquidity_receipt_resource + } + }), + initial_user_resource_volatility: Some( + indexmap! { + resources.bitcoin => Volatility::Volatile, + resources.ethereum => Volatility::Volatile, + resources.usdc => Volatility::NonVolatile, + resources.usdt => Volatility::NonVolatile, + } + ), + initial_reward_rates: Some(reward_information), + initial_volatile_protocol_resources: None, + initial_non_volatile_protocol_resources: None, + initial_is_open_position_enabled: Some(true), + initial_is_close_position_enabled: Some(true), + }, + None:: + ) + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let component_addresses = transaction_service + .submit_manifest( + manifest, + &ephemeral_private_key, + &fee_handling, + )? + .new_component_addresses; + + let ignition_component_address = + *component_addresses.first().unwrap(); + + ( + ignition_component_address, + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) + }; + + // Updating the dapp definition account with the metadata that it + // should have. + { + let manifest = ManifestBuilder::new() + .set_metadata( + dapp_definition_account, + "account_type", + "dapp definition", + ) + .set_metadata( + dapp_definition_account, + "claimed_websites", + Vec::::new(), + ) + .set_metadata( + dapp_definition_account, + "dapp_definitions", + Vec::::new(), + ) + .set_metadata( + dapp_definition_account, + "claimed_entities", + vec![ + GlobalAddress::from(protocol_manager_badge), + GlobalAddress::from(protocol_owner_badge), + GlobalAddress::from(ignition_package_address), + GlobalAddress::from(simple_oracle_package_address), + GlobalAddress::from( + ociswap_v1_adapter_v1_package_address, + ), + GlobalAddress::from( + caviarnine_v1_adapter_v1_package_address, + ), + GlobalAddress::from( + ociswap_v1_liquidity_receipt_resource, + ), + GlobalAddress::from( + caviarnine_v1_liquidity_receipt_resource, + ), + GlobalAddress::from(ignition_component), + GlobalAddress::from(simple_oracle_component), + GlobalAddress::from(ociswap_v1_adapter_v1_component), + GlobalAddress::from(caviarnine_v1_adapter_v1_component), + ], + ) + .call_role_assignment_method( + dapp_definition_account, + ROLE_ASSIGNMENT_SET_OWNER_IDENT, + RoleAssignmentSetOwnerInput { + rule: protocol_owner_rule, + }, + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + transaction_service.submit_manifest( + manifest, + &ephemeral_private_key, + &fee_handling, + )?; + } + + Ok(()) + } +} + +pub struct DexInformation { + pub pools: NameIndexedResourceInformation, + pub package: PackageAddress, +} diff --git a/tools/bootstrap/src/stokenet_production.rs b/tools/bootstrap/src/stokenet_production.rs new file mode 100644 index 00000000..03765762 --- /dev/null +++ b/tools/bootstrap/src/stokenet_production.rs @@ -0,0 +1,662 @@ +use crate::error::*; +use crate::transaction_service::*; +use crate::types::*; +use crate::*; +use clap::Parser; +use common::prelude::*; +use ignition::{InitializationParametersManifest, PoolBlueprintInformation}; +use package_loader::PackageLoader; +use radix_engine_interface::api::node_modules::auth::*; +use radix_engine_interface::api::node_modules::*; +use radix_engine_interface::blueprints::account::*; +use radix_engine_interface::prelude::*; +use transaction::prelude::*; + +const PRIVATE_KEY_ENVIRONMENT_VARIABLE: &str = "PRIVATE_KEY"; + +#[derive(Parser, Debug)] +pub struct StokenetProduction {} + +impl StokenetProduction { + pub fn run(self, _: &mut O) -> Result<(), Error> { + // Loading the private key that will notarize and pay the fees of the + // transaction. + let notary_private_key = { + std::env::var(PRIVATE_KEY_ENVIRONMENT_VARIABLE) + .map_err(|_| Error::FailedToLoadPrivateKey) + .and_then(|hex| { + hex::decode(hex).map_err(|_| Error::FailedToLoadPrivateKey) + }) + .and_then(|bytes| { + Ed25519PrivateKey::from_bytes(&bytes) + .map_err(|_| Error::FailedToLoadPrivateKey) + }) + .map(PrivateKey::Ed25519) + }?; + let notary_account = ComponentAddress::virtual_account_from_public_key( + ¬ary_private_key.public_key(), + ); + let fee_handling = FeeHandling::EstimateAndLock { + fee_payer_account: notary_account, + fee_payer_private_key: ¬ary_private_key, + }; + + // Initializing all of the data that this command will use. These are + // pretty much constants but we can't make them constants because most + // of the functions are not `const`. There is also not really a point + // in making them a lazy static, let's keep things simple. + + /* cSpell:disable - Sorry for this, I dislike it too. */ + const GATEWAY_API_BASE_URL: &str = "https://stokenet.radixdlt.com/"; + let network_definition = NetworkDefinition::stokenet(); + let bech32m_coders = + Bech32mCoders::from_network_definition(&network_definition); + + // TODO: What do we want these values to be? + const MAXIMUM_ALLOWED_PRICE_STALENESS_IN_SECONDS: i64 = 60; // 60 seconds + const MAXIMUM_ALLOWED_PRICE_DIFFERENCE_PERCENTAGE: Decimal = dec!(0.05); // 5 % + + let protocol_resource = resource_address!("resource_tdx_2_1thwmtk9qet08y3wpujd8nddmvjuqyptg5nt0mw0zcdgcrahu5k36qx"); + let resources = NameIndexedResourceInformation { + bitcoin: resource_address!("resource_tdx_2_1thltk578jr4v7axqpu5ceznhlha6ca2qtzcflqdmytgtf37xncu7l9"), + ethereum: resource_address!("resource_tdx_2_1t59gx963vzd6u6fz63h5de2zh9nmgwxc8y832edmr6pxvz98wg6zu3"), + usdc: resource_address!("resource_tdx_2_1thfv477eqwlh8x4wt6xsc62myt4z0zxmdpr4ea74fa8jnxh243y60r"), + usdt: resource_address!("resource_tdx_2_1t4p3ytx933n576pdps4ua7jkjh36zrh36a543u0tfcsu2vthavlqg8"), + }; + let exchanges = NameIndexedDexInformation { + caviarnine_v1: DexInformation { + package: package_address!("package_tdx_2_1p57g523zj736u370z6g4ynrytn7t6r2hledvzkhl6tzpg3urn0707e"), + pools: NameIndexedResourceInformation { + bitcoin: component_address!("component_tdx_2_1czt59vxdqg7q4l0gzphmt5ev6lagl2cu6sm2hsaz9y8ypcf0aukf8r"), + ethereum: component_address!("component_tdx_2_1crqpgnpf3smh7kg8d4sz4h3502l65s4tslwhg46ru07ra6l30pcsj4"), + usdc: component_address!("component_tdx_2_1cpwkf9uhel3ut4ydm58g0uyaw7sxckmp2pz7sdv79vzt9y3p7ad4fu"), + usdt: component_address!("component_tdx_2_1czmdhtq0u8f40khky4c6j74msskuz60yq3y0zewu85phrdj0ryz2hl") + } + }, + // TODO: Ths following is INCORRECT INFORMATION! There is no Ociswap + // package on Stokenet. + ociswap_v1: DexInformation { + package: package_address!("package_tdx_2_1p40dekel26tp2a2srma4sc3lj2ukr6y8k4amr7x8yav86lyyeg7ta7"), + pools: NameIndexedResourceInformation { + bitcoin: component_address!("component_tdx_2_1czt59vxdqg7q4l0gzphmt5ev6lagl2cu6sm2hsaz9y8ypcf0aukf8r"), + ethereum: component_address!("component_tdx_2_1crqpgnpf3smh7kg8d4sz4h3502l65s4tslwhg46ru07ra6l30pcsj4"), + usdc: component_address!("component_tdx_2_1cpwkf9uhel3ut4ydm58g0uyaw7sxckmp2pz7sdv79vzt9y3p7ad4fu"), + usdt: component_address!("component_tdx_2_1czmdhtq0u8f40khky4c6j74msskuz60yq3y0zewu85phrdj0ryz2hl") + } + }, + }; + // TODO: Numbers here are not real and I have added from just to get + // things going. MUST modify before launch. + let reward_information = indexmap! { + LockupPeriod::from_months(9).unwrap() => dec!(0.125), // 12.5% + LockupPeriod::from_months(10).unwrap() => dec!(0.15), // 15.0% + LockupPeriod::from_months(11).unwrap() => dec!(0.175), // 17.5% + LockupPeriod::from_months(12).unwrap() => dec!(0.20), // 20.0% + }; + + // TODO: MUST determine what those accounts are prior to launch! + // For now they are MY stokenet accounts! + let protocol_manager_account = component_address!("account_tdx_2_12xxuglkrdgcphpqk34fv59ewq3gu5uwlzs42hpy0grsrefvgwgxrev"); + let protocol_owner_account = component_address!("account_tdx_2_12xxuglkrdgcphpqk34fv59ewq3gu5uwlzs42hpy0grsrefvgwgxrev"); + + /* cSpell:enable */ + + // An ephemeral private key that we will use the bootstrapping process. + // This key will initially control the dApp definition to allow us to + // easily update the metadata and will later on change the owner role + // of the dApp definition to the protocol owner. + let ephemeral_private_key = PrivateKey::Ed25519( + Ed25519PrivateKey::from_u64(rand::random()).unwrap(), + ); + let ephemeral_virtual_signature_badge = + NonFungibleGlobalId::from_public_key( + &ephemeral_private_key.public_key(), + ); + + // This is the transaction service that the submission will happen + // through. It does most of the heavy lifting associated with the + // transaction submission. + let transaction_service = + TransactionService::new(&bech32m_coders, GATEWAY_API_BASE_URL); + + // Creating the dApp definition account. When this account starts it + // its owner will be a virtual signature badge which will change once + // add all of the metadata fields that we want to add. The the manifest + // that involves the dApp definition will set the metadata on it and + // will also change its owner to be the protocol Owner badge. + let dapp_definition_account = { + let manifest = ManifestBuilder::new() + .call_function( + ACCOUNT_PACKAGE, + ACCOUNT_BLUEPRINT, + ACCOUNT_CREATE_ADVANCED_IDENT, + AccountCreateAdvancedManifestInput { + owner_role: OwnerRole::Updatable(rule!(require( + ephemeral_virtual_signature_badge + ))), + address_reservation: None, + }, + ) + .build(); + std::thread::sleep(std::time::Duration::from_secs(5)); + *transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_component_addresses + .first() + .expect("Must succeed!") + }; + + // Creating the protocol owner and the protocol manager badges and + // sending them off to the accounts specified up above. + let (protocol_manager_badge, protocol_owner_badge) = { + let manifest = ManifestBuilder::new() + // The protocol manager badge + .create_fungible_resource( + OwnerRole::None, + true, + 0, + Default::default(), + // TODO: What do we want those to be? Any preference? + metadata! { + init { + "name" => "Ignition Protocol Manager", updatable; + "symbol" => "IGNPM", updatable; + "description" => "A badge that gives the authority to manage the Ignition protocol.", updatable; + "badge" => vec!["badge"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + } + }, + Some(dec!(1)), + ) + .try_deposit_entire_worktop_or_abort(protocol_manager_account, None) + // The protocol owner badge + .create_fungible_resource( + OwnerRole::None, + true, + 0, + Default::default(), + metadata! { + init { + "name" => "Ignition Protocol Owner", updatable; + "symbol" => "IGNPO", updatable; + "description" => "A badge that of the owner of the ignition protocol.", updatable; + "badge" => vec!["badge"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + } + }, + Some(dec!(1)), + ) + .try_deposit_entire_worktop_or_abort(protocol_owner_account, None) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let resource_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_resource_addresses; + ( + *resource_addresses.first().unwrap(), + *resource_addresses.get(1).unwrap(), + ) + }; + + let protocol_manager_rule = rule!(require(protocol_manager_badge)); + let protocol_owner_rule = rule!(require(protocol_owner_badge)); + let owner_role = OwnerRole::Fixed(protocol_owner_rule.clone()); + + // Publishing the packages. + let ( + ignition_package_address, + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) = { + let (ignition_code, ignition_package_definition) = + PackageLoader::get("ignition"); + let (simple_oracle_code, simple_oracle_package_definition) = + PackageLoader::get("simple-oracle"); + let ( + ociswap_v1_adapter_v1_code, + ociswap_v1_adapter_v1_package_definition, + ) = PackageLoader::get("ociswap-v1-adapter-v1"); + let ( + caviarnine_v1_adapter_v1_code, + caviarnine_v1_adapter_v1_package_definition, + ) = PackageLoader::get("caviarnine-v1-adapter-v1"); + + // We can publish the simple oracle, ociswap adapter v1, and + // caviarnine adapter v1 all in a single transaction since they + // are below the size limit. + let manifest = ManifestBuilder::new() + .publish_package_advanced( + None, + simple_oracle_code, + simple_oracle_package_definition, + metadata_init! { + "name" => "Simple Oracle Package", updatable; + "description" => "The implementation of the Oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .publish_package_advanced( + None, + ociswap_v1_adapter_v1_code, + ociswap_v1_adapter_v1_package_definition, + metadata_init! { + "name" => "Ociswap Adapter v1 Package", updatable; + "description" => "The implementation of an adapter for Ociswap for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .publish_package_advanced( + None, + caviarnine_v1_adapter_v1_code, + caviarnine_v1_adapter_v1_package_definition, + metadata_init! { + "name" => "Caviarnine Adapter v1 Package", updatable; + "description" => "The implementation of an adapter for Caviarnine for the Ignition protocol.", updatable; + "tags" => vec!["adapter"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ).build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let package_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_package_addresses; + + let ( + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) = ( + *package_addresses.first().unwrap(), + *package_addresses.get(1).unwrap(), + *package_addresses.get(2).unwrap(), + ); + + // Publishing the Ignition package + let manifest = ManifestBuilder::new() + .publish_package_advanced( + None, + ignition_code, + ignition_package_definition, + metadata_init! { + "name" => "Ignition Package", updatable; + "description" => "The implementation of the Ignition protocol.", updatable; + "tags" => Vec::::new(), updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + ) + .build(); + std::thread::sleep(std::time::Duration::from_secs(5)); + let ignition_package_address = *transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_package_addresses + .first() + .unwrap(); + + ( + ignition_package_address, + simple_oracle_package_address, + ociswap_v1_adapter_v1_package_address, + caviarnine_v1_adapter_v1_package_address, + ) + }; + + // Creating the different liquidity receipt resources that the different + // exchanges will use. They will be mintable and burnable through the + // Ignition package caller badge. + let ignition_package_global_caller_rule = + rule!(require(package_of_direct_caller(ignition_package_address))); + let ( + ociswap_v1_liquidity_receipt_resource, + caviarnine_v1_liquidity_receipt_resource, + ) = { + let roles = NonFungibleResourceRoles { + // Mintable and burnable by the Ignition package and + // the protocol owner can update who can do that. + mint_roles: mint_roles! { + minter => ignition_package_global_caller_rule.clone(); + minter_updater => protocol_owner_rule.clone(); + }, + burn_roles: burn_roles! { + burner => ignition_package_global_caller_rule.clone(); + burner_updater => protocol_owner_rule.clone(); + }, + // We reserve the right to change the data of the + // liquidity receipts when we want. + non_fungible_data_update_roles: non_fungible_data_update_roles! { + non_fungible_data_updater => rule!(deny_all); + non_fungible_data_updater_updater => protocol_owner_rule.clone(); + }, + // Everything else is deny all and can't be changed. + recall_roles: recall_roles! { + recaller => rule!(deny_all); + recaller_updater => rule!(deny_all); + }, + freeze_roles: freeze_roles! { + freezer => rule!(deny_all); + freezer_updater => rule!(deny_all); + }, + deposit_roles: deposit_roles! { + depositor => rule!(allow_all); + depositor_updater => rule!(deny_all); + }, + withdraw_roles: withdraw_roles! { + withdrawer => rule!(allow_all); + withdrawer_updater => rule!(deny_all); + }, + }; + + let manifest = ManifestBuilder::new() + // Ociswap liquidity receipt + .call_function( + RESOURCE_PACKAGE, + NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, + NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT, + NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput { + owner_role: owner_role.clone(), + track_total_supply: true, + non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::>(), + entries: Vec::new(), + resource_roles: roles.clone(), + metadata: metadata! { + roles { + metadata_setter => protocol_owner_rule.clone(); + metadata_setter_updater => protocol_owner_rule.clone(); + metadata_locker => protocol_owner_rule.clone(); + metadata_locker_updater => protocol_owner_rule.clone(); + }, + init { + // TODO: Confirm with the exchanges what they want + // their name to be. + "name" => "Ignition LP: Ociswap", updatable; + "description" => "Represents a particular contribution of liquidity to Ociswap through the Ignition liquidity incentives program. See the redeem_url metadata for where to redeem these NFTs.", updatable; + "tags" => vec!["lp token"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + // TODO: Must get this from our design team + "icon_url" => UncheckedUrl::of("https://www.google.com"), updatable; + "DEX" => "Ociswap", updatable; + // TODO: Must get this from Ociswap! + "redeem_url" => UncheckedUrl::of("https://www.google.com"), updatable; + } + }, + address_reservation: None + } + ) + // Caviarnine liquidity receipt + .call_function( + RESOURCE_PACKAGE, + NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, + NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT, + NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput { + owner_role: owner_role.clone(), + track_total_supply: true, + non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::>(), + entries: Vec::new(), + resource_roles: roles.clone(), + metadata: metadata! { + roles { + metadata_setter => protocol_owner_rule.clone(); + metadata_setter_updater => protocol_owner_rule.clone(); + metadata_locker => protocol_owner_rule.clone(); + metadata_locker_updater => protocol_owner_rule.clone(); + }, + init { + // TODO: Confirm with the exchanges what they want + // their name to be. + "name" => "Ignition LP: Caviarnine", updatable; + "description" => "Represents a particular contribution of liquidity to Caviarnine through the Ignition liquidity incentives program. See the redeem_url metadata for where to redeem these NFTs.", updatable; + "tags" => vec!["lp token"], updatable; + "dapp_definitions" => vec![dapp_definition_account], updatable; + // TODO: Must get this from our design team + "icon_url" => UncheckedUrl::of("https://www.google.com"), updatable; + "DEX" => "Caviarnine", updatable; + // TODO: Must get this from Caviarnine! + "redeem_url" => UncheckedUrl::of("https://www.google.com"), updatable; + } + }, + address_reservation: None + } + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let resource_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_resource_addresses; + ( + *resource_addresses.first().unwrap(), + *resource_addresses.get(1).unwrap(), + ) + }; + + // Creating the oracle and adapters. + let ( + ignition_component, + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) = { + let manifest = ManifestBuilder::new() + // Creating the oracle component + .call_function( + simple_oracle_package_address, + "SimpleOracle", + "instantiate", + ( + protocol_manager_rule.clone(), + metadata_init! { + "name" => "Ignition Oracle", updatable; + "description" => "The oracle used by the Ignition protocol.", updatable; + "tags" => vec!["oracle"], updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + // Creating the ociswap adapter v1 component + .call_function( + ociswap_v1_adapter_v1_package_address, + "OciswapV1Adapter", + "instantiate", + ( + metadata_init! { + "name" => "Ignition Ociswap Adapter", updatable; + "description" => "The adapter used by the Ignition protocol to communicate with Ociswap pools.", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + // Creating the ociswap adapter v1 component + .call_function( + caviarnine_v1_adapter_v1_package_address, + "CaviarnineV1Adapter", + "instantiate", + ( + metadata_init! { + "name" => "Ignition Caviarnine Adapter", updatable; + "description" => "The adapter used by the Ignition protocol to communicate with Caviarnine pools.", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + None::, + ), + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let component_addresses = transaction_service + .submit_manifest(manifest, ¬ary_private_key, &fee_handling)? + .new_component_addresses; + + let ( + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) = ( + *component_addresses.first().unwrap(), + *component_addresses.get(1).unwrap(), + *component_addresses.get(2).unwrap(), + ); + + // Instantiating the Ignition component + let manifest = ManifestBuilder::new() + // Instantiate Ignition. + .call_function( + ignition_package_address, + "Ignition", + "instantiate", + manifest_args!( + metadata_init! { + "name" => "Ignition", updatable; + "description" => "The Ignition protocol component", updatable; + "dapp_definition" => dapp_definition_account, updatable; + }, + owner_role.clone(), + protocol_owner_rule.clone(), + protocol_manager_rule.clone(), + protocol_resource, + simple_oracle_component, + MAXIMUM_ALLOWED_PRICE_STALENESS_IN_SECONDS, + MAXIMUM_ALLOWED_PRICE_DIFFERENCE_PERCENTAGE, + InitializationParametersManifest { + initial_pool_information: Some(indexmap! { + BlueprintId { + package_address: exchanges.caviarnine_v1.package, + blueprint_name: "QuantaSwap".to_owned() + } => PoolBlueprintInformation { + adapter: caviarnine_v1_adapter_v1_component, + allowed_pools: exchanges.caviarnine_v1.pools.into_iter().collect(), + liquidity_receipt: caviarnine_v1_liquidity_receipt_resource + }, + BlueprintId { + package_address: exchanges.ociswap_v1.package, + blueprint_name: "BasicPool".to_owned() + } => PoolBlueprintInformation { + adapter: ociswap_v1_adapter_v1_component, + // TODO: Fix this when we have actual + // ociswap pools. + allowed_pools: Default::default(), + // allowed_pools: exchanges.ociswap.pools.into_iter().collect(), + liquidity_receipt: ociswap_v1_liquidity_receipt_resource + } + }), + initial_user_resource_volatility: Some( + indexmap! { + resources.bitcoin => Volatility::Volatile, + resources.ethereum => Volatility::Volatile, + resources.usdc => Volatility::NonVolatile, + resources.usdt => Volatility::NonVolatile, + } + ), + initial_reward_rates: Some(reward_information), + initial_volatile_protocol_resources: None, + initial_non_volatile_protocol_resources: None, + initial_is_open_position_enabled: Some(true), + initial_is_close_position_enabled: Some(true), + }, + None:: + ) + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + let component_addresses = transaction_service + .submit_manifest( + manifest, + &ephemeral_private_key, + &fee_handling, + )? + .new_component_addresses; + + let ignition_component_address = + *component_addresses.first().unwrap(); + + ( + ignition_component_address, + simple_oracle_component, + ociswap_v1_adapter_v1_component, + caviarnine_v1_adapter_v1_component, + ) + }; + + // Updating the dapp definition account with the metadata that it + // should have. + { + let manifest = ManifestBuilder::new() + .set_metadata( + dapp_definition_account, + "account_type", + "dapp definition", + ) + .set_metadata( + dapp_definition_account, + "claimed_websites", + Vec::::new(), + ) + .set_metadata( + dapp_definition_account, + "dapp_definitions", + Vec::::new(), + ) + .set_metadata( + dapp_definition_account, + "claimed_entities", + vec![ + GlobalAddress::from(protocol_manager_badge), + GlobalAddress::from(protocol_owner_badge), + GlobalAddress::from(ignition_package_address), + GlobalAddress::from(simple_oracle_package_address), + GlobalAddress::from( + ociswap_v1_adapter_v1_package_address, + ), + GlobalAddress::from( + caviarnine_v1_adapter_v1_package_address, + ), + GlobalAddress::from( + ociswap_v1_liquidity_receipt_resource, + ), + GlobalAddress::from( + caviarnine_v1_liquidity_receipt_resource, + ), + GlobalAddress::from(ignition_component), + GlobalAddress::from(simple_oracle_component), + GlobalAddress::from(ociswap_v1_adapter_v1_component), + GlobalAddress::from(caviarnine_v1_adapter_v1_component), + ], + ) + .call_role_assignment_method( + dapp_definition_account, + ROLE_ASSIGNMENT_SET_OWNER_IDENT, + RoleAssignmentSetOwnerInput { + rule: protocol_owner_rule, + }, + ) + .build(); + + std::thread::sleep(std::time::Duration::from_secs(5)); + transaction_service.submit_manifest( + manifest, + &ephemeral_private_key, + &fee_handling, + )?; + } + + Ok(()) + } +} + +pub struct DexInformation { + pub pools: NameIndexedResourceInformation, + pub package: PackageAddress, +} diff --git a/tools/bootstrap/src/transaction_service.rs b/tools/bootstrap/src/transaction_service.rs new file mode 100644 index 00000000..eecae6ee --- /dev/null +++ b/tools/bootstrap/src/transaction_service.rs @@ -0,0 +1,386 @@ +use crate::error::*; +use gateway_client::apis::configuration::*; +use gateway_client::apis::status_api::*; +use gateway_client::apis::transaction_api::*; +use gateway_client::models::*; +use radix_engine::transaction::*; +use radix_engine_interface::blueprints::account::*; +use radix_engine_interface::prelude::*; +use std::thread::*; +use std::time::*; +use transaction::manifest::*; +use transaction::prelude::*; + +type NativePublicKey = radix_engine_interface::crypto::PublicKey; +type GatewayPublicKey = gateway_client::models::PublicKey; + +/// A transaction service that provides a higher-level abstraction over the +/// gateway API. +pub struct TransactionService<'a> { + /// The Bech32m encoders and decoders that the transaction service uses. + bech32m_coders: &'a Bech32mCoders<'a>, + + /// The base url of the gateway API. + gateway_api_base_url: String, + + /// Controls how often the transaction service should poll for the + /// transaction status. This defaults to 5 seconds which is 5,000 + /// milliseconds. + polling_frequency_in_milliseconds: u64, + + /// Controls how many polling attempts the transaction service should make + /// before considering that to be an error. This defaults to 12 attempts. + maximum_number_of_polling_attempts: u64, +} + +impl<'a> TransactionService<'a> { + pub fn new( + bech32m_coders: &'a Bech32mCoders, + gateway_api_base_url: impl Into, + ) -> Self { + Self::new_configurable(bech32m_coders, gateway_api_base_url, 5_000, 12) + } + + pub fn new_configurable( + bech32m_coders: &'a Bech32mCoders, + gateway_api_base_url: impl Into, + polling_frequency_in_milliseconds: u64, + maximum_number_of_polling_attempts: u64, + ) -> Self { + Self { + bech32m_coders, + gateway_api_base_url: gateway_api_base_url.into(), + polling_frequency_in_milliseconds, + maximum_number_of_polling_attempts, + } + } + + pub fn submit_manifest( + &self, + mut manifest: TransactionManifestV1, + notary_private_key: &PrivateKey, + fee_handling: &FeeHandling<'_>, + ) -> std::result::Result { + // Generating the nonce that will be used in submitting the transaction. + let nonce = rand::random::(); + + // Getting the epoch bounds of this transaction + let current_epoch = self.current_epoch()?; + let max_epoch = current_epoch.after(10).unwrap(); + + let additional_signatures = if let FeeHandling::EstimateAndLock { + fee_payer_private_key, + .. + } = fee_handling + { + let is_additional_fee_payer_signature_required = + match (notary_private_key, fee_payer_private_key) { + ( + PrivateKey::Secp256k1(notary), + PrivateKey::Secp256k1(fee_payer), + ) => notary.to_bytes() != fee_payer.to_bytes(), + ( + PrivateKey::Ed25519(notary), + PrivateKey::Ed25519(fee_payer), + ) => notary.to_bytes() != fee_payer.to_bytes(), + (PrivateKey::Secp256k1(..), PrivateKey::Ed25519(..)) + | (PrivateKey::Ed25519(..), PrivateKey::Secp256k1(..)) => { + true + } + }; + + if is_additional_fee_payer_signature_required { + vec![fee_payer_private_key] + } else { + vec![] + } + } else { + vec![] + }; + + // If we need to estimate the fees then we must get a preview of the + // manifest to estimate how much the fees will be. + if let FeeHandling::EstimateAndLock { + fee_payer_account, + fee_payer_private_key, + } = fee_handling + { + let decompiled_manifest = decompile( + &manifest.instructions, + self.bech32m_coders.network_definition, + )?; + + let fees = { + // Getting a preview of the manifest. + let preview_response = transaction_preview( + &self.gateway_config(), + TransactionPreviewRequest { + manifest: decompiled_manifest.clone(), + blobs_hex: Some( + manifest.blobs.values().map(hex::encode).collect(), + ), + start_epoch_inclusive: current_epoch.number() as i64, + end_epoch_exclusive: max_epoch.number() as i64, + notary_public_key: match notary_private_key.public_key() + { + NativePublicKey::Secp256k1(pk) => Some(Box::new( + GatewayPublicKey::EcdsaSecp256k1 { key: pk.0 }, + )), + NativePublicKey::Ed25519(pk) => { + Some(Box::new(GatewayPublicKey::EddsaEd25519 { + key: pk.0, + })) + } + }, + notary_is_signatory: Some(true), + tip_percentage: 0, + nonce: nonce as i64, + signer_public_keys: vec![match fee_payer_private_key { + PrivateKey::Secp256k1(pk) => { + GatewayPublicKey::EcdsaSecp256k1 { + key: pk.public_key().0, + } + } + PrivateKey::Ed25519(pk) => { + GatewayPublicKey::EddsaEd25519 { + key: pk.public_key().0, + } + } + }], + flags: Box::new(TransactionPreviewRequestFlags { + use_free_credit: true, + assume_all_signature_proofs: true, + skip_epoch_check: false, + }), + }, + )?; + + // Ensure that the transaction succeeded in preview. Getting the + // fees of a transaction that failed or was rejected has no + // point. + let receipt = scrypto_decode::( + &preview_response.encoded_receipt, + ) + .unwrap() + .into_latest(); + + if !receipt.is_commit_success() { + return Err(Error::PreviewFailed { + manifest: decompiled_manifest, + receipt, + }); + } + + receipt.fee_summary.total_execution_cost_in_xrd + + receipt.fee_summary.total_finalization_cost_in_xrd + + receipt.fee_summary.total_tipping_cost_in_xrd + + receipt.fee_summary.total_storage_cost_in_xrd + + receipt.fee_summary.total_royalty_cost_in_xrd + }; + + // Adding a 50% padding over the fees that were calculated. + let fees_to_lock = fees * dec!(1.5); + + // Adding the instruction to lock fees. + manifest.instructions.insert( + 0, + InstructionV1::CallMethod { + address: (*fee_payer_account).into(), + method_name: ACCOUNT_LOCK_FEE_IDENT.to_owned(), + args: manifest_args!(fees_to_lock).into(), + }, + ); + }; + + // Constructing the transaction and submitting it. + let mut builder = TransactionBuilder::new().manifest(manifest).header( + TransactionHeaderV1 { + network_id: self.bech32m_coders.network_definition.id, + start_epoch_inclusive: current_epoch, + end_epoch_exclusive: max_epoch, + nonce, + notary_public_key: notary_private_key.public_key(), + notary_is_signatory: true, + tip_percentage: 0, + }, + ); + for key in additional_signatures { + builder = builder.sign(*key); + } + let notarized_transaction = + builder.notarize(notary_private_key).build(); + + // Compiling the notarized transaction and submitting it to the gateway. + let compiled_notarized_transaction = + notarized_transaction.to_payload_bytes().unwrap(); + transaction_submit( + &self.gateway_config(), + TransactionSubmitRequest { + notarized_transaction: compiled_notarized_transaction, + }, + )?; + + // Getting the intent hash and starting to poll for the transaction. + let intent_hash = + notarized_transaction.prepare().unwrap().intent_hash(); + let bech32m_intent_hash = self + .bech32m_coders + .transaction_hash_encoder + .encode(&intent_hash) + .unwrap(); + println!("{bech32m_intent_hash}"); + + for _ in 0..self.maximum_number_of_polling_attempts { + match transaction_status( + &self.gateway_config(), + TransactionStatusRequest { + intent_hash: bech32m_intent_hash.clone(), + }, + ) { + Ok(TransactionStatusResponse { + status: TransactionStatus::CommittedSuccess, + .. + }) => { + // The transaction has been committed successfully. We can + // now get the transaction committed details with no issues. + let committed_details = transaction_committed_details( + &self.gateway_config(), + TransactionCommittedDetailsRequest { + intent_hash: bech32m_intent_hash.clone(), + opt_ins: Some(Box::new(TransactionDetailsOptIns { + raw_hex: Some(true), + receipt_state_changes: Some(true), + receipt_fee_summary: Some(true), + receipt_fee_source: Some(true), + receipt_fee_destination: Some(true), + receipt_costing_parameters: Some(true), + receipt_events: Some(true), + receipt_output: Some(true), + affected_global_entities: Some(true), + balance_changes: Some(true), + })), + at_ledger_state: None, + }, + )?; + + let state_updates = committed_details + .transaction + .receipt + .unwrap() + .state_updates + .unwrap(); + + let mut simplified_receipt = SimplifiedTransactionReceipt { + new_component_addresses: Default::default(), + new_resource_addresses: Default::default(), + new_package_addresses: Default::default(), + }; + + for entity in state_updates.new_global_entities { + let address_string = entity.entity_address; + + if let Some(address) = PackageAddress::try_from_bech32( + &self.bech32m_coders.address_decoder, + &address_string, + ) { + simplified_receipt + .new_package_addresses + .push(address) + } else if let Some(address) = + ResourceAddress::try_from_bech32( + &self.bech32m_coders.address_decoder, + &address_string, + ) + { + simplified_receipt + .new_resource_addresses + .push(address) + } else if let Some(address) = + ComponentAddress::try_from_bech32( + &self.bech32m_coders.address_decoder, + &address_string, + ) + { + simplified_receipt + .new_component_addresses + .push(address) + } + } + + return Ok(simplified_receipt); + } + Ok(TransactionStatusResponse { + status: + TransactionStatus::CommittedFailure + | TransactionStatus::Rejected, + .. + }) => { + return Err(Error::TransactionWasNotSuccessful { + intent_hash: bech32m_intent_hash, + }) + } + _ => {} + } + sleep(Duration::from_millis( + self.polling_frequency_in_milliseconds, + )); + } + + Err(Error::TransactionPollingYieldedNothing { + intent_hash: bech32m_intent_hash, + }) + } + + fn gateway_config(&self) -> Configuration { + Configuration { + base_path: self.gateway_api_base_url.clone(), + ..Default::default() + } + } + + fn current_epoch(&self) -> std::result::Result { + Ok(Epoch::of( + gateway_status(&self.gateway_config())?.ledger_state.epoch as u64, + )) + } +} + +pub struct SimplifiedTransactionReceipt { + pub new_component_addresses: Vec, + pub new_resource_addresses: Vec, + pub new_package_addresses: Vec, +} + +pub enum FeeHandling<'a> { + AlreadyHandled, + EstimateAndLock { + fee_payer_account: ComponentAddress, + fee_payer_private_key: &'a PrivateKey, + }, +} + +pub struct Bech32mCoders<'a> { + pub network_definition: &'a NetworkDefinition, + pub address_encoder: AddressBech32Encoder, + pub address_decoder: AddressBech32Decoder, + pub transaction_hash_encoder: TransactionHashBech32Encoder, + pub transaction_hash_decoder: TransactionHashBech32Decoder, +} + +impl<'a> Bech32mCoders<'a> { + pub fn from_network_definition( + network_definition: &'a NetworkDefinition, + ) -> Self { + Self { + network_definition, + address_encoder: AddressBech32Encoder::new(network_definition), + address_decoder: AddressBech32Decoder::new(network_definition), + transaction_hash_encoder: TransactionHashBech32Encoder::new( + network_definition, + ), + transaction_hash_decoder: TransactionHashBech32Decoder::new( + network_definition, + ), + } + } +} diff --git a/tools/bootstrap/src/types/mod.rs b/tools/bootstrap/src/types/mod.rs new file mode 100644 index 00000000..e36e386e --- /dev/null +++ b/tools/bootstrap/src/types/mod.rs @@ -0,0 +1,5 @@ +mod name_indexed_dex_information; +mod name_indexed_resource_information; + +pub use name_indexed_dex_information::*; +pub use name_indexed_resource_information::*; diff --git a/tools/bootstrap/src/types/name_indexed_dex_information.rs b/tools/bootstrap/src/types/name_indexed_dex_information.rs new file mode 100644 index 00000000..91302a39 --- /dev/null +++ b/tools/bootstrap/src/types/name_indexed_dex_information.rs @@ -0,0 +1,30 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct NameIndexedDexInformation { + pub ociswap_v1: T, + pub caviarnine_v1: T, +} + +impl NameIndexedDexInformation { + pub fn map(&self, mut map: F) -> NameIndexedDexInformation + where + F: FnMut(&T) -> O, + { + NameIndexedDexInformation:: { + ociswap_v1: map(&self.ociswap_v1), + caviarnine_v1: map(&self.caviarnine_v1), + } + } + + pub fn try_map( + &self, + mut map: F, + ) -> Result, E> + where + F: FnMut(&T) -> Result, + { + Ok(NameIndexedDexInformation:: { + ociswap_v1: map(&self.ociswap_v1)?, + caviarnine_v1: map(&self.caviarnine_v1)?, + }) + } +} diff --git a/tools/bootstrap/src/types/name_indexed_resource_information.rs b/tools/bootstrap/src/types/name_indexed_resource_information.rs new file mode 100644 index 00000000..fc5ad2f7 --- /dev/null +++ b/tools/bootstrap/src/types/name_indexed_resource_information.rs @@ -0,0 +1,45 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct NameIndexedResourceInformation { + pub bitcoin: T, + pub ethereum: T, + pub usdc: T, + pub usdt: T, +} + +impl NameIndexedResourceInformation { + pub fn map(&self, mut map: F) -> NameIndexedResourceInformation + where + F: FnMut(&T) -> O, + { + NameIndexedResourceInformation:: { + bitcoin: map(&self.bitcoin), + ethereum: map(&self.ethereum), + usdc: map(&self.usdc), + usdt: map(&self.usdt), + } + } + + pub fn try_map( + &self, + mut map: F, + ) -> Result, E> + where + F: FnMut(&T) -> Result, + { + Ok(NameIndexedResourceInformation:: { + bitcoin: map(&self.bitcoin)?, + ethereum: map(&self.ethereum)?, + usdc: map(&self.usdc)?, + usdt: map(&self.usdt)?, + }) + } +} + +impl std::iter::IntoIterator for NameIndexedResourceInformation { + type Item = T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + vec![self.bitcoin, self.ethereum, self.usdc, self.usdt].into_iter() + } +}