From 0c34adc2d03329813aff85d3a92b493a1566c9a9 Mon Sep 17 00:00:00 2001 From: Aramik Date: Thu, 21 Nov 2024 11:03:31 -0800 Subject: [PATCH 1/3] init: static schemas package (#2225) # Goal The goal of this PR is create a new js package for schema name and ID mappings Closes #2176 # Discussion - This only generates data for `dsnp` schemas from chain. The issue is that currently there is no easy way to get all schema names without providing namespaces. We can get all using raw state but then we would need to scale decode it. --------- Co-authored-by: Joe Caputo --- .github/workflows/release.yml | 71 + .github/workflows/verify-pr-commit.yml | 38 + js/schemas/.gitignore | 312 +++ js/schemas/.mocharc.json | 5 + js/schemas/.node-version | 1 + js/schemas/.prettierignore | 10 + js/schemas/.prettierrc.json | 8 + js/schemas/.tool-versions | 1 + js/schemas/CONTRIBUTING.md | 12 + js/schemas/README.md | 89 + js/schemas/data.ts | 224 ++ js/schemas/eslint.config.mjs | 68 + js/schemas/index.ts | 6 + js/schemas/package-lock.json | 3490 ++++++++++++++++++++++++ js/schemas/package.json | 39 + js/schemas/schemas.ts | 47 + js/schemas/scripts/fetchSchemaData.mjs | 135 + js/schemas/scripts/package.cjs | 59 + js/schemas/scripts/package.json | 13 + js/schemas/test/schemas.test.ts | 55 + js/schemas/tsconfig.cjs.json | 9 + js/schemas/tsconfig.eslint.json | 4 + js/schemas/tsconfig.esm.json | 9 + js/schemas/tsconfig.json | 19 + js/schemas/tsconfig.types.json | 10 + 25 files changed, 4734 insertions(+) create mode 100644 js/schemas/.gitignore create mode 100644 js/schemas/.mocharc.json create mode 100644 js/schemas/.node-version create mode 100644 js/schemas/.prettierignore create mode 100644 js/schemas/.prettierrc.json create mode 100644 js/schemas/.tool-versions create mode 100644 js/schemas/CONTRIBUTING.md create mode 100644 js/schemas/README.md create mode 100644 js/schemas/data.ts create mode 100644 js/schemas/eslint.config.mjs create mode 100644 js/schemas/index.ts create mode 100644 js/schemas/package-lock.json create mode 100644 js/schemas/package.json create mode 100644 js/schemas/schemas.ts create mode 100644 js/schemas/scripts/fetchSchemaData.mjs create mode 100644 js/schemas/scripts/package.cjs create mode 100644 js/schemas/scripts/package.json create mode 100644 js/schemas/test/schemas.test.ts create mode 100644 js/schemas/tsconfig.cjs.json create mode 100644 js/schemas/tsconfig.eslint.json create mode 100644 js/schemas/tsconfig.esm.json create mode 100644 js/schemas/tsconfig.json create mode 100644 js/schemas/tsconfig.types.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ccda76043..f5a11021ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -420,6 +420,35 @@ jobs: path: js/api-augment/dist if-no-files-found: error + build-js-schemas: + name: Build JS Schemas + runs-on: ubuntu-22.04 + container: ghcr.io/frequency-chain/frequency/ci-base-image:1.3.1 + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + with: + ref: ${{env.RELEASE_BRANCH_NAME}} + - name: Set up NodeJs + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + registry-url: "https://registry.npmjs.org" + cache-dependency-path: js/schemas/package-lock.json + - name: Install + run: npm install + working-directory: js/schemas + - name: Build + run: npm run build + working-directory: js/schemas + - name: Upload Dist Dir + uses: actions/upload-artifact@v4 + with: + name: js-schemas-${{github.run_id}} + path: js/schemas/dist + if-no-files-found: error + test-version-matches-release: needs: build-binaries name: Test Version Matches Release @@ -619,6 +648,7 @@ jobs: test-version-matches-release, build-rust-developer-docs, build-js-api-augment, + build-js-schemas, ] name: Wait for All Builds to Finish runs-on: ubuntu-22.04 @@ -1051,3 +1081,44 @@ jobs: working-directory: ./js/api-augment/dist env: NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} + + release-js-schemas: + needs: wait-for-all-builds + name: Release JS Schemas + runs-on: ubuntu-22.04 + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + with: + ref: ${{env.RELEASE_BRANCH_NAME}} + - name: Set up NodeJs + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + registry-url: "https://registry.npmjs.org" + cache-dependency-path: js/schemas/package-lock.json + - name: Download Dist Dir + id: download + uses: actions/download-artifact@v4 + with: + name: js-schemas-${{github.run_id}} + path: js/schemas/dist + - name: Version Package + if: env.TEST_RUN != 'true' + run: npm version --new-version "${{env.NEW_RELEASE_TAG}}" --no-git-tag-version + working-directory: js/schemas/dist + - name: Release on NPM @latest + if: env.TEST_RUN != 'true' && + steps.is-full-release.outputs.is-full-release == 'true' + run: npm publish --tag latest --access public + working-directory: ./js/schemas/dist + env: + NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} + - name: Release Candidate on NPM + if: env.TEST_RUN != 'true' && + steps.is-full-release.outputs.is-full-release != 'true' + run: npm publish --tag next --access public + working-directory: ./js/schemas/dist + env: + NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} diff --git a/.github/workflows/verify-pr-commit.yml b/.github/workflows/verify-pr-commit.yml index 7c9932dde0..30366d00cc 100644 --- a/.github/workflows/verify-pr-commit.yml +++ b/.github/workflows/verify-pr-commit.yml @@ -453,6 +453,44 @@ jobs: path: js/api-augment/dist/frequency-chain-api-augment-0.0.0.tgz if-no-files-found: error + verify-js-schemas: + name: Verify JS Schemas + runs-on: ubuntu-22.04 + container: ghcr.io/frequency-chain/frequency/ci-base-image:1.3.1 + steps: + - name: Check Out Repo + uses: actions/checkout@v4 + - name: Set up NodeJs + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + cache-dependency-path: js/schemas/package-lock.json + - name: Install Latest Versions + run: npm install + working-directory: js/schemas + - name: Lint + run: npm run lint + working-directory: js/schemas + - name: Test + run: npm test + working-directory: js/schemas + - name: Build + run: npm run build + working-directory: js/schemas + - name: Publish Dry Run + run: npm publish --dry-run + working-directory: js/schemas/dist + - name: Generate npm tarball + run: npm pack + working-directory: js/schemas/dist + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: artifacts-schemas-${{github.run_id}} + path: js/schemas/dist/frequency-chain-schemas-0.0.0.tgz + if-no-files-found: error + verify-node-docker-images: needs: build-binaries name: Verify Node Docker Images diff --git a/js/schemas/.gitignore b/js/schemas/.gitignore new file mode 100644 index 0000000000..d1db1b8a78 --- /dev/null +++ b/js/schemas/.gitignore @@ -0,0 +1,312 @@ +# Generated Files +metadata.* +interfaces/* + + +# Log Files +*.log + +# All of IDEA +.idea/* + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive +ltximg/** + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env*.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### vscode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# End of https://www.toptal.com/developers/gitignore/api/intellij+all,vim,emacs,vscode,git,node + +junit.xml diff --git a/js/schemas/.mocharc.json b/js/schemas/.mocharc.json new file mode 100644 index 0000000000..53ebf896a5 --- /dev/null +++ b/js/schemas/.mocharc.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/mocharc", + "extension": ["ts"], + "spec": ["test"] +} diff --git a/js/schemas/.node-version b/js/schemas/.node-version new file mode 100644 index 0000000000..87834047a6 --- /dev/null +++ b/js/schemas/.node-version @@ -0,0 +1 @@ +20.12.2 diff --git a/js/schemas/.prettierignore b/js/schemas/.prettierignore new file mode 100644 index 0000000000..2cf62f2962 --- /dev/null +++ b/js/schemas/.prettierignore @@ -0,0 +1,10 @@ +# package.json is formatted by package managers, so we ignore it here +package.json +build/* +coverage/* +multimodules/* +/*.d.ts +/*.map +/*.js +*.md +eslint.config.mjs diff --git a/js/schemas/.prettierrc.json b/js/schemas/.prettierrc.json new file mode 100644 index 0000000000..cd87a91cb1 --- /dev/null +++ b/js/schemas/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "useTabs": false, + "printWidth": 120 +} diff --git a/js/schemas/.tool-versions b/js/schemas/.tool-versions new file mode 100644 index 0000000000..958fb36989 --- /dev/null +++ b/js/schemas/.tool-versions @@ -0,0 +1 @@ +nodejs 20.12.2 diff --git a/js/schemas/CONTRIBUTING.md b/js/schemas/CONTRIBUTING.md new file mode 100644 index 0000000000..de3c703d41 --- /dev/null +++ b/js/schemas/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# CONTRIBUTING + +For contributing guidelines see the [Project Liberty Contributing Guidelines](https://github.com/LibertyDSNP/meta/blob/main/CONTRIBUTING.md). + +## Running Tests +- `js/schemas` folder +- `npm run tests` + +### To generate dsnp schemas from mainnet +- inside `js/schemas/scripts` +- run `npm run generate` +- check the newly generated `data.ts` file inside `js/schemas` diff --git a/js/schemas/README.md b/js/schemas/README.md new file mode 100644 index 0000000000..aad0734df8 --- /dev/null +++ b/js/schemas/README.md @@ -0,0 +1,89 @@ +# Static Schemas package + + + + +[![Contributors][contributors-shield]][contributors-url] +[![Forks][forks-shield]][forks-url] +[![Stargazers][stars-shield]][stars-url] +[![Issues][issues-shield]][issues-url] +[![MIT License][license-shield]][license-url] +[![NPM @latest][npm-shield]][npm-url] +[![NPM @next][npm-next-shield]][npm-next-url] + +# Static schemas + +A convenient way to get schema details locally with TypeScript. + + + +## Getting Started + +- `npm install @frequency-chain/schemas` (static schemas library) + +## Usage +After importing, any of the following **Maps** can be used to fetch desired schema information. + +- `ID_TO_SCHEMA_FULL_NAME` is a **Map** that returns full names from schema ids (example `dsnp.tombstone@v1`) +- `FULL_NAME_TO_ID` is a **Map** that returns schema id from full name +- `ID_TO_SCHEMA_INFO` is a **Map** that return `SchemaInfo` from schema id + +Here is an example of a schema info object + +```javascript + { + id: 7, + namespace: 'dsnp', + name: 'public-key-key-agreement', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Itemized', + appendOnly: true, + signatureRequired: true, + }, +``` + +## Upgrades and Matching Versions + +Assuming you are using no deprecated methods, any release version of `@frequency-chain/schemas` should work against a release version of a Frequency node. +If you are working against a development node it is suggested that you match the package version against the commit hash using `v0.0.0-[First 6 of the commit hash]`. + +Changelog is maintained in the [releases for Frequency](https://github.com/frequency-chain/frequency/releases). + + + + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more information. + + + +## License + +Distributed under the Apache 2.0 License. See `LICENSE` for more information. + + + + +[contributors-shield]: https://img.shields.io/github/contributors/frequency-chain/frequency.svg?style=for-the-badge +[contributors-url]: https://github.com/frequency-chain/frequency/graphs/contributors +[forks-shield]: https://img.shields.io/github/forks/frequency-chain/frequency.svg?style=for-the-badge +[forks-url]: https://github.com/frequency-chain/frequency/network/members +[stars-shield]: https://img.shields.io/github/stars/frequency-chain/frequency.svg?style=for-the-badge +[stars-url]: https://github.com/frequency-chain/frequency/stargazers +[issues-shield]: https://img.shields.io/github/issues/frequency-chain/frequency.svg?style=for-the-badge +[issues-url]: https://github.com/frequency-chain/frequency/issues +[license-shield]: https://img.shields.io/github/license/frequency-chain/frequency.svg?style=for-the-badge +[license-url]: https://github.com/frequency-chain/frequency/blob/master/LICENSE +[npm-shield]: https://img.shields.io/npm/v/@frequency-chain/schemas?label=npm%20%40latest&style=for-the-badge +[npm-url]: https://www.npmjs.com/package/@frequency-chain/schemas +[npm-next-shield]: https://img.shields.io/npm/v/@frequency-chain/schemas/next?label=npm%20%40next&style=for-the-badge +[npm-next-url]: https://www.npmjs.com/package/@frequency-chain/schemas diff --git a/js/schemas/data.ts b/js/schemas/data.ts new file mode 100644 index 0000000000..5f472db662 --- /dev/null +++ b/js/schemas/data.ts @@ -0,0 +1,224 @@ +import { SchemaInfo } from './schemas'; + +export const SCHEMA_INFOS: SchemaInfo[] = [ + { + id: 11, + namespace: 'dsnp', + name: 'user-attribute-set', + version: 1, + deprecated: true, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 20, + namespace: 'dsnp', + name: 'user-attribute-set', + version: 2, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 15, + namespace: 'dsnp', + name: 'profile-resources', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Itemized', + appendOnly: false, + signatureRequired: false, + }, + { + id: 7, + namespace: 'dsnp', + name: 'public-key-key-agreement', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Itemized', + appendOnly: true, + signatureRequired: true, + }, + { + id: 4, + namespace: 'dsnp', + name: 'reaction', + version: 1, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 5, + namespace: 'dsnp', + name: 'update', + version: 1, + deprecated: true, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 19, + namespace: 'dsnp', + name: 'update', + version: 2, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 8, + namespace: 'dsnp', + name: 'public-follows', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Paginated', + appendOnly: false, + signatureRequired: false, + }, + { + id: 10, + namespace: 'dsnp', + name: 'private-connections', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Paginated', + appendOnly: false, + signatureRequired: false, + }, + { + id: 13, + namespace: 'dsnp', + name: 'ext-content-attribute-set', + version: 1, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 6, + namespace: 'dsnp', + name: 'profile', + version: 1, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 3, + namespace: 'dsnp', + name: 'reply', + version: 1, + deprecated: true, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 18, + namespace: 'dsnp', + name: 'reply', + version: 2, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 1, + namespace: 'dsnp', + name: 'tombstone', + version: 1, + deprecated: true, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 16, + namespace: 'dsnp', + name: 'tombstone', + version: 2, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 9, + namespace: 'dsnp', + name: 'private-follows', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Paginated', + appendOnly: false, + signatureRequired: false, + }, + { + id: 14, + namespace: 'dsnp', + name: 'public-key-assertion-method', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Itemized', + appendOnly: false, + signatureRequired: true, + }, + { + id: 2, + namespace: 'dsnp', + name: 'broadcast', + version: 1, + deprecated: true, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 17, + namespace: 'dsnp', + name: 'broadcast', + version: 2, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, + { + id: 12, + namespace: 'dsnp', + name: 'dsnp-content-attribute-set', + version: 1, + deprecated: false, + modelType: 'Parquet', + payloadLocation: 'IPFS', + appendOnly: false, + signatureRequired: false, + }, +]; diff --git a/js/schemas/eslint.config.mjs b/js/schemas/eslint.config.mjs new file mode 100644 index 0000000000..a8fb881ff9 --- /dev/null +++ b/js/schemas/eslint.config.mjs @@ -0,0 +1,68 @@ +// @ts-check + +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import mocha from 'eslint-plugin-mocha'; +import globals from 'globals'; + +// Needed for eslint 9 +const mochaConfig = [ + { + name: 'mocha/recommended', + languageOptions: { + globals: globals.mocha, + }, + plugins: { + mocha, + }, + rules: mocha.configs.flat.recommended.rules, + }, +]; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.strict, + ...tseslint.configs.stylistic, + ...mochaConfig, + { + ignores: ['dist/', 'scripts/'], + }, + { + linterOptions: { + // Needed as the generated code uses this + reportUnusedDisableDirectives: false, + }, + }, + { + languageOptions: { + parserOptions: { + projectService: { + allowDefaultProject: ['eslint.config.mjs', 'test/*.ts'], + defaultProject: './tsconfig.eslint.json', + }, + }, + }, + }, + { + rules: { + '@typescript-eslint/no-empty-interface': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-empty-function': 'off', + semi: ['error', 'always'], + 'mocha/no-setup-in-describe': 'off', + 'no-use-before-define': 'off', + 'no-unused-vars': 'off', + 'no-var': 'error', + 'id-length': [ + 'error', + { + exceptionPatterns: ['[i-k]', 'e', 'c', 'x', 'y', 'r', 's', 'v'], + properties: 'never', + }, + ], + 'allow-namespace': 'off', + }, + } +); diff --git a/js/schemas/index.ts b/js/schemas/index.ts new file mode 100644 index 0000000000..42369b9b57 --- /dev/null +++ b/js/schemas/index.ts @@ -0,0 +1,6 @@ +import * as data from './data'; +import * as schemas from './schemas'; + +export * from './data'; +export * from './schemas'; +export default { ...data, ...schemas }; diff --git a/js/schemas/package-lock.json b/js/schemas/package-lock.json new file mode 100644 index 0000000000..0d22ff3623 --- /dev/null +++ b/js/schemas/package-lock.json @@ -0,0 +1,3490 @@ +{ + "name": "@frequency-chain/schemas", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@frequency-chain/schemas", + "version": "0.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@eslint/js": "^9.14.0", + "@polkadot/api": "^14.3.1", + "@polkadot/rpc-provider": "^14.3.1", + "@types/mocha": "^10.0.9", + "eslint": "^9.14.0", + "eslint-plugin-mocha": "^10.5.0", + "mocha": "10.8.2", + "prettier": "^3.3.3", + "tsx": "^4.19.2", + "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/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==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.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": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "dev": true, + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@noble/curves": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "dev": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.0.1.tgz", + "integrity": "sha512-/SMC/l7foRjpykLTUTacIH05H3mr9ip8b5xxfwXlVezXrNVLp3Cv0GX6uItkKd+ZjzVPf3PFrDF2B2/HLSNESA==", + "dev": true, + "optional": true + }, + "node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.1.0.tgz", + "integrity": "sha512-8GSFE5+EF73MCuLQm8tjrbCqlgclcHBSRaswvXziJ0ZW7iw3UEMsKkkKvELayWyBuOPa2T5i1nj6gFOeIsqvrg==", + "dev": true, + "optional": true + }, + "node_modules/@polkadot-api/metadata-builders": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.3.2.tgz", + "integrity": "sha512-TKpfoT6vTb+513KDzMBTfCb/ORdgRnsS3TDFpOhAhZ08ikvK+hjHMt5plPiAX/OWkm1Wc9I3+K6W0hX5Ab7MVg==", + "dev": true, + "optional": true, + "dependencies": { + "@polkadot-api/substrate-bindings": "0.6.0", + "@polkadot-api/utils": "0.1.0" + } + }, + "node_modules/@polkadot-api/observable-client": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.3.2.tgz", + "integrity": "sha512-HGgqWgEutVyOBXoGOPp4+IAq6CNdK/3MfQJmhCJb8YaJiaK4W6aRGrdQuQSTPHfERHCARt9BrOmEvTXAT257Ug==", + "dev": true, + "optional": true, + "dependencies": { + "@polkadot-api/metadata-builders": "0.3.2", + "@polkadot-api/substrate-bindings": "0.6.0", + "@polkadot-api/utils": "0.1.0" + }, + "peerDependencies": { + "@polkadot-api/substrate-client": "0.1.4", + "rxjs": ">=7.8.0" + } + }, + "node_modules/@polkadot-api/substrate-bindings": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.6.0.tgz", + "integrity": "sha512-lGuhE74NA1/PqdN7fKFdE5C1gNYX357j1tWzdlPXI0kQ7h3kN0zfxNOpPUN7dIrPcOFZ6C0tRRVrBylXkI6xPw==", + "dev": true, + "optional": true, + "dependencies": { + "@noble/hashes": "^1.3.1", + "@polkadot-api/utils": "0.1.0", + "@scure/base": "^1.1.1", + "scale-ts": "^1.6.0" + } + }, + "node_modules/@polkadot-api/substrate-client": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.1.4.tgz", + "integrity": "sha512-MljrPobN0ZWTpn++da9vOvt+Ex+NlqTlr/XT7zi9sqPtDJiQcYl+d29hFAgpaeTqbeQKZwz3WDE9xcEfLE8c5A==", + "dev": true, + "optional": true, + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.0.1", + "@polkadot-api/utils": "0.1.0" + } + }, + "node_modules/@polkadot-api/utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.1.0.tgz", + "integrity": "sha512-MXzWZeuGxKizPx2Xf/47wx9sr/uxKw39bVJUptTJdsaQn/TGq+z310mHzf1RCGvC1diHM8f593KrnDgc9oNbJA==", + "dev": true, + "optional": true + }, + "node_modules/@polkadot/api": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/api/-/api-14.3.1.tgz", + "integrity": "sha512-ZBKSXEVJa1S1bnmpnA7KT/fX3sJDIJOdVD9Hp3X+G73yvXzuK5k1Mn5z9bD/AcMs/HAGcbuYU+b9+b9IByH9YQ==", + "dev": true, + "dependencies": { + "@polkadot/api-augment": "14.3.1", + "@polkadot/api-base": "14.3.1", + "@polkadot/api-derive": "14.3.1", + "@polkadot/keyring": "^13.2.3", + "@polkadot/rpc-augment": "14.3.1", + "@polkadot/rpc-core": "14.3.1", + "@polkadot/rpc-provider": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/types-augment": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/types-create": "14.3.1", + "@polkadot/types-known": "14.3.1", + "@polkadot/util": "^13.2.3", + "@polkadot/util-crypto": "^13.2.3", + "eventemitter3": "^5.0.1", + "rxjs": "^7.8.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-augment": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/api-augment/-/api-augment-14.3.1.tgz", + "integrity": "sha512-PE6DW+8kRhbnGKn7qCF7yM6eEt/kqrY8bh1i0RZcPY9QgwXW4bZZrtMK4WssX6Z70NTEoOW6xHYIjc7gFZuz8g==", + "dev": true, + "dependencies": { + "@polkadot/api-base": "14.3.1", + "@polkadot/rpc-augment": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/types-augment": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-base": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/api-base/-/api-base-14.3.1.tgz", + "integrity": "sha512-GZT6rTpT3HYZ/C3rLPjoX3rX3DOxNG/zgts+jKjNrCumAeZkVq5JErKIX8/3f2TVaE2Kbqniy3d1TH/AL4HBPA==", + "dev": true, + "dependencies": { + "@polkadot/rpc-core": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/util": "^13.2.3", + "rxjs": "^7.8.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-derive": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/api-derive/-/api-derive-14.3.1.tgz", + "integrity": "sha512-PhqUEJCY54vXtIaoYqGUtJY06wHd/K0cBmBz9yCLxp8UZkLoGWhfJRTruI25Jnucf9awS5cZKYqbsoDrL09Oqg==", + "dev": true, + "dependencies": { + "@polkadot/api": "14.3.1", + "@polkadot/api-augment": "14.3.1", + "@polkadot/api-base": "14.3.1", + "@polkadot/rpc-core": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/util": "^13.2.3", + "@polkadot/util-crypto": "^13.2.3", + "rxjs": "^7.8.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/keyring": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/keyring/-/keyring-13.2.3.tgz", + "integrity": "sha512-pgTo6DXNXub0wGD+MnVHYhKxf80Jl+QMOCb818ioGdXz++Uw4mTueFAwtB+N7TGo0HafhChUiNJDxFdlDkcAng==", + "dev": true, + "dependencies": { + "@polkadot/util": "13.2.3", + "@polkadot/util-crypto": "13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "13.2.3", + "@polkadot/util-crypto": "13.2.3" + } + }, + "node_modules/@polkadot/networks": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-13.2.3.tgz", + "integrity": "sha512-mG+zkXg/33AyPrkv2xBbAo3LBUwOwBn6qznBU/4jxiZPnVvCwMaxE7xHM22B5riItbNJ169FXv3wy0v6ZmkFbw==", + "dev": true, + "dependencies": { + "@polkadot/util": "13.2.3", + "@substrate/ss58-registry": "^1.51.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-augment": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-augment/-/rpc-augment-14.3.1.tgz", + "integrity": "sha512-Z8Hp8fFHwFCiTX0bBCDqCZ4U26wLIJl1NRSjJTsAr+SS68pYZBDGCwhKztpKGqndk1W1akRUaxrkGqYdIFmspQ==", + "dev": true, + "dependencies": { + "@polkadot/rpc-core": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-core": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-core/-/rpc-core-14.3.1.tgz", + "integrity": "sha512-FV2NPhFwFxmX8LqibDcGc6IKTBqmvwr7xwF2OA60Br4cX+AQzMSVpFlfQcETll+0M+LnRhqGKGkP0EQWXaSowA==", + "dev": true, + "dependencies": { + "@polkadot/rpc-augment": "14.3.1", + "@polkadot/rpc-provider": "14.3.1", + "@polkadot/types": "14.3.1", + "@polkadot/util": "^13.2.3", + "rxjs": "^7.8.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-provider": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-provider/-/rpc-provider-14.3.1.tgz", + "integrity": "sha512-NF/Z/7lzT+jp5LZzC49g+YIjRzXVI0hFag3+B+4zh6E/kKADdF59EHj2Im4LDhRGOnEO9AE4H6/UjNEbZ94JtA==", + "dev": true, + "dependencies": { + "@polkadot/keyring": "^13.2.3", + "@polkadot/types": "14.3.1", + "@polkadot/types-support": "14.3.1", + "@polkadot/util": "^13.2.3", + "@polkadot/util-crypto": "^13.2.3", + "@polkadot/x-fetch": "^13.2.3", + "@polkadot/x-global": "^13.2.3", + "@polkadot/x-ws": "^13.2.3", + "eventemitter3": "^5.0.1", + "mock-socket": "^9.3.1", + "nock": "^13.5.5", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@substrate/connect": "0.8.11" + } + }, + "node_modules/@polkadot/types": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types/-/types-14.3.1.tgz", + "integrity": "sha512-O748XgCLDQYxS5nQ6TJSqW88oC4QNIoNVlWZC2Qq4SmEXuSzaNHQwSVtdyPRJCCc4Oi1DCQvGui4O+EukUl7HA==", + "dev": true, + "dependencies": { + "@polkadot/keyring": "^13.2.3", + "@polkadot/types-augment": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/types-create": "14.3.1", + "@polkadot/util": "^13.2.3", + "@polkadot/util-crypto": "^13.2.3", + "rxjs": "^7.8.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-augment": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-augment/-/types-augment-14.3.1.tgz", + "integrity": "sha512-SC4M6TBlgCglNz+gRbvfoVRDz0Vyeev6v0HeAdw0H6ayEW4BXUdo5bFr0092bdS5uTrEPgiSyUry5TJs2KoXig==", + "dev": true, + "dependencies": { + "@polkadot/types": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-codec": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-codec/-/types-codec-14.3.1.tgz", + "integrity": "sha512-3y3RBGd+8ebscGbNUOjqUjnRE7hgicgid5LtofHK3O1EDcJQJnYBDkJ7fOAi96CDgHsg+f2FWWkBWEPgpOQoMQ==", + "dev": true, + "dependencies": { + "@polkadot/util": "^13.2.3", + "@polkadot/x-bigint": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-create": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-create/-/types-create-14.3.1.tgz", + "integrity": "sha512-F4EBvF3Zvym0xrkAA5Yz01IAVMepMV3w2Dwd0C9IygEAQ5sYLLPHmf72/aXn+Ag+bSyT2wlJHpDc+nEBXNQ3Gw==", + "dev": true, + "dependencies": { + "@polkadot/types-codec": "14.3.1", + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-known": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-known/-/types-known-14.3.1.tgz", + "integrity": "sha512-58b3Yc7+sxwNjs8axmrA9OCgnxmEKIq7XCH2VxSgLqTeqbohVtxwUSCW/l8NPrq1nxzj4J2sopu0PPg8/++q4g==", + "dev": true, + "dependencies": { + "@polkadot/networks": "^13.2.3", + "@polkadot/types": "14.3.1", + "@polkadot/types-codec": "14.3.1", + "@polkadot/types-create": "14.3.1", + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-support": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-support/-/types-support-14.3.1.tgz", + "integrity": "sha512-MfVe4iIOJIfBr+gj8Lu8gwIvhnO6gDbG5LeaKAjY6vS6Oh0y5Ztr8NdMIl8ccSpoyt3LqIXjfApeGzHiLzr6bw==", + "dev": true, + "dependencies": { + "@polkadot/util": "^13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/util": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.2.3.tgz", + "integrity": "sha512-pioNnsig3qHXrfOKMe4Yqos8B8N3/EZUpS+WfTpWnn1VjYban/0GrTXeavPlAwggnY27b8fS6rBzQBhnVYDw8g==", + "dev": true, + "dependencies": { + "@polkadot/x-bigint": "13.2.3", + "@polkadot/x-global": "13.2.3", + "@polkadot/x-textdecoder": "13.2.3", + "@polkadot/x-textencoder": "13.2.3", + "@types/bn.js": "^5.1.6", + "bn.js": "^5.2.1", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/util-crypto": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-13.2.3.tgz", + "integrity": "sha512-5sbggmLbn5eiuVMyPROPlT5roHRqdKHOfSpioNbGvGIZ1qIWVoC1RfsK0NWJOVGDzy6DpQe0KYT/kgcU5Xsrzw==", + "dev": true, + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@polkadot/networks": "13.2.3", + "@polkadot/util": "13.2.3", + "@polkadot/wasm-crypto": "^7.4.1", + "@polkadot/wasm-util": "^7.4.1", + "@polkadot/x-bigint": "13.2.3", + "@polkadot/x-randomvalues": "13.2.3", + "@scure/base": "^1.1.7", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "13.2.3" + } + }, + "node_modules/@polkadot/wasm-bridge": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.4.1.tgz", + "integrity": "sha512-tdkJaV453tezBxhF39r4oeG0A39sPKGDJmN81LYLf+Fihb7astzwju+u75BRmDrHZjZIv00un3razJEWCxze6g==", + "dev": true, + "dependencies": { + "@polkadot/wasm-util": "7.4.1", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.4.1.tgz", + "integrity": "sha512-kHN/kF7hYxm1y0WeFLWeWir6oTzvcFmR4N8fJJokR+ajYbdmrafPN+6iLgQVbhZnDdxyv9jWDuRRsDnBx8tPMQ==", + "dev": true, + "dependencies": { + "@polkadot/wasm-bridge": "7.4.1", + "@polkadot/wasm-crypto-asmjs": "7.4.1", + "@polkadot/wasm-crypto-init": "7.4.1", + "@polkadot/wasm-crypto-wasm": "7.4.1", + "@polkadot/wasm-util": "7.4.1", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-asmjs": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.4.1.tgz", + "integrity": "sha512-pwU8QXhUW7IberyHJIQr37IhbB6DPkCG5FhozCiNTq4vFBsFPjm9q8aZh7oX1QHQaiAZa2m2/VjIVE+FHGbvHQ==", + "dev": true, + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-init": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.4.1.tgz", + "integrity": "sha512-AVka33+f7MvXEEIGq5U0dhaA2SaXMXnxVCQyhJTaCnJ5bRDj0Xlm3ijwDEQUiaDql7EikbkkRtmlvs95eSUWYQ==", + "dev": true, + "dependencies": { + "@polkadot/wasm-bridge": "7.4.1", + "@polkadot/wasm-crypto-asmjs": "7.4.1", + "@polkadot/wasm-crypto-wasm": "7.4.1", + "@polkadot/wasm-util": "7.4.1", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-wasm": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.4.1.tgz", + "integrity": "sha512-PE1OAoupFR0ZOV2O8tr7D1FEUAwaggzxtfs3Aa5gr+yxlSOaWUKeqsOYe1KdrcjmZVV3iINEAXxgrbzCmiuONg==", + "dev": true, + "dependencies": { + "@polkadot/wasm-util": "7.4.1", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-util": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.4.1.tgz", + "integrity": "sha512-RAcxNFf3zzpkr+LX/ItAsvj+QyM56TomJ0xjUMo4wKkHjwsxkz4dWJtx5knIgQz/OthqSDMR59VNEycQeNuXzA==", + "dev": true, + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/x-bigint": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-13.2.3.tgz", + "integrity": "sha512-VKgEAh0LsxTd/Hg517Tt5ZU4CySjBwMpaojbkjgv3fOdg1cN7t4eFEUxpyj7mlO0cp22SzDh7nmy4TO98qhLQA==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-fetch": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-fetch/-/x-fetch-13.2.3.tgz", + "integrity": "sha512-7Nmk+8ieEGzz43nc1rX6nH3rQo6rhGmAaIXJWnXY9gOHY0k1me1bJYbP+xDdh8vcLh8eY3D1sESUwG6QYZW2lg==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "node-fetch": "^3.3.2", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-global": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-13.2.3.tgz", + "integrity": "sha512-7MYQIAEwBkRcNrgqac5PbB0kNPlI6ISJEy6/Nb+crj8BFjQ8rf11PF49fq0QsvDeuYM1aNLigrvYZNptQs4lbw==", + "dev": true, + "dependencies": { + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-randomvalues": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-13.2.3.tgz", + "integrity": "sha512-Zf0GTfLmVk+VzPUmcQSpXjjmFzMTjPhXoLuIoE7xIu73T+vQ+TX9j7DvorN6bIRsnZ9l1SyTZsSf/NTjNZKIZg==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "13.2.3", + "@polkadot/wasm-util": "*" + } + }, + "node_modules/@polkadot/x-textdecoder": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-13.2.3.tgz", + "integrity": "sha512-i8hRXPtGknmdm3FYv6/94I52VXHJZa5sgYNw1+Hqb4Jqmq4awUjea35CKXd/+aw70Qn8Ngg31l2GoiH494fa+Q==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-textencoder": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-13.2.3.tgz", + "integrity": "sha512-wJI3Bb/dC4zyBXJFm5+ZhyBXWoI5wvP8k8qX0/ZC0PQsgSAqs7LVhiofk4Wd94n0P41W5re58LrGXLyziSAshw==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-ws": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-ws/-/x-ws-13.2.3.tgz", + "integrity": "sha512-Y6MTAWgcnrnx/LkBx65X3ZyoJH5EFj3tXtflRoKg1+PLHSLuNBV7Wi5mLcE70z4e5c+4hgBbLq+8SqCqzFtSPw==", + "dev": true, + "dependencies": { + "@polkadot/x-global": "13.2.3", + "tslib": "^2.8.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@substrate/connect": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@substrate/connect/-/connect-0.8.11.tgz", + "integrity": "sha512-ofLs1PAO9AtDdPbdyTYj217Pe+lBfTLltdHDs3ds8no0BseoLeAGxpz1mHfi7zB4IxI3YyAiLjH6U8cw4pj4Nw==", + "deprecated": "versions below 1.x are no longer maintained", + "dev": true, + "optional": true, + "dependencies": { + "@substrate/connect-extension-protocol": "^2.0.0", + "@substrate/connect-known-chains": "^1.1.5", + "@substrate/light-client-extension-helpers": "^1.0.0", + "smoldot": "2.0.26" + } + }, + "node_modules/@substrate/connect-extension-protocol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@substrate/connect-extension-protocol/-/connect-extension-protocol-2.2.1.tgz", + "integrity": "sha512-GoafTgm/Jey9E4Xlj4Z5ZBt/H4drH2CNq8VrAro80rtoznrXnFDNVivLQzZN0Xaj2g8YXSn9pC9Oc9IovYZJXw==", + "dev": true, + "optional": true + }, + "node_modules/@substrate/connect-known-chains": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@substrate/connect-known-chains/-/connect-known-chains-1.7.0.tgz", + "integrity": "sha512-Qf+alxEPmNycUyrPkXWrlFA97punnBCGxSWqiLG1CNu+jQoFYqi8x7gZYfqmdUHDY4nG1F84KHPPk7Zy4ngSfg==", + "dev": true, + "optional": true + }, + "node_modules/@substrate/light-client-extension-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@substrate/light-client-extension-helpers/-/light-client-extension-helpers-1.0.0.tgz", + "integrity": "sha512-TdKlni1mBBZptOaeVrKnusMg/UBpWUORNDv5fdCaJklP4RJiFOzBCrzC+CyVI5kQzsXBisZ+2pXm+rIjS38kHg==", + "dev": true, + "optional": true, + "dependencies": { + "@polkadot-api/json-rpc-provider": "^0.0.1", + "@polkadot-api/json-rpc-provider-proxy": "^0.1.0", + "@polkadot-api/observable-client": "^0.3.0", + "@polkadot-api/substrate-client": "^0.1.2", + "@substrate/connect-extension-protocol": "^2.0.0", + "@substrate/connect-known-chains": "^1.1.5", + "rxjs": "^7.8.1" + }, + "peerDependencies": { + "smoldot": "2.x" + } + }, + "node_modules/@substrate/ss58-registry": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.51.0.tgz", + "integrity": "sha512-TWDurLiPxndFgKjVavCniytBIw+t4ViOi7TYp9h/D0NMmkEc9klFTo+827eyEJ0lELpqO207Ey7uGxUa+BS1jQ==", + "dev": true + }, + "node_modules/@types/bn.js": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", + "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", + "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/type-utils": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", + "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", + "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", + "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", + "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", + "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", + "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", + "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/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==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.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==", + "dev": true, + "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/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": 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/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "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==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.5", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-mocha": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz", + "integrity": "sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "globals": "^13.24.0", + "rambda": "^7.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-mocha/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/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==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "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==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.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==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.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==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/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==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/nock": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.6.tgz", + "integrity": "sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "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/rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "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==", + "dev": true, + "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/scale-ts": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/scale-ts/-/scale-ts-1.6.1.tgz", + "integrity": "sha512-PBMc2AWc6wSEqJYBDPcyCLUj9/tMKnLX70jLOSndMtcUoLQucP/DM0vnQo1wJAYjTrQiq8iG9rD0q6wFzgjH7g==", + "dev": true, + "optional": true + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smoldot": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-2.0.26.tgz", + "integrity": "sha512-F+qYmH4z2s2FK+CxGj8moYcd1ekSIKH8ywkdqlOz88Dat35iB1DIYL11aILN46YSGMzQW/lbJNS307zBSDN5Ig==", + "dev": true, + "optional": true, + "dependencies": { + "ws": "^8.8.1" + } + }, + "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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "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==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", + "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.14.0", + "@typescript-eslint/parser": "8.14.0", + "@typescript-eslint/utils": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true + }, + "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==", + "dev": true, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/js/schemas/package.json b/js/schemas/package.json new file mode 100644 index 0000000000..bb9e07348d --- /dev/null +++ b/js/schemas/package.json @@ -0,0 +1,39 @@ +{ + "name": "@frequency-chain/schemas", + "version": "0.0.0", + "bugs": { + "url": "https://github.com/frequency-chain/frequency/issues" + }, + "description": "A static package which allows getting schemas locally", + "main": "index.js", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/frequency-chain/frequency.git", + "directory": "js/schemas" + }, + "scripts": { + "package": "node scripts/package.cjs", + "prepackage": "cp CONTRIBUTING.md README.md ../../LICENSE ./dist", + "build": "tsc -p ./tsconfig.types.json && tsc -p ./tsconfig.cjs.json && tsc -p ./tsconfig.esm.json", + "postbuild": "npm run package", + "test": "mocha --import=tsx ./test/**/*.test.ts", + "format": "tsc --noEmit --pretty && prettier --write . && eslint --fix", + "lint": "tsc --noEmit --pretty && prettier --check . && eslint" + }, + "author": "frequency-chain", + "license": "Apache-2.0", + "devDependencies": { + "@polkadot/api": "^14.3.1", + "@polkadot/rpc-provider": "^14.3.1", + "@eslint/js": "^9.14.0", + "@types/mocha": "^10.0.9", + "eslint": "^9.14.0", + "eslint-plugin-mocha": "^10.5.0", + "mocha": "10.8.2", + "prettier": "^3.3.3", + "tsx": "^4.19.2", + "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0" + } +} diff --git a/js/schemas/schemas.ts b/js/schemas/schemas.ts new file mode 100644 index 0000000000..6a83807cdc --- /dev/null +++ b/js/schemas/schemas.ts @@ -0,0 +1,47 @@ +import { SCHEMA_INFOS } from './data'; + +export interface SchemaInfo { + id: number; + name: string; + namespace: string; + version: number; + modelType: string; + payloadLocation: string; + appendOnly: boolean; + signatureRequired: boolean; + deprecated: boolean; +} + +const schemaFullName = (info: SchemaInfo): string => `${info.namespace}.${info.name}@v${info.version}`; +const schemaFullNameWithoutVersion = (info: SchemaInfo): string => `${info.namespace}.${info.name}`; + +/** + * Mapping that will allow us to get schema full names from their ids + */ +export const ID_TO_SCHEMA_FULL_NAME = new Map(SCHEMA_INFOS.map((x) => [x.id, schemaFullName(x)])); + +/** + * Mapping that will allow us to get schema ids from their full names + */ +export const FULL_NAME_TO_ID = new Map(SCHEMA_INFOS.map((x) => [schemaFullName(x), x.id])); + +/** + * Mapping that will allow us to get active schema ids from their names + * example input dsnp.public-key-key-agreement + */ +export const NAME_TO_ID_ACTIVE = new Map( + SCHEMA_INFOS.filter((info) => !info.deprecated).map((x) => [schemaFullNameWithoutVersion(x), x.id]) +); + +/** + * Mapping that will allow us to get schema infos from their IDs + */ +export const ID_TO_SCHEMA_INFO = new Map(SCHEMA_INFOS.map((x) => [x.id, x])); + +/** + * A method that can retrieve all versions of a given schema name without any version + * example input dsnp.public-key-key-agreement + */ +export const getAllVersionsFromSchemaName = (schemaName: string): SchemaInfo[] => { + return SCHEMA_INFOS.filter((info) => schemaFullNameWithoutVersion(info) === schemaName); +}; diff --git a/js/schemas/scripts/fetchSchemaData.mjs b/js/schemas/scripts/fetchSchemaData.mjs new file mode 100644 index 0000000000..9fcebd9ab6 --- /dev/null +++ b/js/schemas/scripts/fetchSchemaData.mjs @@ -0,0 +1,135 @@ +// Only way to silence PolkadotJS API warnings we don't want +console.warn = () => {}; +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { promises as fs } from 'fs'; + +const options = { + rpc: { + schemas: { + getBySchemaId: { + description: 'Get a Schema by Id', + params: [ + { + name: 'schema_id', + type: 'SchemaId', + }, + ], + type: 'Option', + }, + getVersions: { + description: 'Get different versions and schema ids for a complete schema name or only a namespace', + params: [ + { + name: 'schema_name', + type: 'String', + }, + ], + type: 'Option>', + }, + }, + }, + types: { + SchemaId: 'u16', + SchemaModel: 'Vec', + SchemaVersion: 'u8', + SchemaResponse: { + schema_id: 'SchemaId', + model: 'SchemaModel', + model_type: 'ModelType', + payload_location: 'PayloadLocation', + settings: 'Vec', + }, + ModelType: { + _enum: ['AvroBinary', 'Parquet'], + }, + PayloadLocation: { + _enum: ['OnChain', 'IPFS', 'Itemized', 'Paginated'], + }, + SchemaSetting: { + _enum: ['AppendOnly', 'SignatureRequired'], + }, + SchemaVersionResponse: { + schema_name: 'String', + schema_version: 'SchemaVersion', + schema_id: 'SchemaId', + }, + }, +}; +const SOURCE_URL = 'wss://1.rpc.frequency.xyz'; +const GENERATED_FILE_NAME = '../data.ts'; + +async function main() { + try { + await getSchemas(SOURCE_URL); + process.exit(0); + } catch (error) { + console.error('Error:', error); + process.exit(1); + } +} + +main(); + +async function getSchemas(sourceUrl) { + const provider = new WsProvider(sourceUrl); + const api = await ApiPromise.create({ provider, ...options }); + const nameToIds = await api.rpc.schemas.getVersions('dsnp'); + + const idToSchemaInfo = new Map(); + const fullNameToVersions = new Map(); + + for (const v of JSON.parse(JSON.stringify(nameToIds))) { + const fullName = v.schema_name; + const names = fullName.split('.'); + const version = v.schema_version; + const id = v.schema_id; + + if (fullNameToVersions.has(fullName)) { + const arr = fullNameToVersions.get(fullName); + arr.push({ + version: version, + id: id, + }); + fullNameToVersions.set(fullName, arr); + } else { + fullNameToVersions.set(fullName, [ + { + version: version, + id: id, + }, + ]); + } + + const chainSchemaInfo = await api.query.schemas.schemaInfos(id); + const objSchemaInfo = JSON.parse(JSON.stringify(chainSchemaInfo)); + idToSchemaInfo.set(id, { + id: id, + namespace: names[0], + name: names[1], + version: version, + deprecated: false, + modelType: objSchemaInfo.modelType, + payloadLocation: objSchemaInfo.payloadLocation, + appendOnly: (objSchemaInfo.settings & 1) > 0, + signatureRequired: (objSchemaInfo.settings & 2) > 0, + }); + } + + for (let arr of fullNameToVersions.values()) { + arr.sort((a, b) => a.version - b.version); + for (let i = 0; i < arr.length; i++) { + const inner = arr[i]; + const info = idToSchemaInfo.get(inner.id); + info.deprecated = i < arr.length - 1; + } + } + + let generated = ''; + for (let v of idToSchemaInfo.values()) { + generated += `\n${JSON.stringify(v, null, 2).replace(/"([^"]+)":/g, '$1:')},`; + } + let output = `import { SchemaInfo } from './schemas';\n\nexport const SCHEMA_INFOS: SchemaInfo[] = [${generated}\n];\n`; + + console.log(output); + await fs.writeFile(GENERATED_FILE_NAME, output, 'utf8'); +} diff --git a/js/schemas/scripts/package.cjs b/js/schemas/scripts/package.cjs new file mode 100644 index 0000000000..fba215a527 --- /dev/null +++ b/js/schemas/scripts/package.cjs @@ -0,0 +1,59 @@ +/** + * Build the package.json for the actual publishing + */ +// eslint-disable-next-line +const fs = require('fs'); +// eslint-disable-next-line +const path = require('path'); + +// eslint-disable-next-line +const rootPackage = require('../package.json'); + +// Remove test related work +delete rootPackage['jest-junit']; +delete rootPackage['jest']; + +// Don't keep scripts +delete rootPackage['scripts']; + +// Don't keep dev dependencies +delete rootPackage['devDependencies']; + +// Setup the main and types correctly +rootPackage['main'] = './cjs/index.js'; +rootPackage['module'] = './esm/index.js'; +rootPackage['types'] = 'index.d.ts'; +(rootPackage['exports'] = { + '.': { + types: './index.d.ts', + require: './cjs/index.js', + import: './esm/index.js', + default: './esm/index.js', + }, +}), + // Write it out + fs.writeFileSync( + `${path.join(__dirname, '../dist', 'package.json')}`, + JSON.stringify(rootPackage, null, 2), + (err) => { + if (err) throw new Error(err); + } + ); + +// Write out a simple type override for the esm side of things +fs.writeFileSync( + `${path.join(__dirname, '../dist/esm', 'package.json')}`, + JSON.stringify({ type: 'module' }, null, 2), + (err) => { + if (err) throw new Error(err); + } +); + +// Write out a simple type override for the cjs side of things +fs.writeFileSync( + `${path.join(__dirname, '../dist/cjs', 'package.json')}`, + JSON.stringify({ type: 'commonjs' }, null, 2), + (err) => { + if (err) throw new Error(err); + } +); diff --git a/js/schemas/scripts/package.json b/js/schemas/scripts/package.json new file mode 100644 index 0000000000..6cdce10515 --- /dev/null +++ b/js/schemas/scripts/package.json @@ -0,0 +1,13 @@ +{ + "name": "schema-data", + "version": "1.0.0", + "description": "Gets data from mainnet and outputs them in the format used by schema package", + "scripts": { + "generate": "node fetchSchemaData.mjs" + }, + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@polkadot/api": "^13.2.1" + } +} diff --git a/js/schemas/test/schemas.test.ts b/js/schemas/test/schemas.test.ts new file mode 100644 index 0000000000..727042e2b5 --- /dev/null +++ b/js/schemas/test/schemas.test.ts @@ -0,0 +1,55 @@ +import assert from 'assert'; +import { + FULL_NAME_TO_ID, + getAllVersionsFromSchemaName, + ID_TO_SCHEMA_FULL_NAME, + ID_TO_SCHEMA_INFO, + NAME_TO_ID_ACTIVE, + SchemaInfo, +} from '../schemas'; + +describe('schemas', function () { + it('should be able to successfully get schemas from Id', function () { + const fullName = ID_TO_SCHEMA_FULL_NAME.get(7); + assert.equal(fullName, 'dsnp.public-key-key-agreement@v1'); + }); + + it('should be able to successfully get schema id from name', function () { + const id = FULL_NAME_TO_ID.get('dsnp.public-key-key-agreement@v1'); + assert.equal(id, 7); + }); + + it('should be able to successfully get schema info from ID', function () { + const info = ID_TO_SCHEMA_INFO.get(7); + const expected: SchemaInfo = { + id: 7, + namespace: 'dsnp', + name: 'public-key-key-agreement', + version: 1, + deprecated: false, + modelType: 'AvroBinary', + payloadLocation: 'Itemized', + appendOnly: true, + signatureRequired: true, + }; + assert.equal(info.id, expected.id); + assert.equal(info.namespace, expected.namespace); + assert.equal(info.name, expected.name); + assert.equal(info.version, expected.version); + assert.equal(info.deprecated, expected.deprecated); + assert.equal(info.modelType, expected.modelType); + assert.equal(info.payloadLocation, expected.payloadLocation); + assert.equal(info.appendOnly, expected.appendOnly); + assert.equal(info.signatureRequired, expected.signatureRequired); + }); + + it('should be able to successfully get all schema version from the schema name', function () { + const versions = getAllVersionsFromSchemaName('dsnp.tombstone'); + assert.deepEqual(versions, [ID_TO_SCHEMA_INFO.get(1), ID_TO_SCHEMA_INFO.get(16)]); + }); + + it('should be able to successfully get active schema version from the schema name', function () { + const id = NAME_TO_ID_ACTIVE.get('dsnp.tombstone'); + assert.equal(id, 16); + }); +}); diff --git a/js/schemas/tsconfig.cjs.json b/js/schemas/tsconfig.cjs.json new file mode 100644 index 0000000000..ebe4fe2b67 --- /dev/null +++ b/js/schemas/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["ES2020"], + "module": "CommonJS", + "outDir": "dist/cjs", + "declaration": false + } +} diff --git a/js/schemas/tsconfig.eslint.json b/js/schemas/tsconfig.eslint.json new file mode 100644 index 0000000000..2d2a3b3f8b --- /dev/null +++ b/js/schemas/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules/**", "./scripts/**", "./dist/**"] +} diff --git a/js/schemas/tsconfig.esm.json b/js/schemas/tsconfig.esm.json new file mode 100644 index 0000000000..fc39b784b8 --- /dev/null +++ b/js/schemas/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["ES2020"], + "module": "ES2022", + "outDir": "dist/esm", + "declaration": false + } +} diff --git a/js/schemas/tsconfig.json b/js/schemas/tsconfig.json new file mode 100644 index 0000000000..ad486c3507 --- /dev/null +++ b/js/schemas/tsconfig.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Base", + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "moduleResolution": "node", + "module": "esnext", + "noImplicitAny": true, + "outDir": "dist", + "resolveJsonModule": true, + "sourceMap": false, + "strict": true, + "skipLibCheck": true, + "target": "es2022", + "typeRoots": ["node_modules/@types"] + }, + "exclude": ["node_modules/**", "./test/**", "./scripts/**", "**/*.test.ts", "./dist/**"] +} diff --git a/js/schemas/tsconfig.types.json b/js/schemas/tsconfig.types.json new file mode 100644 index 0000000000..420c04d5fd --- /dev/null +++ b/js/schemas/tsconfig.types.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "lib": ["ES2020"], + "target": "es2022", + "outDir": "dist", + "emitDeclarationOnly": true, + "declaration": true + } +} From f70489c2abf1e40c0692768d080b54338b3542a9 Mon Sep 17 00:00:00 2001 From: Aramik Date: Fri, 22 Nov 2024 14:20:31 -0800 Subject: [PATCH 2/3] ethereum: added e2e tests (#2218) # Goal The goal of this PR is Closes #2203 # Discussion - added e2e tests for more usecase for ethereum keys - Some clean up and refactoring - Added eslint rules to enforce correct usage # Checklist - [X] e2e Tests added? --- e2e/capacity/capacityFail.test.ts | 5 +- e2e/capacity/capacity_rpc.test.ts | 5 +- e2e/capacity/transactions.test.ts | 3 +- e2e/capacity/transactionsBatch.test.ts | 9 +- e2e/eslint.config.mjs | 13 ++ e2e/load-tests/signatureRegistry.test.ts | 4 +- e2e/miscellaneous/balance.ethereum.test.ts | 67 ++++++ e2e/miscellaneous/frequency.test.ts | 6 +- e2e/msa/keyManagement.ethereum.test.ts | 122 +++++++++++ e2e/msa/msaKeyManagement.test.ts | 17 +- e2e/passkey/passkeyProxy.ethereum.test.ts | 10 +- e2e/passkey/passkeyProxy.test.ts | 18 +- e2e/scaffolding/P256.ts | 4 +- e2e/scaffolding/ethereum.ts | 101 +++++---- e2e/scaffolding/extrinsicHelpers.ts | 73 ++++--- e2e/scaffolding/funding.ts | 4 + e2e/scaffolding/helpers.ts | 37 +++- .../grantDelegation.ethereum.test.ts | 183 +++++++++++++++++ .../stateful.ethereum.test.ts | 193 ++++++++++++++++++ 19 files changed, 765 insertions(+), 109 deletions(-) create mode 100644 e2e/miscellaneous/balance.ethereum.test.ts create mode 100644 e2e/msa/keyManagement.ethereum.test.ts create mode 100644 e2e/scenarios/grantDelegation.ethereum.test.ts create mode 100644 e2e/stateful-pallet-storage/stateful.ethereum.test.ts diff --git a/e2e/capacity/capacityFail.test.ts b/e2e/capacity/capacityFail.test.ts index fefed7c903..d6b1a5c41c 100644 --- a/e2e/capacity/capacityFail.test.ts +++ b/e2e/capacity/capacityFail.test.ts @@ -19,6 +19,7 @@ import { assertAddNewKey, } from '../scaffolding/helpers'; import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const FUNDS_AMOUNT: bigint = 50n * DOLLARS; const fundingSource = getFundingSource('capacity-transactions-fail'); @@ -111,7 +112,7 @@ describe('Capacity Transaction Failures', function () { // As current owner, add a new set of control keys that do not have a balance. const newControlKeypair = createKeys('NewKeyNoBalance'); - const newPublicKey = newControlKeypair.publicKey; + const newPublicKey = getUnifiedPublicKey(newControlKeypair); const addKeyPayload: AddKeyData = await generateAddKeyPayload({ msaId: capacityProvider, newPublicKey: newPublicKey, @@ -193,7 +194,7 @@ describe('Capacity Transaction Failures', function () { // Add new key const newKeyPayload: AddKeyData = await generateAddKeyPayload({ msaId: new u64(ExtrinsicHelper.api.registry, capacityProvider), - newPublicKey: noTokensKeys.publicKey, + newPublicKey: getUnifiedPublicKey(noTokensKeys), }); const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newKeyPayload); diff --git a/e2e/capacity/capacity_rpc.test.ts b/e2e/capacity/capacity_rpc.test.ts index acb5653dff..f83882a10c 100644 --- a/e2e/capacity/capacity_rpc.test.ts +++ b/e2e/capacity/capacity_rpc.test.ts @@ -13,6 +13,7 @@ import { } from '../scaffolding/helpers'; import { FeeDetails } from '@polkadot/types/interfaces'; import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const FUNDS_AMOUNT: bigint = 50n * DOLLARS; const fundingSource = getFundingSource('capacity-rpcs'); @@ -46,7 +47,7 @@ describe('Capacity RPC', function () { const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload); const delegatorKeys = createKeys('delegatorKeys'); const call = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signPayloadSr25519(delegatorKeys, addProviderData), addProviderPayload ); @@ -89,7 +90,7 @@ describe('Capacity RPC', function () { const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload); const delegatorKeys = createKeys('delegatorKeys'); const insideTx = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signPayloadSr25519(delegatorKeys, addProviderData), addProviderPayload ); diff --git a/e2e/capacity/transactions.test.ts b/e2e/capacity/transactions.test.ts index 1498e8e89b..b64cb6d507 100644 --- a/e2e/capacity/transactions.test.ts +++ b/e2e/capacity/transactions.test.ts @@ -38,6 +38,7 @@ import { } from '../scaffolding/helpers'; import { ipfsCid } from '../messages/ipfs'; import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const FUNDS_AMOUNT: bigint = 50n * DOLLARS; const fundingSource = getFundingSource('capacity-transactions'); @@ -92,7 +93,7 @@ describe('Capacity Transactions', function () { authorizedKeys.push(await createAndFundKeypair(fundingSource, 50_000_000n)); defaultPayload.msaId = capacityProvider; - defaultPayload.newPublicKey = authorizedKeys[0].publicKey; + defaultPayload.newPublicKey = getUnifiedPublicKey(authorizedKeys[0]); const payload = await generateAddKeyPayload(defaultPayload); const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); diff --git a/e2e/capacity/transactionsBatch.test.ts b/e2e/capacity/transactionsBatch.test.ts index b8845411ee..6af3079a73 100644 --- a/e2e/capacity/transactionsBatch.test.ts +++ b/e2e/capacity/transactionsBatch.test.ts @@ -16,6 +16,7 @@ import { getTestHandle, } from '../scaffolding/helpers'; import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const FUNDS_AMOUNT: bigint = 50n * DOLLARS; const fundingSource = getFundingSource('capacity-transactions-batch'); @@ -49,7 +50,7 @@ describe('Capacity Transactions Batch', function () { const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload); const delegatorKeys = createKeys('delegatorKeys'); const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signPayloadSr25519(delegatorKeys, addProviderData), addProviderPayload ); @@ -70,7 +71,7 @@ describe('Capacity Transactions Batch', function () { }; const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), claimHandleProof, claimHandlePayload ); @@ -95,7 +96,7 @@ describe('Capacity Transactions Batch', function () { const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload); const delegatorKeys = createKeys('delegatorKeys'); const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signPayloadSr25519(delegatorKeys, addProviderData), addProviderPayload ); @@ -116,7 +117,7 @@ describe('Capacity Transactions Batch', function () { }; const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), calimHandleProof, claimHandlePayload ); diff --git a/e2e/eslint.config.mjs b/e2e/eslint.config.mjs index e8f62eccce..f1de04d4c0 100644 --- a/e2e/eslint.config.mjs +++ b/e2e/eslint.config.mjs @@ -51,6 +51,19 @@ export default tseslint.config( }, ], 'allow-namespace': 'off', + 'no-restricted-syntax': [ + 'error', + { + message: + 'Direct usage of keyPair.address is not allowed in this file. please use getUnifiedAddress function.', + selector: 'MemberExpression[property.name="address"]', + }, + { + message: + 'Direct usage of keyPair.publicKey is not allowed in this file. please use getUnifiedPublicKey function', + selector: 'MemberExpression[property.name="publicKey"]', + }, + ], }, } ); diff --git a/e2e/load-tests/signatureRegistry.test.ts b/e2e/load-tests/signatureRegistry.test.ts index ee2547edd2..789de5599d 100644 --- a/e2e/load-tests/signatureRegistry.test.ts +++ b/e2e/load-tests/signatureRegistry.test.ts @@ -13,7 +13,7 @@ import { KeyringPair } from '@polkadot/keyring/types'; import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; import { u64, Option } from '@polkadot/types'; import { getFundingSource } from '../scaffolding/funding'; -import { getUnifiedAddress } from '../scaffolding/ethereum'; +import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum'; interface GeneratedMsa { id: u64; @@ -154,7 +154,7 @@ async function addSigs(msaId: u64, keys: KeyringPair, blockNumber: number, nonce const defaultPayload: AddKeyData = {}; defaultPayload.msaId = msaId; - defaultPayload.newPublicKey = newKeys.publicKey; + defaultPayload.newPublicKey = getUnifiedPublicKey(newKeys); const payload = await generateAddKeyPayload(defaultPayload, 100, blockNumber); const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); diff --git a/e2e/miscellaneous/balance.ethereum.test.ts b/e2e/miscellaneous/balance.ethereum.test.ts new file mode 100644 index 0000000000..0cd67b9ff1 --- /dev/null +++ b/e2e/miscellaneous/balance.ethereum.test.ts @@ -0,0 +1,67 @@ +import '@frequency-chain/api-augment'; +import assert from 'assert'; +import { DOLLARS, createAndFundKeypair, createKeys } from '../scaffolding/helpers'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; +import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedAddress } from '../scaffolding/ethereum'; + +const fundingSource: KeyringPair = getFundingSource('frequency-balance-ethereum'); + +describe('Balance transfer ethereum', function () { + describe('setup', function () { + let senderSr25519Keys: KeyringPair; + let senderEthereumKeys: KeyringPair; + let ethereumKeys: KeyringPair; + let ethereumKeys2: KeyringPair; + let sr25519Keys: KeyringPair; + + before(async function () { + senderSr25519Keys = await createAndFundKeypair(fundingSource, 30n * DOLLARS); + senderEthereumKeys = await createAndFundKeypair(fundingSource, 30n * DOLLARS, undefined, undefined, 'ethereum'); + ethereumKeys = await createKeys('another-key-1', 'ethereum'); + ethereumKeys2 = await createKeys('another-key-2', 'ethereum'); + sr25519Keys = await createKeys('another-sr25519', 'sr25519'); + }); + + it('should transfer from sr25519 to ethereum style key', async function () { + const transferAmount = 10n * DOLLARS; + const extrinsic = new Extrinsic( + () => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(ethereumKeys), transferAmount), + senderSr25519Keys, + ExtrinsicHelper.api.events.balances.Transfer + ); + const { target } = await extrinsic.signAndSend(); + assert.notEqual(target, undefined, 'should have returned Transfer event'); + const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys); + assert(accountInfo.data.free.toBigInt() >= transferAmount); + }); + + it('should transfer from sr25519 to ethereum 20 byte address', async function () { + const transferAmount = 10n * DOLLARS; + const extrinsic = new Extrinsic( + // this is using MultiAddress::Address20 type in Rust since addressRaw is 20 bytes ethereum address + () => ExtrinsicHelper.api.tx.balances.transferKeepAlive(ethereumKeys2.addressRaw, transferAmount), + senderSr25519Keys, + ExtrinsicHelper.api.events.balances.Transfer + ); + const { target } = await extrinsic.signAndSend(); + assert.notEqual(target, undefined, 'should have returned Transfer event'); + const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys2); + assert(accountInfo.data.free.toBigInt() >= transferAmount); + }); + + it('should transfer from an ethereum key to sr25519 key', async function () { + const transferAmount = 10n * DOLLARS; + const extrinsic = new Extrinsic( + () => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(sr25519Keys), transferAmount), + senderEthereumKeys, + ExtrinsicHelper.api.events.balances.Transfer + ); + const { target } = await extrinsic.signAndSend(); + assert.notEqual(target, undefined, 'should have returned Transfer event'); + const accountInfo = await ExtrinsicHelper.getAccountInfo(sr25519Keys); + assert(accountInfo.data.free.toBigInt() >= transferAmount); + }); + }); +}); diff --git a/e2e/miscellaneous/frequency.test.ts b/e2e/miscellaneous/frequency.test.ts index d0848032dc..ce3c3b4330 100644 --- a/e2e/miscellaneous/frequency.test.ts +++ b/e2e/miscellaneous/frequency.test.ts @@ -6,7 +6,7 @@ import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; import { getFundingSource } from '../scaffolding/funding'; import { u8, Option } from '@polkadot/types'; import { u8aToHex } from '@polkadot/util/u8a/toHex'; -import { getUnifiedAddress } from '../scaffolding/ethereum'; +import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum'; const fundingSource: KeyringPair = getFundingSource('frequency-misc'); @@ -23,7 +23,7 @@ describe('Frequency', function () { it('Get events successfully', async function () { const balance_pallet = new u8(ExtrinsicHelper.api.registry, 10); const transfer_event = new u8(ExtrinsicHelper.api.registry, 2); - const dest_account = u8aToHex(keypairB.publicKey).slice(2); + const dest_account = u8aToHex(getUnifiedPublicKey(keypairB)).slice(2); const beforeBlockNumber = await getBlockNumber(); const extrinsic = new Extrinsic( @@ -66,7 +66,7 @@ describe('Frequency', function () { } // wait a little for all of the above transactions to get queued await new Promise((resolve) => setTimeout(resolve, 1000)); - const missingNonce = await ExtrinsicHelper.getMissingNonceValues(keypairB.publicKey); + const missingNonce = await ExtrinsicHelper.getMissingNonceValues(getUnifiedPublicKey(keypairB)); assert.equal(missingNonce.length, 4, 'Could not get missing nonce values'); // applying the missing nonce values to next transactions to unblock the stuck ones diff --git a/e2e/msa/keyManagement.ethereum.test.ts b/e2e/msa/keyManagement.ethereum.test.ts new file mode 100644 index 0000000000..c66dd2f996 --- /dev/null +++ b/e2e/msa/keyManagement.ethereum.test.ts @@ -0,0 +1,122 @@ +import '@frequency-chain/api-augment'; +import assert from 'assert'; +import { + createKeys, + createAndFundKeypair, + generateAddKeyPayload, + CENTS, + signPayload, + MultiSignatureType, +} from '../scaffolding/helpers'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; +import { u64 } from '@polkadot/types'; +import { Codec } from '@polkadot/types/types'; +import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; + +const maxU64 = 18_446_744_073_709_551_615n; +const fundingSource = getFundingSource('msa-key-management-ethereum'); + +describe('MSA Key management Ethereum', function () { + describe('addPublicKeyToMsa Ethereum', function () { + let keys: KeyringPair; + let msaId: u64; + let secondaryKey: KeyringPair; + const defaultPayload: AddKeyData = {}; + let payload: AddKeyData; + let ownerSig: MultiSignatureType; + let newSig: MultiSignatureType; + let badSig: MultiSignatureType; + let addKeyData: Codec; + + before(async function () { + // Setup an MSA with one key and a secondary funded key + keys = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum'); + const { target } = await ExtrinsicHelper.createMsa(keys).signAndSend(); + assert.notEqual(target?.data.msaId, undefined, 'MSA Id not in expected event'); + msaId = target!.data.msaId; + + secondaryKey = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum'); + + // Default payload making it easier to test `addPublicKeyToMsa` + defaultPayload.msaId = msaId; + defaultPayload.newPublicKey = getUnifiedPublicKey(secondaryKey); + }); + + beforeEach(async function () { + payload = await generateAddKeyPayload(defaultPayload); + }); + + it('should fail to add public key if origin is not one of the signers of the payload (MsaOwnershipInvalidSignature) for a Ethereum key', async function () { + const badKeys: KeyringPair = createKeys(); + addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); + newSig = signPayload(secondaryKey, addKeyData); + badSig = signPayload(badKeys, addKeyData); + const op = ExtrinsicHelper.addPublicKeyToMsa(keys, badSig, newSig, payload); + await assert.rejects(op.fundAndSend(fundingSource), { + name: 'MsaOwnershipInvalidSignature', + }); + }); + + it('should fail to add public key if origin does not own MSA (NotMsaOwner) for a Ethereum key', async function () { + const newPayload = await generateAddKeyPayload({ + ...defaultPayload, + msaId: new u64(ExtrinsicHelper.api.registry, maxU64), + }); + addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload); + ownerSig = signPayload(keys, addKeyData); + newSig = signPayload(secondaryKey, addKeyData); + const op = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, newPayload); + await assert.rejects(op.fundAndSend(fundingSource), { + name: 'NotMsaOwner', + }); + }); + + it('should successfully add a new public key to an existing MSA & disallow duplicate signed payload submission (SignatureAlreadySubmitted) for a Ethereum key', async function () { + addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); + + ownerSig = signPayload(keys, addKeyData); + newSig = signPayload(secondaryKey, addKeyData); + const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload); + + const { target: publicKeyEvents } = await addPublicKeyOp.fundAndSend(fundingSource); + + assert.notEqual(publicKeyEvents, undefined, 'should have added public key'); + + await assert.rejects( + addPublicKeyOp.fundAndSend(fundingSource), + 'should reject sending the same signed payload twice' + ); + }); + + it('should fail if attempting to add the same key more than once (KeyAlreadyRegistered) for a Ethereum key', async function () { + const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); + + const ownerSig = signPayload(keys, addKeyData); + const newSig = signPayload(secondaryKey, addKeyData); + const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload); + + await assert.rejects(addPublicKeyOp.fundAndSend(fundingSource), { + name: 'KeyAlreadyRegistered', + }); + }); + + it('should allow new keypair to act for/on MSA for a Ethereum key', async function () { + const thirdKey = createKeys(); + const newPayload = await generateAddKeyPayload({ + ...defaultPayload, + newPublicKey: getUnifiedPublicKey(thirdKey), + }); + addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload); + ownerSig = signPayload(secondaryKey, addKeyData); + newSig = signPayload(thirdKey, addKeyData); + const op = ExtrinsicHelper.addPublicKeyToMsa(secondaryKey, ownerSig, newSig, newPayload); + const { target: event } = await op.fundAndSend(fundingSource); + assert.notEqual(event, undefined, 'should have added public key'); + + // Cleanup + await assert.doesNotReject(ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(thirdKey)).signAndSend()); + }); + }); +}); diff --git a/e2e/msa/msaKeyManagement.test.ts b/e2e/msa/msaKeyManagement.test.ts index 672257346f..36a3f836c8 100644 --- a/e2e/msa/msaKeyManagement.test.ts +++ b/e2e/msa/msaKeyManagement.test.ts @@ -14,6 +14,7 @@ import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; import { u64 } from '@polkadot/types'; import { Codec } from '@polkadot/types/types'; import { getFundingSource } from '../scaffolding/funding'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const maxU64 = 18_446_744_073_709_551_615n; const fundingSource = getFundingSource('msa-key-management'); @@ -41,7 +42,7 @@ describe('MSA Key management', function () { // Default payload making it easier to test `addPublicKeyToMsa` defaultPayload.msaId = msaId; - defaultPayload.newPublicKey = secondaryKey.publicKey; + defaultPayload.newPublicKey = getUnifiedPublicKey(secondaryKey); }); beforeEach(async function () { @@ -157,7 +158,7 @@ describe('MSA Key management', function () { const thirdKey = createKeys(); const newPayload = await generateAddKeyPayload({ ...defaultPayload, - newPublicKey: thirdKey.publicKey, + newPublicKey: getUnifiedPublicKey(thirdKey), }); addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload); ownerSig = signPayloadSr25519(secondaryKey, addKeyData); @@ -167,7 +168,7 @@ describe('MSA Key management', function () { assert.notEqual(event, undefined, 'should have added public key'); // Cleanup - await assert.doesNotReject(ExtrinsicHelper.deletePublicKey(keys, thirdKey.publicKey).signAndSend()); + await assert.doesNotReject(ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(thirdKey)).signAndSend()); }); }); @@ -200,7 +201,7 @@ describe('MSA Key management', function () { const payload = await generateAddKeyPayload({ msaId, - newPublicKey: secondaryKey.publicKey, + newPublicKey: getUnifiedPublicKey(secondaryKey), }); const payloadData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload); const ownerSig = signPayloadSr25519(keys, payloadData); @@ -219,7 +220,7 @@ describe('MSA Key management', function () { }); it('should fail to delete public key for self', async function () { - const op = ExtrinsicHelper.deletePublicKey(keys, keys.publicKey); + const op = ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(keys)); await assert.rejects(op.signAndSend('current'), { name: 'RpcError', message: /Custom error: 4/, @@ -229,7 +230,7 @@ describe('MSA Key management', function () { it("should fail to delete key if not authorized for key's MSA", async function () { const [providerKeys] = await createProviderKeysAndId(fundingSource); - const op = ExtrinsicHelper.deletePublicKey(providerKeys, keys.publicKey); + const op = ExtrinsicHelper.deletePublicKey(providerKeys, getUnifiedPublicKey(keys)); await assert.rejects(op.signAndSend('current'), { name: 'RpcError', message: /Custom error: 5/, @@ -238,7 +239,7 @@ describe('MSA Key management', function () { it("should test for 'NoKeyExists' error", async function () { const key = createKeys('nothing key'); - const op = ExtrinsicHelper.deletePublicKey(keys, key.publicKey); + const op = ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(key)); await assert.rejects(op.signAndSend('current'), { name: 'RpcError', message: /Custom error: 1/, @@ -246,7 +247,7 @@ describe('MSA Key management', function () { }); it('should delete secondary key', async function () { - const op = ExtrinsicHelper.deletePublicKey(keys, secondaryKey.publicKey); + const op = ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(secondaryKey)); const { target: event } = await op.signAndSend(); assert.notEqual(event, undefined, 'should have returned PublicKeyDeleted event'); }); diff --git a/e2e/passkey/passkeyProxy.ethereum.test.ts b/e2e/passkey/passkeyProxy.ethereum.test.ts index 2aa71b72e6..03daef3f2b 100644 --- a/e2e/passkey/passkeyProxy.ethereum.test.ts +++ b/e2e/passkey/passkeyProxy.ethereum.test.ts @@ -4,14 +4,13 @@ import { createAndFundKeypair, EcdsaSignature, getBlockNumber, - getNextEpochBlock, getNonce, Sr25519Signature, } from '../scaffolding/helpers'; import { KeyringPair } from '@polkadot/keyring/types'; import { ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; import { getFundingSource } from '../scaffolding/funding'; -import { getConvertedEthereumPublicKey, getUnifiedAddress } from '../scaffolding/ethereum'; +import { getUnifiedPublicKey, getUnifiedAddress } from '../scaffolding/ethereum'; import { createPassKeyAndSignAccount, createPassKeyCall, createPasskeyPayload } from '../scaffolding/P256'; import { u8aToHex, u8aWrapBytes } from '@polkadot/util'; const fundingSource = getFundingSource('passkey-proxy-ethereum'); @@ -25,12 +24,12 @@ describe('Passkey Pallet Ethereum Tests', function () { before(async function () { fundedSr25519Keys = await createAndFundKeypair(fundingSource, 300_000_000n); fundedEthereumKeys = await createAndFundKeypair(fundingSource, 300_000_000n, undefined, undefined, 'ethereum'); - receiverKeys = await createAndFundKeypair(fundingSource, undefined, undefined, undefined, 'ethereum'); + receiverKeys = await createAndFundKeypair(fundingSource); }); it('should transfer via passkeys with root sr25519 key into an ethereum style account', async function () { const initialReceiverBalance = await ExtrinsicHelper.getAccountInfo(receiverKeys); - const accountPKey = fundedSr25519Keys.publicKey; + const accountPKey = getUnifiedPublicKey(fundedSr25519Keys); const nonce = await getNonce(fundedSr25519Keys); const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( getUnifiedAddress(receiverKeys), @@ -51,7 +50,8 @@ describe('Passkey Pallet Ethereum Tests', function () { }); it('should transfer via passkeys with root ethereum style key into another one', async function () { - const accountPKey = getConvertedEthereumPublicKey(fundedEthereumKeys); + const initialReceiverBalance = await ExtrinsicHelper.getAccountInfo(receiverKeys); + const accountPKey = getUnifiedPublicKey(fundedEthereumKeys); console.log(`accountPKey ${u8aToHex(accountPKey)}`); const nonce = await getNonce(fundedEthereumKeys); const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( diff --git a/e2e/passkey/passkeyProxy.test.ts b/e2e/passkey/passkeyProxy.test.ts index 4b59e4e807..b467018aef 100644 --- a/e2e/passkey/passkeyProxy.test.ts +++ b/e2e/passkey/passkeyProxy.test.ts @@ -12,6 +12,7 @@ import { ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; import { getFundingSource } from '../scaffolding/funding'; import { u8aToHex, u8aWrapBytes } from '@polkadot/util'; import { createPassKeyAndSignAccount, createPassKeyCall, createPasskeyPayload } from '../scaffolding/P256'; +import { getUnifiedPublicKey } from '../scaffolding/ethereum'; const fundingSource = getFundingSource('passkey-proxy'); describe('Passkey Pallet Tests', function () { @@ -25,7 +26,7 @@ describe('Passkey Pallet Tests', function () { }); it('should fail due to unsupported call', async function () { - const accountPKey = fundedKeys.publicKey; + const accountPKey = getUnifiedPublicKey(fundedKeys); const nonce = await getNonce(fundedKeys); const remarksCalls = ExtrinsicHelper.api.tx.system.remark('passkey-test'); @@ -40,9 +41,9 @@ describe('Passkey Pallet Tests', function () { }); it('should fail to transfer balance due to bad account ownership proof', async function () { - const accountPKey = fundedKeys.publicKey; + const accountPKey = getUnifiedPublicKey(fundedKeys); const nonce = await getNonce(fundedKeys); - const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive(receiverKeys.publicKey, 0n); + const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedPublicKey(receiverKeys), 0n); const { passKeyPrivateKey, passKeyPublicKey, passkeySignature } = createPassKeyAndSignAccount(accountPKey); const accountSignature = fundedKeys.sign('badPasskeyPublicKey'); const multiSignature: Sr25519Signature = { Sr25519: u8aToHex(accountSignature) }; @@ -54,9 +55,9 @@ describe('Passkey Pallet Tests', function () { }); it('should fail to transfer balance due to bad passkey signature', async function () { - const accountPKey = fundedKeys.publicKey; + const accountPKey = getUnifiedPublicKey(fundedKeys); const nonce = await getNonce(fundedKeys); - const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive(receiverKeys.publicKey, 0n); + const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedPublicKey(receiverKeys), 0n); const { passKeyPrivateKey, passKeyPublicKey, passkeySignature } = createPassKeyAndSignAccount(accountPKey); const accountSignature = fundedKeys.sign(u8aWrapBytes(passKeyPublicKey)); const multiSignature: Sr25519Signature = { Sr25519: u8aToHex(accountSignature) }; @@ -68,9 +69,12 @@ describe('Passkey Pallet Tests', function () { }); it('should transfer small balance from fundedKeys to receiverKeys', async function () { - const accountPKey = fundedKeys.publicKey; + const accountPKey = getUnifiedPublicKey(fundedKeys); const nonce = await getNonce(fundedKeys); - const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive(receiverKeys.publicKey, 100_000_000n); + const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( + getUnifiedPublicKey(receiverKeys), + 100_000_000n + ); const { passKeyPrivateKey, passKeyPublicKey } = createPassKeyAndSignAccount(accountPKey); const accountSignature = fundedKeys.sign(u8aWrapBytes(passKeyPublicKey)); const multiSignature: Sr25519Signature = { Sr25519: u8aToHex(accountSignature) }; diff --git a/e2e/scaffolding/P256.ts b/e2e/scaffolding/P256.ts index 25aa16ce69..3d3fc3cbd6 100644 --- a/e2e/scaffolding/P256.ts +++ b/e2e/scaffolding/P256.ts @@ -1,5 +1,5 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; -import { base64UrlToUint8Array, Sr25519Signature, Ed25519Signature, EcdsaSignature } from './helpers'; +import { base64UrlToUint8Array, MultiSignatureType } from './helpers'; import { secp256r1 } from '@noble/curves/p256'; import { ISubmittableResult } from '@polkadot/types/types'; import { u8aWrapBytes } from '@polkadot/util'; @@ -16,7 +16,7 @@ export function createPassKeyAndSignAccount(accountPKey: Uint8Array) { export async function createPassKeyCall( accountPKey: Uint8Array, nonce: number, - accountSignature: Sr25519Signature | Ed25519Signature | EcdsaSignature, + accountSignature: MultiSignatureType, call: SubmittableExtrinsic<'rxjs', ISubmittableResult> ) { const ext_call_type = ExtrinsicHelper.api.registry.createType('Call', call); diff --git a/e2e/scaffolding/ethereum.ts b/e2e/scaffolding/ethereum.ts index 69eecf7638..4137452ac2 100644 --- a/e2e/scaffolding/ethereum.ts +++ b/e2e/scaffolding/ethereum.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-restricted-syntax */ import { KeyringPair } from '@polkadot/keyring/types'; import { encodeAddress, ethereumEncode } from '@polkadot/util-crypto'; import { hexToU8a, u8aToHex } from '@polkadot/util'; @@ -8,17 +9,44 @@ import { Keyring } from '@polkadot/api'; import { Keypair } from '@polkadot/util-crypto/types'; import { Address20MultiAddress } from './helpers'; +/** + * Returns unified 32 bytes SS58 accountId + * @param pair + */ export function getUnifiedAddress(pair: KeyringPair): string { if ('ethereum' === pair.type) { const etheAddressHex = ethereumEncode(pair.publicKey); - return getConvertedEthereumAccount(etheAddressHex); + return getSS58AccountFromEthereumAccount(etheAddressHex); } if (pair.type === 'ecdsa') { - throw new Error(`ecdsa type is not supported!`); + throw new Error('Ecdsa key type is not supported and it should be replaced with ethereum ones!'); } return pair.address; } +/** + * Returns ethereum style public key with prefixed zeros example: 0x00000000000000000000000019a701d23f0ee1748b5d5f883cb833943096c6c4 + * @param pair + */ +export function getUnifiedPublicKey(pair: KeyringPair): Uint8Array { + if ('ethereum' === pair.type) { + const publicKeyBytes = hexToU8a(ethereumEncode(pair.publicKey)); + const result = new Uint8Array(32); + result.fill(0, 0, 12); + result.set(publicKeyBytes, 12); + return result; + } + if (pair.type === 'ecdsa') { + throw new Error('Ecdsa key type is not supported and it should be replaced with ethereum ones!'); + } + return pair.publicKey; +} + +/** + * This custom signer can get used to mimic EIP-191 message signing. By replacing the `ethereumPair.sign` with + * any wallet call we can sign any extrinsic with any wallet + * @param ethereumPair + */ export function getEthereumStyleSigner(ethereumPair: KeyringPair): Signer { return { signRaw: async (payload): Promise => { @@ -35,48 +63,37 @@ export function getEthereumStyleSigner(ethereumPair: KeyringPair): Signer { } /** - * This is a helper method to allow being able to create a signature that might be created by metamask - * @param hexPayload - */ -function wrapCustomFrequencyTag(hexPayload: string): Uint8Array { - // wrapping in frequency tags to show this is a Frequency related payload - const frequencyWrapped = `${hexPayload.toLowerCase()}`; - return prefixEthereumTags(frequencyWrapped); -} - -/** - * prefixing with the EIP-191 for personal_sign messages (this gets wrapped automatically in metamask) - * @param hexPayload + * Convert a keyPair into a 20 byte ethereum address + * @param pair */ -function prefixEthereumTags(hexPayload: string): Uint8Array { - const wrapped = `\x19Ethereum Signed Message:\n${hexPayload.length}${hexPayload}`; - const buffer = Buffer.from(wrapped, 'utf-8'); - return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); -} - export function getAccountId20MultiAddress(pair: KeyringPair): Address20MultiAddress { + if (pair.type !== 'ethereum') { + throw new Error(`Only ethereum keys are supported!`); + } const etheAddress = ethereumEncode(pair.publicKey); const ethAddress20 = Array.from(hexToU8a(etheAddress)); return { Address20: ethAddress20 }; } /** - * Returns ethereum style public key with prefixed zeros example: 0x00000000000000000000000019a701d23f0ee1748b5d5f883cb833943096c6c4 - * @param pair + * + * @param secretKey of secp256k1 keypair exported from any wallet (should be 32 bytes) */ -export function getConvertedEthereumPublicKey(pair: KeyringPair): Uint8Array { - const publicKeyBytes = hexToU8a(ethereumEncode(pair.publicKey)); - const result = new Uint8Array(32); - result.fill(0, 0, 12); - result.set(publicKeyBytes, 12); - return result; +export function getKeyringPairFromSecp256k1PrivateKey(secretKey: Uint8Array): KeyringPair { + const publicKey = secp256k1.getPublicKey(secretKey, true); + const keypair: Keypair = { + secretKey, + publicKey, + }; + const keyring = new Keyring({ type: 'ethereum' }); + return keyring.addFromPair(keypair, undefined, 'ethereum'); } /** * converts an ethereum account to SS58 format * @param accountId20Hex */ -function getConvertedEthereumAccount(accountId20Hex: string): string { +function getSS58AccountFromEthereumAccount(accountId20Hex: string): string { const addressBytes = hexToU8a(accountId20Hex); const result = new Uint8Array(32); result.fill(0, 0, 12); @@ -85,15 +102,21 @@ function getConvertedEthereumAccount(accountId20Hex: string): string { } /** - * - * @param secretKey of secp256k1 keypair exported from any wallet (should be 32 bytes) + * This is a helper method to allow being able to create a signature that might be created by Metamask + * @param hexPayload */ -export function getKeyringPairFromSecp256k1PrivateKey(secretKey: Uint8Array): KeyringPair { - const publicKey = secp256k1.getPublicKey(secretKey, true); - const keypair: Keypair = { - secretKey, - publicKey, - }; - const keyring = new Keyring({ type: 'ethereum' }); - return keyring.addFromPair(keypair, undefined, 'ethereum'); +function wrapCustomFrequencyTag(hexPayload: string): Uint8Array { + // wrapping in frequency tags to show this is a Frequency related payload + const frequencyWrapped = `${hexPayload.toLowerCase()}`; + return prefixEthereumTags(frequencyWrapped); +} + +/** + * prefixing with the EIP-191 for personal_sign messages (this gets wrapped automatically in metamask) + * @param hexPayload + */ +function prefixEthereumTags(hexPayload: string): Uint8Array { + const wrapped = `\x19Ethereum Signed Message:\n${hexPayload.length}${hexPayload}`; + const buffer = Buffer.from(wrapped, 'utf-8'); + return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); } diff --git a/e2e/scaffolding/extrinsicHelpers.ts b/e2e/scaffolding/extrinsicHelpers.ts index aff5840827..3c0231dabe 100644 --- a/e2e/scaffolding/extrinsicHelpers.ts +++ b/e2e/scaffolding/extrinsicHelpers.ts @@ -6,7 +6,7 @@ import { Compact, u128, u16, u32, u64, Vec, Option, Bool } from '@polkadot/types import { FrameSystemAccountInfo, PalletPasskeyPasskeyPayload, SpRuntimeDispatchError } from '@polkadot/types/lookup'; import { AnyJson, AnyNumber, AnyTuple, Codec, IEvent, ISubmittableResult } from '@polkadot/types/types'; import { firstValueFrom, filter, map, pipe, tap } from 'rxjs'; -import { getBlockNumber, getExistentialDeposit, getFinalizedBlockNumber, log, Sr25519Signature } from './helpers'; +import { getBlockNumber, getExistentialDeposit, getFinalizedBlockNumber, log, MultiSignatureType } from './helpers'; import autoNonce, { AutoNonce } from './autoNonce'; import { connect, connectPromise } from './apiConnection'; import { DispatchError, Event, Index, SignedBlock } from '@polkadot/types/interfaces'; @@ -24,7 +24,7 @@ import { u8aToHex } from '@polkadot/util/u8a/toHex'; import { u8aWrapBytes } from '@polkadot/util'; import type { AccountId32, Call, H256 } from '@polkadot/types/interfaces/runtime'; import { hasRelayChain } from './env'; -import { getUnifiedAddress } from './ethereum'; +import { getUnifiedAddress, getUnifiedPublicKey } from './ethereum'; export interface ReleaseSchedule { start: number; @@ -234,7 +234,7 @@ export class Extrinsic { return firstValueFrom( this.extrinsic() - .paymentInfo(this.keys) + .paymentInfo(getUnifiedAddress(this.keys)) .pipe(map((info) => info.partialFee.toBigInt())) ); } @@ -479,7 +479,7 @@ export class ExtrinsicHelper { return new Extrinsic( () => ExtrinsicHelper.api.tx.schemas.createSchemaViaGovernance( - keys.publicKey, + getUnifiedPublicKey(keys), JSON.stringify(model), modelType, payloadLocation, @@ -502,7 +502,7 @@ export class ExtrinsicHelper { return new Extrinsic( () => ExtrinsicHelper.api.tx.schemas.createSchemaViaGovernanceV2( - keys.publicKey, + getUnifiedPublicKey(keys), JSON.stringify(model), modelType, payloadLocation, @@ -526,12 +526,13 @@ export class ExtrinsicHelper { public static addPublicKeyToMsa( keys: KeyringPair, - ownerSignature: Sr25519Signature, - newSignature: Sr25519Signature, + ownerSignature: MultiSignatureType, + newSignature: MultiSignatureType, payload: AddKeyData ) { return new Extrinsic( - () => ExtrinsicHelper.api.tx.msa.addPublicKeyToMsa(keys.publicKey, ownerSignature, newSignature, payload), + () => + ExtrinsicHelper.api.tx.msa.addPublicKeyToMsa(getUnifiedPublicKey(keys), ownerSignature, newSignature, payload), keys, ExtrinsicHelper.api.events.msa.PublicKeyAdded ); @@ -560,12 +561,16 @@ export class ExtrinsicHelper { public static createSponsoredAccountWithDelegation( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: AddProviderPayload ) { return new Extrinsic( () => - ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(delegatorKeys.publicKey, signature, payload), + ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation( + getUnifiedPublicKey(delegatorKeys), + signature, + payload + ), providerKeys, ExtrinsicHelper.api.events.msa.MsaCreated ); @@ -574,11 +579,11 @@ export class ExtrinsicHelper { public static grantDelegation( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: AddProviderPayload ) { return new Extrinsic( - () => ExtrinsicHelper.api.tx.msa.grantDelegation(delegatorKeys.publicKey, signature, payload), + () => ExtrinsicHelper.api.tx.msa.grantDelegation(getUnifiedPublicKey(delegatorKeys), signature, payload), providerKeys, ExtrinsicHelper.api.events.msa.DelegationGranted ); @@ -666,13 +671,13 @@ export class ExtrinsicHelper { public static applyItemActionsWithSignature( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: ItemizedSignaturePayload ) { return new Extrinsic( () => ExtrinsicHelper.api.tx.statefulStorage.applyItemActionsWithSignature( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signature, payload ), @@ -684,13 +689,13 @@ export class ExtrinsicHelper { public static applyItemActionsWithSignatureV2( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: ItemizedSignaturePayloadV2 ) { return new Extrinsic( () => ExtrinsicHelper.api.tx.statefulStorage.applyItemActionsWithSignatureV2( - delegatorKeys.publicKey, + getUnifiedPublicKey(delegatorKeys), signature, payload ), @@ -702,11 +707,16 @@ export class ExtrinsicHelper { public static deletePageWithSignature( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: PaginatedDeleteSignaturePayload ) { return new Extrinsic( - () => ExtrinsicHelper.api.tx.statefulStorage.deletePageWithSignature(delegatorKeys.publicKey, signature, payload), + () => + ExtrinsicHelper.api.tx.statefulStorage.deletePageWithSignature( + getUnifiedPublicKey(delegatorKeys), + signature, + payload + ), providerKeys, ExtrinsicHelper.api.events.statefulStorage.PaginatedPageDeleted ); @@ -715,12 +725,16 @@ export class ExtrinsicHelper { public static deletePageWithSignatureV2( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: PaginatedDeleteSignaturePayloadV2 ) { return new Extrinsic( () => - ExtrinsicHelper.api.tx.statefulStorage.deletePageWithSignatureV2(delegatorKeys.publicKey, signature, payload), + ExtrinsicHelper.api.tx.statefulStorage.deletePageWithSignatureV2( + getUnifiedPublicKey(delegatorKeys), + signature, + payload + ), providerKeys, ExtrinsicHelper.api.events.statefulStorage.PaginatedPageDeleted ); @@ -729,11 +743,16 @@ export class ExtrinsicHelper { public static upsertPageWithSignature( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: PaginatedUpsertSignaturePayload ) { return new Extrinsic( - () => ExtrinsicHelper.api.tx.statefulStorage.upsertPageWithSignature(delegatorKeys.publicKey, signature, payload), + () => + ExtrinsicHelper.api.tx.statefulStorage.upsertPageWithSignature( + getUnifiedPublicKey(delegatorKeys), + signature, + payload + ), providerKeys, ExtrinsicHelper.api.events.statefulStorage.PaginatedPageUpdated ); @@ -742,12 +761,16 @@ export class ExtrinsicHelper { public static upsertPageWithSignatureV2( delegatorKeys: KeyringPair, providerKeys: KeyringPair, - signature: Sr25519Signature, + signature: MultiSignatureType, payload: PaginatedUpsertSignaturePayloadV2 ) { return new Extrinsic( () => - ExtrinsicHelper.api.tx.statefulStorage.upsertPageWithSignatureV2(delegatorKeys.publicKey, signature, payload), + ExtrinsicHelper.api.tx.statefulStorage.upsertPageWithSignatureV2( + getUnifiedPublicKey(delegatorKeys), + signature, + payload + ), providerKeys, ExtrinsicHelper.api.events.statefulStorage.PaginatedPageUpdated ); @@ -772,7 +795,7 @@ export class ExtrinsicHelper { public static claimHandle(delegatorKeys: KeyringPair, payload: any) { const proof = { Sr25519: u8aToHex(delegatorKeys.sign(u8aWrapBytes(payload.toU8a()))) }; return new Extrinsic( - () => ExtrinsicHelper.api.tx.handles.claimHandle(delegatorKeys.publicKey, proof, payload), + () => ExtrinsicHelper.api.tx.handles.claimHandle(getUnifiedPublicKey(delegatorKeys), proof, payload), delegatorKeys, ExtrinsicHelper.api.events.handles.HandleClaimed ); diff --git a/e2e/scaffolding/funding.ts b/e2e/scaffolding/funding.ts index 927acb51e1..0f18fab281 100644 --- a/e2e/scaffolding/funding.ts +++ b/e2e/scaffolding/funding.ts @@ -21,16 +21,20 @@ export const fundingSources = [ 'capacity-unstaking', 'check-metadata-hash', 'frequency-misc', + 'frequency-balance-ethereum', 'handles', 'load-signature-registry', 'messages-add-ipfs', 'misc-util-batch', 'msa-create-msa', 'msa-key-management', + 'msa-key-management-ethereum', 'passkey-proxy', 'passkey-proxy-ethereum', + 'stateful-storage-ethereum', 'proxy-pallet', 'scenarios-grant-delegation', + 'grant-delegation-ethereum', 'schemas-create', 'stateful-storage-handle-itemized', 'stateful-storage-handle-paginated', diff --git a/e2e/scaffolding/helpers.ts b/e2e/scaffolding/helpers.ts index 733066478d..f5b081a3f2 100644 --- a/e2e/scaffolding/helpers.ts +++ b/e2e/scaffolding/helpers.ts @@ -57,6 +57,8 @@ export interface EcdsaSignature { Ecdsa: `0x${string}`; } +export type MultiSignatureType = Sr25519Signature | Ed25519Signature | EcdsaSignature; + export interface Address20MultiAddress { Address20: number[]; } @@ -79,6 +81,19 @@ export function signPayloadSr25519(keys: KeyringPair, data: Codec): Sr25519Signa return { Sr25519: u8aToHex(keys.sign(u8aWrapBytes(data.toU8a()))) }; } +export function signPayload(keys: KeyringPair, data: Codec): MultiSignatureType { + switch (keys.type) { + case 'ecdsa': + throw new Error('Ecdsa key type is not supported and it should be replaced with ethereum ones!'); + case 'sr25519': + return { Sr25519: u8aToHex(keys.sign(u8aWrapBytes(data.toU8a()))) }; + case 'ed25519': + return { Ed25519: u8aToHex(keys.sign(u8aWrapBytes(data.toU8a()))) }; + case 'ethereum': + return { Ecdsa: u8aToHex(keys.sign(data.toU8a())) }; + } +} + export async function generateDelegationPayload( payloadInputs: AddProviderPayload, expirationOffset: number = 100, @@ -148,7 +163,7 @@ export async function generateItemizedActionsPayloadAndSignature( ) { const payloadData = await generateItemizedSignaturePayload(payloadInput); const payload = ExtrinsicHelper.api.registry.createType(payloadType, payloadData); - const signature = signPayloadSr25519(signingKeys, payload); + const signature = signPayload(signingKeys, payload); return { payload: payloadData, signature }; } @@ -341,8 +356,12 @@ export async function createProviderKeysAndId(source: KeyringPair, amount?: bigi return [providerKeys, providerId]; } -export async function createDelegator(source: KeyringPair, amount?: bigint): Promise<[KeyringPair, u64]> { - const keys = await createAndFundKeypair(source, amount); +export async function createDelegator( + source: KeyringPair, + amount?: bigint, + keyType: KeypairType = 'sr25519' +): Promise<[KeyringPair, u64]> { + const keys = await createAndFundKeypair(source, amount, undefined, undefined, keyType); const createMsa = ExtrinsicHelper.createMsa(keys); const { target: msaCreatedEvent } = await createMsa.fundAndSend(source); const delegatorMsaId = msaCreatedEvent?.data.msaId || new u64(ExtrinsicHelper.api.registry, 0); @@ -354,11 +373,11 @@ export async function createDelegatorAndDelegation( source: KeyringPair, schemaId: u16 | u16[], providerId: u64, - providerKeys: KeyringPair + providerKeys: KeyringPair, + keyType: KeypairType = 'sr25519' ): Promise<[KeyringPair, u64]> { // Create a delegator msa - const [keys, delegatorMsaId] = await createDelegator(source); - + const [keys, delegatorMsaId] = await createDelegator(source, undefined, keyType); // Grant delegation to the provider const payload = await generateDelegationPayload({ authorizedMsaId: providerId, @@ -369,7 +388,7 @@ export async function createDelegatorAndDelegation( const grantDelegationOp = ExtrinsicHelper.grantDelegation( keys, providerKeys, - signPayloadSr25519(keys, addProviderData), + signPayload(keys, addProviderData), payload ); await grantDelegationOp.fundAndSend(source); @@ -666,8 +685,8 @@ export async function assertAddNewKey( newControlKeypair: KeyringPair ) { const addKeyPayloadCodec: Codec = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', addKeyPayload); - const ownerSig: Sr25519Signature = signPayloadSr25519(capacityKeys, addKeyPayloadCodec); - const newSig: Sr25519Signature = signPayloadSr25519(newControlKeypair, addKeyPayloadCodec); + const ownerSig: MultiSignatureType = signPayload(capacityKeys, addKeyPayloadCodec); + const newSig: MultiSignatureType = signPayload(newControlKeypair, addKeyPayloadCodec); const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(capacityKeys, ownerSig, newSig, addKeyPayload); const { eventMap } = await addPublicKeyOp.signAndSend(); assertEvent(eventMap, 'system.ExtrinsicSuccess'); diff --git a/e2e/scenarios/grantDelegation.ethereum.test.ts b/e2e/scenarios/grantDelegation.ethereum.test.ts new file mode 100644 index 0000000000..357a569143 --- /dev/null +++ b/e2e/scenarios/grantDelegation.ethereum.test.ts @@ -0,0 +1,183 @@ +import '@frequency-chain/api-augment'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { u16, u64 } from '@polkadot/types'; +import assert from 'assert'; +import { AddProviderPayload, Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; +import { + DOLLARS, + createAndFundKeypair, + createAndFundKeypairs, + generateDelegationPayload, + signPayload, +} from '../scaffolding/helpers'; +import { SchemaId } from '@frequency-chain/api-augment/interfaces'; +import { getFundingSource } from '../scaffolding/funding'; + +const fundingSource = getFundingSource('grant-delegation-ethereum'); + +describe('Delegation Scenario Tests Ethereum', function () { + let keys: KeyringPair; + let otherMsaKeys: KeyringPair; + let thirdMsaKeys: KeyringPair; + let noMsaKeys: KeyringPair; + let providerKeys: KeyringPair; + let otherProviderKeys: KeyringPair; + let schemaId: u16; + let schemaId2: SchemaId; + let providerId: u64; + let otherProviderId: u64; + let msaId: u64; + let otherMsaId: u64; + let thirdMsaId: u64; + + before(async function () { + // Fund all the different keys + [noMsaKeys, keys, otherMsaKeys, thirdMsaKeys, providerKeys, otherProviderKeys] = await createAndFundKeypairs( + fundingSource, + ['noMsaKeys', 'keys', 'otherMsaKeys', 'thirdMsaKeys', 'providerKeys', 'otherProviderKeys'], + 1n * DOLLARS, + 'ethereum' + ); + + const { target: msaCreatedEvent1 } = await ExtrinsicHelper.createMsa(keys).signAndSend(); + msaId = msaCreatedEvent1!.data.msaId; + + const { target: msaCreatedEvent2 } = await ExtrinsicHelper.createMsa(otherMsaKeys).signAndSend(); + otherMsaId = msaCreatedEvent2!.data.msaId; + + const { target: msaCreatedEvent3 } = await ExtrinsicHelper.createMsa(thirdMsaKeys).signAndSend(); + thirdMsaId = msaCreatedEvent3!.data.msaId; + + let createProviderMsaOp = ExtrinsicHelper.createMsa(providerKeys); + await createProviderMsaOp.signAndSend(); + let createProviderOp = ExtrinsicHelper.createProvider(providerKeys, 'MyPoster'); + let { target: providerEvent } = await createProviderOp.signAndSend(); + assert.notEqual(providerEvent, undefined, 'setup should return a ProviderCreated event'); + providerId = providerEvent!.data.providerId; + + createProviderMsaOp = ExtrinsicHelper.createMsa(otherProviderKeys); + await createProviderMsaOp.signAndSend(); + createProviderOp = ExtrinsicHelper.createProvider(otherProviderKeys, 'MyPoster'); + ({ target: providerEvent } = await createProviderOp.signAndSend()); + assert.notEqual(providerEvent, undefined, 'setup should return a ProviderCreated event'); + otherProviderId = providerEvent!.data.providerId; + + const schema = { + type: 'record', + name: 'Post', + fields: [ + { name: 'title', type: { name: 'Title', type: 'string' } }, + { name: 'content', type: { name: 'Content', type: 'string' } }, + { name: 'fromId', type: { name: 'DSNPId', type: 'fixed', size: 8 } }, + { name: 'objectId', type: 'DSNPId' }, + ], + }; + + schemaId = await ExtrinsicHelper.getOrCreateSchemaV3( + keys, + schema, + 'AvroBinary', + 'OnChain', + [], + 'test.grantDelegation' + ); + + schemaId2 = await ExtrinsicHelper.getOrCreateSchemaV3( + keys, + schema, + 'AvroBinary', + 'OnChain', + [], + 'test.grantDelegationSecond' + ); + }); + + describe('delegation grants for a Ethereum key', function () { + it('should fail to grant delegation if payload not signed by delegator (AddProviderSignatureVerificationFailed)', async function () { + const payload = await generateDelegationPayload({ + authorizedMsaId: providerId, + schemaIds: [schemaId], + }); + const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload); + + const grantDelegationOp = ExtrinsicHelper.grantDelegation( + keys, + providerKeys, + signPayload(providerKeys, addProviderData), + payload + ); + await assert.rejects(grantDelegationOp.fundAndSend(fundingSource), { + name: 'AddProviderSignatureVerificationFailed', + }); + }); + + it('should fail to grant delegation if ID in payload does not match origin (UnauthorizedDelegator)', async function () { + const payload = await generateDelegationPayload({ + authorizedMsaId: otherMsaId, + schemaIds: [schemaId], + }); + const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload); + + const grantDelegationOp = ExtrinsicHelper.grantDelegation( + keys, + providerKeys, + signPayload(keys, addProviderData), + payload + ); + await assert.rejects(grantDelegationOp.fundAndSend(fundingSource), { name: 'UnauthorizedDelegator' }); + }); + + it('should grant a delegation to a provider', async function () { + const payload = await generateDelegationPayload({ + authorizedMsaId: providerId, + schemaIds: [schemaId], + }); + const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload); + + const grantDelegationOp = ExtrinsicHelper.grantDelegation( + keys, + providerKeys, + signPayload(keys, addProviderData), + payload + ); + const { target: grantDelegationEvent } = await grantDelegationOp.fundAndSend(fundingSource); + assert.notEqual(grantDelegationEvent, undefined, 'should have returned DelegationGranted event'); + assert.deepEqual(grantDelegationEvent?.data.providerId, providerId, 'provider IDs should match'); + assert.deepEqual(grantDelegationEvent?.data.delegatorId, msaId, 'delegator IDs should match'); + }); + }); + + describe('createSponsoredAccountWithDelegation', function () { + let sponsorKeys: KeyringPair; + let op: Extrinsic; + let defaultPayload: AddProviderPayload; + + before(async function () { + sponsorKeys = await createAndFundKeypair(fundingSource, 50_000_000n, undefined, undefined, 'ethereum'); + defaultPayload = { + authorizedMsaId: providerId, + schemaIds: [schemaId], + }; + }); + + it('should successfully create a delegated account', async function () { + const payload = await generateDelegationPayload(defaultPayload); + const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload); + + op = ExtrinsicHelper.createSponsoredAccountWithDelegation( + sponsorKeys, + providerKeys, + signPayload(sponsorKeys, addProviderData), + payload + ); + const { target: event, eventMap } = await op.fundAndSend(fundingSource); + assert.notEqual(event, undefined, 'should have returned MsaCreated event'); + assert.notEqual(eventMap['msa.DelegationGranted'], undefined, 'should have returned DelegationGranted event'); + await assert.rejects( + op.fundAndSend(fundingSource), + { name: 'SignatureAlreadySubmitted' }, + 'should reject double submission' + ); + }); + }); +}); diff --git a/e2e/stateful-pallet-storage/stateful.ethereum.test.ts b/e2e/stateful-pallet-storage/stateful.ethereum.test.ts new file mode 100644 index 0000000000..9cbe260efc --- /dev/null +++ b/e2e/stateful-pallet-storage/stateful.ethereum.test.ts @@ -0,0 +1,193 @@ +// E2E tests for pallets/stateful-pallet-storage/handleItemizedWithSignature.ts +import '@frequency-chain/api-augment'; +import assert from 'assert'; +import { + DOLLARS, + createDelegatorAndDelegation, + createProviderKeysAndId, + generateItemizedActions, + generateItemizedActionsSignedPayloadV2, + generatePaginatedDeleteSignaturePayloadV2, + generatePaginatedUpsertSignaturePayloadV2, + getCurrentPaginatedHash, + signPayload, +} from '../scaffolding/helpers'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; +import { AVRO_CHAT_MESSAGE } from '../stateful-pallet-storage/fixtures/itemizedSchemaType'; +import { MessageSourceId, SchemaId } from '@frequency-chain/api-augment/interfaces'; +import { Bytes, u16 } from '@polkadot/types'; +import { getFundingSource } from '../scaffolding/funding'; + +const fundingSource = getFundingSource('stateful-storage-ethereum'); + +describe('📗 Stateful Pallet Storage Ethereum', function () { + let itemizedSchemaId: SchemaId; + let paginatedSchemaId: SchemaId; + let msa_id: MessageSourceId; + let undelegatedProviderId: MessageSourceId; + let undelegatedProviderKeys: KeyringPair; + let delegatedProviderId: MessageSourceId; + let delegatedProviderKeys: KeyringPair; + let ethereumDelegatorKeys: KeyringPair; + + before(async function () { + // Create a provider. This provider will NOT be granted delegations; + // methods requiring a payload signature do not require a delegation + [undelegatedProviderKeys, undelegatedProviderId] = await createProviderKeysAndId(fundingSource, 2n * DOLLARS); + assert.notEqual(undelegatedProviderId, undefined, 'setup should populate undelegatedProviderId'); + assert.notEqual(undelegatedProviderKeys, undefined, 'setup should populate undelegatedProviderKeys'); + + // Create a provider for the MSA, the provider will be used to grant delegation + [delegatedProviderKeys, delegatedProviderId] = await createProviderKeysAndId(fundingSource, 2n * DOLLARS); + assert.notEqual(delegatedProviderId, undefined, 'setup should populate delegatedProviderId'); + assert.notEqual(delegatedProviderKeys, undefined, 'setup should populate delegatedProviderKeys'); + + // Create a schema for Itemized PayloadLocation + itemizedSchemaId = await ExtrinsicHelper.getOrCreateSchemaV3( + undelegatedProviderKeys, + AVRO_CHAT_MESSAGE, + 'AvroBinary', + 'Itemized', + ['AppendOnly', 'SignatureRequired'], + 'test.ItemizedSignatureRequired' + ); + + // Create a schema for Paginated PayloadLocation + paginatedSchemaId = await ExtrinsicHelper.getOrCreateSchemaV3( + undelegatedProviderKeys, + AVRO_CHAT_MESSAGE, + 'AvroBinary', + 'Paginated', + ['SignatureRequired'], + 'test.PaginatedSignatureRequired' + ); + + // Create a MSA for the delegator + [ethereumDelegatorKeys, msa_id] = await createDelegatorAndDelegation( + fundingSource, + [itemizedSchemaId, paginatedSchemaId], + delegatedProviderId, + delegatedProviderKeys, + 'ethereum' + ); + console.log('after createDelegatorAndDelegation'); + assert.notEqual(ethereumDelegatorKeys, undefined, 'setup should populate delegator_key'); + assert.notEqual(msa_id, undefined, 'setup should populate msa_id'); + }); + + describe('Itemized With Signature Storage Tests', function () { + it('provider should be able to call applyItemizedActionWithSignatureV2 and apply actions with Ethereum keys', async function () { + const { payload, signature } = await generateItemizedActionsSignedPayloadV2( + generateItemizedActions([ + { action: 'Add', value: 'Hello, world from Frequency' }, + { action: 'Add', value: 'Hello, world again from Frequency' }, + ]), + itemizedSchemaId, + ethereumDelegatorKeys, + msa_id + ); + + const itemized_add_result_1 = ExtrinsicHelper.applyItemActionsWithSignatureV2( + ethereumDelegatorKeys, + undelegatedProviderKeys, + signature, + payload + ); + const { target: pageUpdateEvent1, eventMap: chainEvents } = + await itemized_add_result_1.fundAndSend(fundingSource); + assert.notEqual( + chainEvents['system.ExtrinsicSuccess'], + undefined, + 'should have returned an ExtrinsicSuccess event' + ); + assert.notEqual( + chainEvents['transactionPayment.TransactionFeePaid'], + undefined, + 'should have returned a TransactionFeePaid event' + ); + assert.notEqual( + pageUpdateEvent1, + undefined, + 'should have returned a PalletStatefulStorageItemizedActionApplied event' + ); + }); + }); + + describe('Paginated With Signature Storage Tests with Ethereum keys', function () { + it('provider should be able to call upsertPageWithSignatureV2 a page and deletePageWithSignatureV2 it successfully with Ethereum keys', async function () { + const page_id = new u16(ExtrinsicHelper.api.registry, 1); + + // Add and update actions + let target_hash = await getCurrentPaginatedHash(msa_id, paginatedSchemaId, page_id.toNumber()); + const upsertPayload = await generatePaginatedUpsertSignaturePayloadV2({ + targetHash: target_hash, + schemaId: paginatedSchemaId, + pageId: page_id, + payload: new Bytes(ExtrinsicHelper.api.registry, 'Hello World From Frequency'), + }); + const upsertPayloadData = ExtrinsicHelper.api.registry.createType( + 'PalletStatefulStoragePaginatedUpsertSignaturePayloadV2', + upsertPayload + ); + const upsert_result = ExtrinsicHelper.upsertPageWithSignatureV2( + ethereumDelegatorKeys, + undelegatedProviderKeys, + signPayload(ethereumDelegatorKeys, upsertPayloadData), + upsertPayload + ); + const { target: pageUpdateEvent, eventMap: chainEvents1 } = await upsert_result.fundAndSend(fundingSource); + assert.notEqual( + chainEvents1['system.ExtrinsicSuccess'], + undefined, + 'should have returned an ExtrinsicSuccess event' + ); + assert.notEqual( + chainEvents1['transactionPayment.TransactionFeePaid'], + undefined, + 'should have returned a TransactionFeePaid event' + ); + assert.notEqual( + pageUpdateEvent, + undefined, + 'should have returned a PalletStatefulStoragePaginatedPageUpdate event' + ); + + // Remove the page + target_hash = await getCurrentPaginatedHash(msa_id, paginatedSchemaId, page_id.toNumber()); + const deletePayload = await generatePaginatedDeleteSignaturePayloadV2({ + targetHash: target_hash, + schemaId: paginatedSchemaId, + pageId: page_id, + }); + const deletePayloadData = ExtrinsicHelper.api.registry.createType( + 'PalletStatefulStoragePaginatedDeleteSignaturePayloadV2', + deletePayload + ); + const remove_result = ExtrinsicHelper.deletePageWithSignatureV2( + ethereumDelegatorKeys, + undelegatedProviderKeys, + signPayload(ethereumDelegatorKeys, deletePayloadData), + deletePayload + ); + const { target: pageRemove, eventMap: chainEvents2 } = await remove_result.fundAndSend(fundingSource); + assert.notEqual( + chainEvents2['system.ExtrinsicSuccess'], + undefined, + 'should have returned an ExtrinsicSuccess event' + ); + assert.notEqual( + chainEvents2['transactionPayment.TransactionFeePaid'], + undefined, + 'should have returned a TransactionFeePaid event' + ); + assert.notEqual(pageRemove, undefined, 'should have returned a event'); + + // no pages should exist + const result = await ExtrinsicHelper.getPaginatedStorage(msa_id, paginatedSchemaId); + assert.notEqual(result, undefined, 'should have returned a valid response'); + const thePage = result.toArray().find((page) => page.page_id === page_id); + assert.equal(thePage, undefined, 'inserted page should not exist'); + }); + }); +}); From e95a823d06e764b5b2ded1c886bb76a18d97c8e1 Mon Sep 17 00:00:00 2001 From: Aramik Date: Fri, 22 Nov 2024 15:42:03 -0800 Subject: [PATCH 3/3] added migrations for key fix (#2226) # Goal The goal of this PR is Closes #2227 # Details - The mainnet will be migrated as all other migrations since it is small enough that would easily fit into a block via ```rust pallet_stateful_storage::migration::v1::MigrateToV1 ``` - For testnet we will use the same path as block just to mark the ```rust Pallet::::on_chain_storage_version(); ``` but the actual multi-block migration is using `on_initialize` hook and a new storage item called `MigrationPageIndex` that would store the progress. # Verification - There are issues with try-runtime that doesn't allow me to run it against mainnet or testnet. Added some tests to verify the changes. # Checklist - [x] Unit Tests added? - [x] Spec version incremented? --- .github/workflows/verify-pr-commit.yml | 3 +- Cargo.lock | 1 + .../src/migration/provider_boost_init.rs | 2 + pallets/stateful-storage/Cargo.toml | 3 +- pallets/stateful-storage/src/lib.rs | 31 ++- pallets/stateful-storage/src/migration/mod.rs | 2 + pallets/stateful-storage/src/migration/v1.rs | 258 ++++++++++++++++++ .../src/tests/migrations_tests.rs | 104 +++++++ pallets/stateful-storage/src/tests/mock.rs | 23 +- pallets/stateful-storage/src/tests/mod.rs | 1 + pallets/stateful-storage/src/types.rs | 4 + runtime/frequency/src/lib.rs | 8 +- 12 files changed, 430 insertions(+), 10 deletions(-) create mode 100644 pallets/stateful-storage/src/migration/mod.rs create mode 100644 pallets/stateful-storage/src/migration/v1.rs create mode 100644 pallets/stateful-storage/src/tests/migrations_tests.rs diff --git a/.github/workflows/verify-pr-commit.yml b/.github/workflows/verify-pr-commit.yml index 30366d00cc..3f02924244 100644 --- a/.github/workflows/verify-pr-commit.yml +++ b/.github/workflows/verify-pr-commit.yml @@ -181,9 +181,10 @@ jobs: steps: - name: Check Out Repo uses: actions/checkout@v4 + # using older version of cargo deny since the new one requires rustc version >= 1.81 - name: Set Up Cargo Deny run: | - cargo install --force --locked cargo-deny + cargo install --force --locked cargo-deny@0.16.1 cargo generate-lockfile - name: Run Cargo Deny run: cargo deny check --hide-inclusion-graph -c deny.toml diff --git a/Cargo.lock b/Cargo.lock index b79199c0f1..5d0de21e55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7831,6 +7831,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "hex", "log", "parity-scale-codec", "pretty_assertions", diff --git a/pallets/capacity/src/migration/provider_boost_init.rs b/pallets/capacity/src/migration/provider_boost_init.rs index 3a4747beda..a1e30d2d02 100644 --- a/pallets/capacity/src/migration/provider_boost_init.rs +++ b/pallets/capacity/src/migration/provider_boost_init.rs @@ -3,6 +3,8 @@ use frame_support::{ pallet_prelude::Weight, traits::{Get, OnRuntimeUpgrade}, }; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; diff --git a/pallets/stateful-storage/Cargo.toml b/pallets/stateful-storage/Cargo.toml index ec862e836d..ac2f9d8dbc 100644 --- a/pallets/stateful-storage/Cargo.toml +++ b/pallets/stateful-storage/Cargo.toml @@ -33,6 +33,7 @@ common-runtime = { path = "../../runtime/common", default-features = false } env_logger = { workspace = true } pretty_assertions = { workspace = true } sp-keystore = { workspace = true } +hex = { workspace = true, default-features = false, features = ["alloc"] } [features] default = ['std'] @@ -57,4 +58,4 @@ std = [ "common-runtime/std", ] try-runtime = ['frame-support/try-runtime'] -test = [] \ No newline at end of file +test = [] diff --git a/pallets/stateful-storage/src/lib.rs b/pallets/stateful-storage/src/lib.rs index 9bb27e8867..dab6c14568 100644 --- a/pallets/stateful-storage/src/lib.rs +++ b/pallets/stateful-storage/src/lib.rs @@ -36,7 +36,8 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] use common_primitives::benchmarks::{MsaBenchmarkHelper, SchemaBenchmarkHelper}; use sp_std::prelude::*; - +/// storage migrations +pub mod migration; mod stateful_child_tree; pub mod types; pub mod weights; @@ -60,6 +61,8 @@ use sp_core::{bounded::BoundedVec, crypto::AccountId32}; use sp_runtime::{traits::Convert, DispatchError, MultiSignature}; pub use weights::*; +const LOG_TARGET: &str = "runtime::stateful-storage"; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -124,8 +127,13 @@ pub mod pallet { // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and // method. #[pallet::pallet] + #[pallet::storage_version(STATEFUL_STORAGE_VERSION)] pub struct Pallet(_); + /// A temporary storage for migration + #[pallet::storage] + pub(super) type MigrationPageIndex = StorageValue<_, u32, ValueQuery>; + #[pallet::error] pub enum Error { /// Page would exceed the highest allowable PageId @@ -220,6 +228,27 @@ pub mod pallet { }, } + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_current: BlockNumberFor) -> Weight { + // this should get removed after rolling out to testnet + #[cfg(any(feature = "frequency-testnet", test))] + { + let page_index = >::get(); + let (weight, continue_migration) = migration::v1::paginated_migration_testnet::( + MIGRATION_PAGE_SIZE, + page_index, + ); + if continue_migration { + >::set(page_index.saturating_add(1)); + } + T::DbWeight::get().reads_writes(1, 1).saturating_add(weight) + } + #[cfg(not(any(feature = "frequency-testnet", test)))] + Weight::zero() + } + } + #[pallet::call] impl Pallet { /// Applies the Add or Delete Actions on the requested Itemized page. diff --git a/pallets/stateful-storage/src/migration/mod.rs b/pallets/stateful-storage/src/migration/mod.rs new file mode 100644 index 0000000000..5d89e038e1 --- /dev/null +++ b/pallets/stateful-storage/src/migration/mod.rs @@ -0,0 +1,2 @@ +/// migrations to v1 +pub mod v1; diff --git a/pallets/stateful-storage/src/migration/v1.rs b/pallets/stateful-storage/src/migration/v1.rs new file mode 100644 index 0000000000..66ad4a6111 --- /dev/null +++ b/pallets/stateful-storage/src/migration/v1.rs @@ -0,0 +1,258 @@ +#[cfg(feature = "try-runtime")] +use crate::types::STATEFUL_STORAGE_VERSION; +use crate::{ + stateful_child_tree::StatefulChildTree, + types::{ + ItemAction, ItemizedKey, ItemizedOperations, ItemizedPage, Page, ITEMIZED_STORAGE_PREFIX, + PALLET_STORAGE_PREFIX, + }, + Config, Pallet, LOG_TARGET, +}; +use common_primitives::{ + msa::MessageSourceId, + utils::{get_chain_type_by_genesis_hash, DetectedChainType}, +}; +use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight}; +use frame_system::pallet_prelude::BlockNumberFor; +use log; +#[cfg(feature = "try-runtime")] +use sp_core::hexdisplay::HexDisplay; +use sp_runtime::Saturating; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; +use sp_std::{vec, vec::Vec}; + +/// testnet specific msa ids for migration +#[cfg(any(feature = "frequency-testnet", test))] +pub fn get_testnet_msa_ids() -> Vec { + vec![ + 8004, 8009, 8816, 8817, 8818, 8819, 8820, 8822, 8823, 8824, 8825, 8826, 9384, 9753, 9919, + 9992, 9994, 9996, 9997, 10009, 10010, 10012, 10013, 10014, 10015, 10019, 10020, 10021, + 10022, 10023, 10024, 10025, 10026, 10027, 10028, 10029, 10030, 10031, 10032, 10033, 10034, + 10035, 10036, 10037, 10038, 10039, 10040, 10041, 10042, 10043, 10044, 10045, 10046, 10047, + 10048, 10049, 10050, 10051, 10052, 10053, 10054, 10055, 10056, 10057, 10058, 10059, 10061, + 10062, 10064, 10067, 10068, 10069, 10070, 10071, 10072, 10075, 10076, 10077, 10078, 10079, + 10138, 10139, 10140, 10206, 10207, 10209, 10212, 10218, 10219, 10220, 10221, 10222, 10223, + 10224, 10231, 10232, 10233, 10234, 10235, 10236, 10237, 10238, 10239, 10240, 10241, 10242, + 10243, 10247, 10248, 10251, 10253, 10254, 10255, 10256, 10257, 10258, 10259, 10260, 10261, + 10262, 10263, 10264, 10265, 10266, 10267, 10268, 10269, 10270, 10271, 10272, 10273, 10274, + 10275, 10287, 10288, 10289, 10290, 10291, 10292, 10293, 10294, 10295, 10296, 10297, 10298, + 10299, 10300, 10301, 10302, 10303, 10304, 10305, 10306, 10307, 10308, 10309, 10311, 10312, + 10313, 10314, 10315, 10316, 10317, 10318, 10319, 10320, 10321, 10322, 10323, 10324, 10325, + 10326, 10327, 10328, 10329, + ] +} + +/// returns the chain type from genesis hash +pub fn get_chain_type() -> DetectedChainType { + let genesis_block: BlockNumberFor = 0u32.into(); + let genesis = >::block_hash(genesis_block); + get_chain_type_by_genesis_hash(&genesis.encode()[..]) +} + +/// get the msa ids with key migrations +pub fn get_msa_ids() -> Vec { + let chain_type = get_chain_type::(); + if let DetectedChainType::FrequencyMainNet = chain_type { + vec![ + 227, 542, 1249820, 1287729, 1288925, 1309067, 1309241, 1309258, 1309367, 1309397, + 1329112, 1329535, 1330067, + ] + } else { + if cfg!(test) { + // this allows to test the mainnet path + vec![1] + } else { + // we are going to use hooks for this multi-block migration so this is empty to only flag that + // it as done for consistency + vec![] + } + } +} + +/// migration to v1 implementation +pub struct MigrateToV1(PhantomData); + +impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + migrate_to_v1::() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + log::info!(target: LOG_TARGET, "Running pre_upgrade..."); + let on_chain_version = Pallet::::on_chain_storage_version(); + let genesis_block: BlockNumberFor = 0u32.into(); + let genesis = >::block_hash(genesis_block); + if on_chain_version >= 1 { + return Ok(Vec::new()) + } + log::info!(target: LOG_TARGET, "Found genesis... {:?}", genesis); + let detected_chain = get_chain_type_by_genesis_hash(&genesis.encode()[..]); + log::info!(target: LOG_TARGET,"Detected Chain is {:?}", detected_chain); + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + log::info!(target: LOG_TARGET, "Running post_upgrade..."); + let on_chain_version = Pallet::::on_chain_storage_version(); + if on_chain_version > 1 { + return Ok(()) + } + let onchain_version = Pallet::::on_chain_storage_version(); + assert_eq!(onchain_version, STATEFUL_STORAGE_VERSION); + // check to ensure updates took place + let schema_id = get_schema_id(); + let msa_ids = get_msa_ids::(); + for msa_id in msa_ids.into_iter() { + let itemized: ItemizedPage = Pallet::::get_itemized_page_for(msa_id, schema_id) + .map_err(|_| TryRuntimeError::Other("can not get storage"))? + .ok_or(TryRuntimeError::Other("no storage"))?; + let (_, val) = as ItemizedOperations>::try_parse( + &itemized, false, + ) + .map_err(|_| TryRuntimeError::Other("can not parse storage"))? + .items + .clone() + .into_iter() + .next() + .ok_or(TryRuntimeError::Other("no item"))?; + + assert_eq!(val.len(), 33); + log::info!(target: LOG_TARGET, "{:?}", HexDisplay::from(&val)); + } + log::info!(target: LOG_TARGET, "Finished post_upgrade"); + Ok(()) + } +} + +/// migrating to v1 +pub fn migrate_to_v1() -> Weight { + log::info!(target: LOG_TARGET, "Running storage migration..."); + let onchain_version = Pallet::::on_chain_storage_version(); + let current_version = Pallet::::in_code_storage_version(); + log::info!(target: LOG_TARGET, "onchain_version= {:?}, current_version={:?}", onchain_version, current_version); + if onchain_version < 1 { + let msa_ids = get_msa_ids::(); + let weights = migrate_msa_ids::(&msa_ids[..]); + // Set storage version to `1`. + StorageVersion::new(1).put::>(); + let total_weight = T::DbWeight::get().writes(1).saturating_add(weights); + log::info!(target: LOG_TARGET, "Migration Calculated weights={:?}",total_weight); + total_weight + } else { + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed onchain:{:?}, current:{:?}", + onchain_version, + current_version + ); + T::DbWeight::get().reads(1) + } +} + +/// migrating all msa_ids +pub fn migrate_msa_ids(msa_ids: &[MessageSourceId]) -> Weight { + let schema_id = get_schema_id(); + let key: ItemizedKey = (schema_id,); + let each_layer_access: u64 = 33 * 16; + let mut reads = 1u64; + let mut writes = 0u64; + let mut bytes = 0u64; + + for msa_id in msa_ids.iter() { + reads.saturating_inc(); + // get the itemized storages + let itemized_result: Result>, _> = + Pallet::::get_itemized_page_for(*msa_id, schema_id); + match itemized_result { + Ok(Some(existing_page)) => { + bytes = bytes.saturating_add(existing_page.encode().len() as u64); + bytes = bytes.saturating_add(each_layer_access * 3); // three layers in merkle tree + + match as ItemizedOperations>::try_parse( + &existing_page, + false, + ) { + Ok(parsed_page) => match parsed_page.items.clone().into_iter().next() { + Some((_, existing_value)) => match existing_value.len() { + 32usize => { + // 64 is decimal value for 0x40 + let mut prefixed = vec![64u8]; + prefixed.extend_from_slice(existing_value); + let bounded: BoundedVec = + prefixed.try_into().unwrap_or_default(); + + let empty_page = ItemizedPage::::default(); + match ::MaxItemizedPageSizeBytes> as ItemizedOperations>::apply_item_actions(&empty_page,&vec![ItemAction::Add { + data: bounded, + }]) { + Ok(mut updated_page) => { + updated_page.nonce = existing_page.nonce; + StatefulChildTree::::write( + msa_id, + PALLET_STORAGE_PREFIX, + ITEMIZED_STORAGE_PREFIX, + &key, + &updated_page, + ); + bytes = bytes.saturating_add(updated_page.encode().len() as u64); + writes.saturating_inc(); + }, + Err(e) => + log::error!(target: LOG_TARGET, "Error appending prefixed value {:?} and schema_id {:?} with {:?}", msa_id, schema_id, e), + } + }, + 33usize => + log::warn!(target: LOG_TARGET, "Itemized page item for msa_id {:?} and schema_id {:?} has correct size", msa_id, schema_id), + _ => + log::warn!(target: LOG_TARGET, "Itemized page item for msa_id {:?} and schema_id {:?} has invalid size {:?}", msa_id, schema_id, existing_value.len()), + }, + None => + log::warn!(target: LOG_TARGET, "Itemized page was empty for msa_id {:?} and schema_id {:?}", msa_id, schema_id), + }, + Err(e) => + log::error!(target: LOG_TARGET, "Error parsing page for msa_id {:?} and schema_id {:?} with {:?}", msa_id, schema_id, e), + } + }, + Ok(None) => + log::warn!(target: LOG_TARGET, "No page found for msa_id {:?} and schema_id {:?}", msa_id, schema_id), + Err(e) => + log::error!(target: LOG_TARGET, "Error getting the page for msa_id {:?} and schema_id {:?} with {:?}", msa_id, schema_id, e), + } + } + log::info!(target: LOG_TARGET, "Storage migrated to version 1 read={:?}, write={:?}, bytes={:?}", reads, writes, bytes); + let weights = T::DbWeight::get().reads_writes(reads, writes).add_proof_size(bytes); + log::info!(target: LOG_TARGET, "migrate_msa_ids weights={:?}",weights); + weights +} + +/// paginated migration for testnet +#[cfg(any(feature = "frequency-testnet", test))] +pub fn paginated_migration_testnet(page_size: u32, page_index: u32) -> (Weight, bool) { + let msa_ids: Vec = get_testnet_msa_ids(); + let mut chunks = msa_ids.chunks(page_size as usize); + let chunk_len = chunks.len() as u32; + let mut current = 0u32; + while current < page_index && current < chunk_len { + let _ = chunks.next(); + current += 1; + } + match chunks.next() { + Some(page) => { + let weight = migrate_msa_ids::(page); + (weight, true) + }, + None => (Weight::zero(), false), + } +} + +fn get_schema_id() -> u16 { + if cfg!(test) { + // Supported ITEMIZED_APPEND_ONLY_SCHEMA for tests + 103 + } else { + 7 + } +} diff --git a/pallets/stateful-storage/src/tests/migrations_tests.rs b/pallets/stateful-storage/src/tests/migrations_tests.rs new file mode 100644 index 0000000000..313f0ae76f --- /dev/null +++ b/pallets/stateful-storage/src/tests/migrations_tests.rs @@ -0,0 +1,104 @@ +use crate::{ + migration::{v1, v1::get_testnet_msa_ids}, + pallet::MigrationPageIndex, + test_common::constants::ITEMIZED_APPEND_ONLY_SCHEMA, + tests::mock::{ + new_test_ext, run_to_block, test_public, RuntimeOrigin, StatefulStoragePallet, Test, + }, + types::{ItemAction, MIGRATION_PAGE_SIZE}, +}; +use common_primitives::stateful_storage::PageHash; +use frame_support::{ + assert_ok, pallet_prelude::StorageVersion, traits::GetStorageVersion, BoundedVec, +}; + +#[test] +fn migration_to_v1_should_work_as_expected() { + new_test_ext().execute_with(|| { + // arrange + let msa_id = 1; + let caller_1 = test_public(msa_id); + let schema_id = ITEMIZED_APPEND_ONLY_SCHEMA; + let payload = + hex::decode("0e0abc9afdfb34cf30c59d16bbbbd76cae1668fc331eb9e505cb0d6af6365f17") + .expect("should decode hex"); + let expected = + hex::decode("400e0abc9afdfb34cf30c59d16bbbbd76cae1668fc331eb9e505cb0d6af6365f17") + .expect("should decode hex"); + let prev_content_hash: PageHash = 0; + let actions = vec![ItemAction::Add { data: payload.try_into().unwrap() }]; + + // act + assert_ok!(StatefulStoragePallet::apply_item_actions( + RuntimeOrigin::signed(caller_1), + msa_id, + schema_id, + prev_content_hash, + BoundedVec::try_from(actions).unwrap(), + )); + + // Act + let _ = v1::migrate_to_v1::(); + + // Assert + let current_version = StatefulStoragePallet::on_chain_storage_version(); + assert_eq!(current_version, StorageVersion::new(1)); + + let known_msa_ids = v1::get_msa_ids::(); + assert_eq!(known_msa_ids.len(), 1); + + let after_update = + StatefulStoragePallet::get_itemized_storage(msa_id, schema_id).expect("should get"); + let item = after_update.items.into_iter().next().expect("should item exists"); + assert_eq!(item.payload, expected); + }); +} + +#[test] +fn migration_to_v1_should_work_on_test_net_and_multi_block_path() { + new_test_ext().execute_with(|| { + // arrange + let msa_ids = get_testnet_msa_ids(); + let schema_id = ITEMIZED_APPEND_ONLY_SCHEMA; + let payload = + hex::decode("0e0abc9afdfb34cf30c59d16bbbbd76cae1668fc331eb9e505cb0d6af6365f17") + .expect("should decode hex"); + let expected = + hex::decode("400e0abc9afdfb34cf30c59d16bbbbd76cae1668fc331eb9e505cb0d6af6365f17") + .expect("should decode hex"); + let prev_content_hash: PageHash = 0; + let actions = vec![ItemAction::Add { data: payload.try_into().unwrap() }]; + for msa_id in msa_ids.iter() { + let caller_1 = test_public(*msa_id); + assert_ok!(StatefulStoragePallet::apply_item_actions( + RuntimeOrigin::signed(caller_1), + *msa_id, + schema_id, + prev_content_hash, + BoundedVec::try_from(actions.clone()).unwrap(), + )); + } + let msa_id_len = msa_ids.len() as u32; + + // Act + let _ = v1::migrate_to_v1::(); + + let blocks = msa_id_len / MIGRATION_PAGE_SIZE + 5; + for b in 2..=blocks { + run_to_block(b); + } + + // Assert + let current_version = StatefulStoragePallet::on_chain_storage_version(); + assert_eq!(current_version, StorageVersion::new(1)); + + for msa_id in msa_ids { + let after_update = + StatefulStoragePallet::get_itemized_storage(msa_id, schema_id).expect("should get"); + let item = after_update.items.into_iter().next().expect("should item exists"); + assert_eq!(item.payload, expected); + } + + assert_eq!(MigrationPageIndex::::get(), msa_id_len / MIGRATION_PAGE_SIZE + 1); + }); +} diff --git a/pallets/stateful-storage/src/tests/mock.rs b/pallets/stateful-storage/src/tests/mock.rs index 5810f40460..f7059447b4 100644 --- a/pallets/stateful-storage/src/tests/mock.rs +++ b/pallets/stateful-storage/src/tests/mock.rs @@ -16,10 +16,11 @@ use common_primitives::{ SchemaSetting, }, }; +use common_runtime::weights::rocksdb_weights::constants::RocksDbWeight; use frame_support::{ dispatch::DispatchResult, parameter_types, - traits::{ConstU16, ConstU32}, + traits::{ConstU16, ConstU32, OnFinalize, OnInitialize}, Twox128, }; use frame_system as system; @@ -32,7 +33,7 @@ use sp_runtime::{ type Block = frame_system::mocking::MockBlockU32; pub const INVALID_SCHEMA_ID: SchemaId = SchemaId::MAX; -pub const INVALID_MSA_ID: MessageSourceId = 100; +pub const INVALID_MSA_ID: MessageSourceId = 100_000_000; pub const TEST_ACCOUNT_SEED: [u8; 32] = [0; 32]; // Configure a mock runtime to test the pallet. @@ -48,7 +49,7 @@ impl system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type DbWeight = (); + type DbWeight = RocksDbWeight; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Nonce = u64; @@ -406,7 +407,9 @@ fn get_signature_benchmarks_public_account() -> sr25519::Public { } pub fn test_public(n: MessageSourceId) -> AccountId32 { - AccountId32::new([n as u8; 32]) + let mut array = [0u8; 32]; + array[0..8].copy_from_slice(&n.to_le_bytes()); + AccountId32::new(array) } #[cfg(feature = "runtime-benchmarks")] @@ -420,3 +423,15 @@ pub fn new_test_ext_keystore() -> sp_io::TestExternalities { ext } + +/// advances the block +pub fn run_to_block(n: u32) { + while System::block_number() < n { + if System::block_number() > 1 { + System::on_finalize(System::block_number()); + } + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + StatefulStoragePallet::on_initialize(System::block_number()); + } +} diff --git a/pallets/stateful-storage/src/tests/mod.rs b/pallets/stateful-storage/src/tests/mod.rs index 333aa74e56..ab44b035a1 100644 --- a/pallets/stateful-storage/src/tests/mod.rs +++ b/pallets/stateful-storage/src/tests/mod.rs @@ -4,5 +4,6 @@ mod apply_item_actions_tests; mod child_tree_tests; mod delete_page_tests; mod itemized_operations_tests; +mod migrations_tests; mod other_tests; mod upsert_page_tests; diff --git a/pallets/stateful-storage/src/types.rs b/pallets/stateful-storage/src/types.rs index 1570202cfa..41cb420adb 100644 --- a/pallets/stateful-storage/src/types.rs +++ b/pallets/stateful-storage/src/types.rs @@ -19,6 +19,10 @@ use sp_std::{ }; use twox_hash::XxHash64; +/// Migration page size +pub const MIGRATION_PAGE_SIZE: u32 = 20; +/// Current storage version of the pallet. +pub const STATEFUL_STORAGE_VERSION: StorageVersion = StorageVersion::new(1); /// pallet storage prefix pub const PALLET_STORAGE_PREFIX: &[u8] = b"stateful-storage"; /// itemized storage prefix diff --git a/runtime/frequency/src/lib.rs b/runtime/frequency/src/lib.rs index 70be9373f7..39be3c7f2c 100644 --- a/runtime/frequency/src/lib.rs +++ b/runtime/frequency/src/lib.rs @@ -114,7 +114,8 @@ pub use common_runtime::{ weights::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight}, }; use frame_support::traits::Contains; - +#[cfg(feature = "try-runtime")] +use frame_support::traits::{TryStateSelect, UpgradeCheckSelect}; mod ethereum; mod genesis; @@ -345,6 +346,7 @@ pub type Executive = frame_executive::Executive< MigratePalletsCurrentStorage, pallet_capacity::migration::v4::MigrationToV4, pallet_capacity::migration::provider_boost_init::ProviderBoostInit, + pallet_stateful_storage::migration::v1::MigrateToV1, ), >; @@ -402,7 +404,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("frequency"), impl_name: create_runtime_str!("frequency"), authoring_version: 1, - spec_version: 132, + spec_version: 133, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -416,7 +418,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("frequency-testnet"), impl_name: create_runtime_str!("frequency"), authoring_version: 1, - spec_version: 132, + spec_version: 133, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1,